viewcvs-web r135 - in branches/VIEWCVS_DIST: . bin bin/mod_python docs lib lib/vcauth lib/vcauth/forbidden lib/vcauth/forbiddenre lib/vcauth/svnauthz lib/vclib lib/vclib/ccvs lib/vclib/ccvs/rcsparse lib/vclib/svn notes notes/logo templates templates-contrib/newvc templates-contrib/newvc/templates templates-contrib/newvc/templates/docroot templates-contrib/newvc/templates/docroot/images templates-contrib/newvc/templates/include templates-contrib/tabbed/templates templates-contrib/tabbed/templates/docroot templates-contrib/tabbed/templates/docroot/images templates-contrib/tabbed/templates/include templates-contrib/viewsvn templates-contrib/viewsvn/extras templates-contrib/viewsvn/screenshots templates-contrib/viewsvn/templates templates-contrib/viewsvn/templates/docroot templates-contrib/viewsvn/templates/docroot/images templates-contrib/viewsvn/templates/docroot/images/tortoisesvn templates-contrib/viewsvn/templates/include templates/docroot templates/docroot/images t emplates/include tparse viewvc.org viewvc.org/images viewvc.org/nightly windows www



Author: ovitters
Date: Mon Nov  3 09:44:02 2008
New Revision: 135
URL: http://svn.gnome.org/viewvc/viewcvs-web?rev=135&view=rev

Log:
Import of viewcvs on 2008-11-03

Added:
   branches/VIEWCVS_DIST/lib/vcauth/forbiddenre/
   branches/VIEWCVS_DIST/lib/vcauth/forbiddenre/__init__.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/bincvs.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/ccvs.py
   branches/VIEWCVS_DIST/lib/vclib/svn/svn_ra.py
   branches/VIEWCVS_DIST/lib/vclib/svn/svn_repos.py
   branches/VIEWCVS_DIST/notes/logo/
   branches/VIEWCVS_DIST/notes/logo/viewvc-logo.odg   (contents, props changed)
   branches/VIEWCVS_DIST/notes/logo/viewvc-logo.pdf   (contents, props changed)
   branches/VIEWCVS_DIST/notes/logo/viewvc-logo.svg
   branches/VIEWCVS_DIST/templates-contrib/newvc/
   branches/VIEWCVS_DIST/templates-contrib/newvc/README
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/diff.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/directory.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help.css
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_dirview.html
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_log.html
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_query.html
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_rootview.html
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/back.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/back_small.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/broken.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/cvs-logo.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/dir.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/down.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/feed-icon-16x16.jpg   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/forward.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/svn-logo.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/text.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/up.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/viewvc-logo.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/scripts.js
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/styles.css
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/error.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/file.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/graph.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/diff_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/fileview.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/header.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/pathrev_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/props.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/log.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/markup.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_results.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/revision.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/roots.ezt
   branches/VIEWCVS_DIST/templates-contrib/newvc/templates/rss.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/images/lock.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/fileview.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/props.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/INSTALL
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/README
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.css
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.xsl
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/diff.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/dir.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/log.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/markup.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/diff.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/directory.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/broken.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/dir.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/down.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/download.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/favicon-svn.ico   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/feed-icon-16x16.jpg   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/logo-svn.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/logo-viewvc.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/svn.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/text.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/back.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/back_small.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/blame.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/checkout.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/diff.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/forward.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/license.txt   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/log.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/patch.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/repos.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/tsvn.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/up.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/viewvc.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/styles.css
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/error.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/file.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/diff_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_header.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/file_header.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/header.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_header.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/paging.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/pathrev_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/props.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/log.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_results.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/revision.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/roots.ezt
   branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/rss.ezt
   branches/VIEWCVS_DIST/templates/docroot/images/favicon.ico   (contents, props changed)
   branches/VIEWCVS_DIST/templates/docroot/images/lock.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates/docroot/images/viewvc-logo.png   (contents, props changed)
   branches/VIEWCVS_DIST/templates/file.ezt
   branches/VIEWCVS_DIST/templates/include/props.ezt
   branches/VIEWCVS_DIST/viewvc.org/favicon.ico   (contents, props changed)
Modified:
   branches/VIEWCVS_DIST/CHANGES
   branches/VIEWCVS_DIST/INSTALL
   branches/VIEWCVS_DIST/LICENSE.html
   branches/VIEWCVS_DIST/bin/cvsdbadmin
   branches/VIEWCVS_DIST/bin/loginfo-handler
   branches/VIEWCVS_DIST/bin/make-database
   branches/VIEWCVS_DIST/bin/mod_python/query.py
   branches/VIEWCVS_DIST/bin/mod_python/viewvc.py
   branches/VIEWCVS_DIST/bin/standalone.py
   branches/VIEWCVS_DIST/bin/svndbadmin
   branches/VIEWCVS_DIST/docs/template-authoring-guide.html
   branches/VIEWCVS_DIST/docs/upgrading-howto.html
   branches/VIEWCVS_DIST/docs/url-reference.html
   branches/VIEWCVS_DIST/lib/blame.py
   branches/VIEWCVS_DIST/lib/config.py
   branches/VIEWCVS_DIST/lib/cvsdb.py
   branches/VIEWCVS_DIST/lib/debug.py
   branches/VIEWCVS_DIST/lib/popen.py
   branches/VIEWCVS_DIST/lib/query.py
   branches/VIEWCVS_DIST/lib/vcauth/__init__.py
   branches/VIEWCVS_DIST/lib/vcauth/forbidden/__init__.py
   branches/VIEWCVS_DIST/lib/vcauth/svnauthz/__init__.py
   branches/VIEWCVS_DIST/lib/vclib/__init__.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/__init__.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/blame.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/common.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/default.py
   branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/texttools.py
   branches/VIEWCVS_DIST/lib/vclib/svn/__init__.py
   branches/VIEWCVS_DIST/lib/viewvc.py
   branches/VIEWCVS_DIST/notes/releases.txt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/annotate.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/diff.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/directory.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/styles.css
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/diff_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_header.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/header.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_footer.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_header.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/pathrev_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/log.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/markup.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_form.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_results.ezt
   branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/revision.ezt
   branches/VIEWCVS_DIST/templates/diff.ezt
   branches/VIEWCVS_DIST/templates/dir_new.ezt
   branches/VIEWCVS_DIST/templates/directory.ezt
   branches/VIEWCVS_DIST/templates/docroot/help_dirview.html
   branches/VIEWCVS_DIST/templates/docroot/help_log.html
   branches/VIEWCVS_DIST/templates/docroot/help_query.html
   branches/VIEWCVS_DIST/templates/docroot/help_rootview.html
   branches/VIEWCVS_DIST/templates/docroot/styles.css
   branches/VIEWCVS_DIST/templates/include/diff_form.ezt
   branches/VIEWCVS_DIST/templates/include/dir_footer.ezt
   branches/VIEWCVS_DIST/templates/include/dir_header.ezt
   branches/VIEWCVS_DIST/templates/include/header.ezt
   branches/VIEWCVS_DIST/templates/include/log_header.ezt
   branches/VIEWCVS_DIST/templates/include/paging.ezt
   branches/VIEWCVS_DIST/templates/include/pathrev_form.ezt
   branches/VIEWCVS_DIST/templates/include/sort.ezt
   branches/VIEWCVS_DIST/templates/log.ezt
   branches/VIEWCVS_DIST/templates/log_table.ezt
   branches/VIEWCVS_DIST/templates/query_form.ezt
   branches/VIEWCVS_DIST/templates/revision.ezt
   branches/VIEWCVS_DIST/tparse/tparse.h
   branches/VIEWCVS_DIST/viewvc-install
   branches/VIEWCVS_DIST/viewvc.conf.dist
   branches/VIEWCVS_DIST/viewvc.org/contact.html
   branches/VIEWCVS_DIST/viewvc.org/contributing.html
   branches/VIEWCVS_DIST/viewvc.org/download.html
   branches/VIEWCVS_DIST/viewvc.org/faq.html
   branches/VIEWCVS_DIST/viewvc.org/images/title.jpg
   branches/VIEWCVS_DIST/viewvc.org/images/title.xcf
   branches/VIEWCVS_DIST/viewvc.org/index.html
   branches/VIEWCVS_DIST/viewvc.org/nightly/build-viewvc-snapshot
   branches/VIEWCVS_DIST/viewvc.org/styles.css
   branches/VIEWCVS_DIST/viewvc.org/who.html
   branches/VIEWCVS_DIST/windows/README
   branches/VIEWCVS_DIST/www/index.html

Modified: branches/VIEWCVS_DIST/CHANGES
==============================================================================
--- branches/VIEWCVS_DIST/CHANGES	(original)
+++ branches/VIEWCVS_DIST/CHANGES	Mon Nov  3 09:44:02 2008
@@ -17,8 +17,56 @@
   * add support for disabling the checkout view (now the default state)
   * add support for ranges of revisions to svndbadmin (issue #224)
   * make the query handling more forgiving of malformatted subdirs (issue #244)
-  * add support for per-root configuration overrides
+  * add support for per-root configuration overrides (issue #371)
   * add support for optional email address mangling (issue #290)
+  * extensible path-based authorization subsystem (issue #268), supporting:
+    - Subversion authz files (new)
+    - regexp-based path hiding (for compat with 1.0.x)
+    - file glob top-level directory hiding (for compat with 1.0.x)
+  * allow default file view to be "markup" (issue #305)
+  * add support for displaying file/directory properties (issue #39)
+  * pagination improvements
+  * add gzip output encoding support for template-driven pages
+  * fix cache control bugs (issue #259)
+  * add RSS feed URL generation for file history
+  * add support for remote creation of ViewVC checkins database
+  * add integration with Pygments for syntax highlighting
+  * preserve executability of Subversion files in tarballs (issue #233)
+  * add ability to set Subversion runtime config dir (issue #351, issue #339)
+  * show RSS/query links only for roots found in commits database (issue #357)
+  * recognize Subversion svn:mime-type property values (issue #364)
+  * hide CVS files when viewing tags/branches on which they don't exist
+  * add support for hiding errorful entries from the directory view (issue #105)
+
+Version 1.0.7 (released 14-Oct-2008)
+
+  * fix regression in the 'as text' download view (issue #373)
+
+Version 1.0.6 (released 16-Sep-2008)
+
+  * security fix: ignore arbitrary user-provided MIME types (issue #354)
+  * fix bug in regexp search filter when used with sticky tag (issue #346)
+  * fix bug in handling of certain 'co' output (issue #348)
+  * fix regexp search filter template bug
+  * fix annotate code syntax error
+  * fix mod_python import cycle (issue #369)
+
+Version 1.0.5 (released 28-Feb-2008)
+
+  * security fix: omit commits of all-forbidden files from query results
+  * security fix: disallow direct URL navigation to hidden CVSROOT folder
+  * security fix: strip forbidden paths from revision view
+  * security fix: don't traverse log history thru forbidden locations
+  * security fix: honor forbiddenness via diff view path parameters
+  * new 'forbiddenre' regexp-based path authorization feature
+  * fix root name conflict resolution inconsistencies (issue #287)
+  * fix an oversight in the CVS 1.12.9 loginfo-handler support
+  * fix RSS feed content type to be more specific (issue #306)
+  * fix entity escaping problems in RSS feed data (issue #238)
+  * fix bug in tarball generation for remote Subversion repositories
+  * fix query interface file-count-limiting logic
+  * fix query results plus/minus count to ignore forbidden files
+  * fix blame error caused by 'svn' unable to create runtime config dir
 
 Version 1.0.4 (released 10-Apr-2007)
 

Modified: branches/VIEWCVS_DIST/INSTALL
==============================================================================
--- branches/VIEWCVS_DIST/INSTALL	(original)
+++ branches/VIEWCVS_DIST/INSTALL	Mon Nov  3 09:44:02 2008
@@ -43,13 +43,8 @@
       * MySQL 3.22 and MySQLdb 0.9.0 or later to create a commit database
           (http://www.mysql.com/)
           (http://sourceforge.net/projects/mysql-python)
-      * one of the following syntax highlighting programs:
-          - GNU enscript
-              (http://www.codento.com/people/mtr/genscript/)
-          - Highlight 2.2.10 or later (we recommend 2.4.5 or later)
-              (http://www.andre-simon.de/)
-          - GNU source-highlight 2.5 or later
-              (http://www.gnu.org/software/src-highlite/)
+      * Pygments 0.9 or later, syntax highlighting engine
+          (http://pygments.org)
       * CvsGraph 1.5.0 or later, graphical CVS revision tree generator
           (http://www.akhphd.au.dk/~bertho/cvsgraph/)
 
@@ -225,8 +220,8 @@
    you copied the files to.
    
    Note: If you are using Mod_Python under Apache 1.3 the tarball generation
-   and enscript colorizing features may not work because they use
-   multithreading. They do work fine with Apache 2.
+   feature may not work because it uses multithreading.  This works fine
+   under Apache 2.
    
    continue with step 3).
 
@@ -256,6 +251,16 @@
       http://<server_name>/viewvc/~checkout~/<module_name>
       http://<server_name>/viewvc/<module_name>.tar.gz?view=tar
 
+5) Optional: Protect your ViewVC instance from server-whacking webcrawlers.
+
+   As ViewVC is a web-based application which each page containing various
+   links to other pages and views, you can expect your server's performance
+   to suffer if a webcrawler finds your ViewVC instance and begins
+   traversing those links.  We highly recommend that you add your ViewVC
+   location to a site-wide robots.txt file.  Visit the Wikipedia page
+   for Robots.txt (http://en.wikipedia.org/wiki/Robots.txt) for more
+   information.
+
 
 UPGRADING VIEWVC
 -----------------
@@ -386,21 +391,11 @@
 ENABLING SYNTAX COLORATION
 --------------------------
 
-Enscript and Highlight are two programs that can colorize source code
-for a lot of languages.  ViewVC can be configured to use either one.
-
-1) Install Enscript, Highlight, or GNU Source Highlight using your
-   system's package manager, or by downloading from the project home pages.
-
-2) Set either the 'use_enscript' or 'use_highlight' or 'use_source_highlight'
-   option in viewvc.conf to 1.
-
-3) You may also need to set 'enscript', 'highlight', or 'source_highlight'
-   option in the [utilities] section if the executables are not located 
-   on the system PATH.
-
-That's it!  Now when you view the contents of recognized filetypes in
-ViewVC, you should see colorized syntax.
+ViewVC uses Pygments (http://pygments.org) for syntax coloration.  You
+need only install a suitable version of that module, and if ViewVC
+finds it in your Python module path, it will use it (unless you
+specifically disable the feature by setting use_pygments = 0 in your
+viewvc.conf file).
 
 
 CVSGRAPH CONFIGURATION
@@ -438,9 +433,12 @@
 Unlike the CVS integration, which simply wraps the RCS and CVS utility
 programs, the Subversion integration requires additional Python
 libraries.  To use ViewVC with Subversion, make sure you have both
-Subversion itself and the Subversion Python bindings installed.  See
-Subversion's installation notes for more details on how to build and
-install these items.
+Subversion itself and the Subversion Python bindings installed.  These
+can be obtained through typical package distribution mechanisms, or
+may be build from source.  (See the files 'INSTALL' and
+'subversion/bindings/swig/INSTALL' in the Subversion source tree for
+more details on how to build and install Subversion and its Python
+bindings.)
 
 Generally speaking, you'll know when your installation of Subversion's
 bindings has been successful if you can import the 'svn.core' module

Modified: branches/VIEWCVS_DIST/LICENSE.html
==============================================================================
--- branches/VIEWCVS_DIST/LICENSE.html	(original)
+++ branches/VIEWCVS_DIST/LICENSE.html	Mon Nov  3 09:44:02 2008
@@ -15,7 +15,7 @@
 
 <blockquote>
 
-<p><strong>Copyright &copy; 1999-2007 The ViewCVS Group.  All rights
+<p><strong>Copyright &copy; 1999-2008 The ViewCVS Group.  All rights
    reserved.</strong></p>
 
 <p>By using ViewVC, you agree to the terms and conditions set forth
@@ -58,6 +58,7 @@
   <li>September 5, 2002 &mdash; copyright years updated</li>
   <li>March 17, 2006 &mdash; software renamed from "ViewCVS"</li>
   <li>April 10, 2007 &mdash; copyright years updated</li>
+  <li>February 22, 2008 &mdash; copyright years updated</li>
 </ul>
 
 </body>

Modified: branches/VIEWCVS_DIST/bin/cvsdbadmin
==============================================================================
--- branches/VIEWCVS_DIST/bin/cvsdbadmin	(original)
+++ branches/VIEWCVS_DIST/bin/cvsdbadmin	Mon Nov  3 09:44:02 2008
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -43,7 +43,7 @@
 import string
 import cvsdb
 import viewvc
-import vclib.bincvs
+import vclib.ccvs
 
 
 def UpdateFile(db, repository, path, update, quiet_level):
@@ -129,7 +129,8 @@
        3. %s [[-q] -q] purge REPOS-PATH
 
 1.  Rebuild the commit database information for the repository located
-    at REPOS-PATH.
+    at REPOS-PATH, after first purging information specific to that
+    repository (if any).
 
 2.  Update the commit database information for all unrecorded commits
     in the repository located at REPOS-PATH.
@@ -168,6 +169,7 @@
 
     # get repository and path, and do the work
     root, path_parts = RootPath(args[2], quiet_level)
+    rootpath = vclib.ccvs.canonicalize_rootpath(root)
     try:
         cfg = viewvc.load_config(CONF_PATHNAME)
         db = cvsdb.ConnectDatabase(cfg)
@@ -178,8 +180,8 @@
             db.PurgeRepository(root)
 
         if command in ('rebuild', 'update'):
-            repository = vclib.bincvs.BinCVSRepository(None, root,
-                                                       cfg.utilities)
+            repository = vclib.ccvs.CVSRepository(None, rootpath, None,
+                                                  cfg.utilities, 0)
             RecurseUpdate(db, repository, path_parts,
                           command == 'update', quiet_level)
     except KeyboardInterrupt:

Modified: branches/VIEWCVS_DIST/bin/loginfo-handler
==============================================================================
--- branches/VIEWCVS_DIST/bin/loginfo-handler	(original)
+++ branches/VIEWCVS_DIST/bin/loginfo-handler	Mon Nov  3 09:44:02 2008
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*-python-*-
 #
-# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -44,7 +44,7 @@
 import re
 import cvsdb
 import viewvc
-import vclib.bincvs
+import vclib.ccvs
 
 DEBUG_FLAG = 0
 
@@ -223,7 +223,8 @@
 def ProcessLoginfo(rootpath, directory, files):
     cfg = viewvc.load_config(CONF_PATHNAME)
     db = cvsdb.ConnectDatabase(cfg)
-    repository = vclib.bincvs.BinCVSRepository(None, rootpath, cfg.utilities)
+    repository = vclib.ccvs.CVSRepository(None, rootpath, None,
+                                          cfg.utilities, 0)
 
     # split up the directory components
     dirpath = filter(None, string.split(os.path.normpath(directory), os.sep))

Modified: branches/VIEWCVS_DIST/bin/make-database
==============================================================================
--- branches/VIEWCVS_DIST/bin/make-database	(original)
+++ branches/VIEWCVS_DIST/bin/make-database	Mon Nov  3 09:44:02 2008
@@ -20,11 +20,12 @@
 import popen2
 
 INTRO_TEXT = """\
-This script creates the database and tables in MySQL used by the ViewVC
-checkin database.  You will be prompted for: database user, database user
-password, and database name.  This script will use mysql to create the
-database for you.  You will then need to set the appropriate parameters
-in your viewvc.conf file under the [cvsdb] section.
+This script creates the database and tables in MySQL used by the
+ViewVC checkin database.  You will be prompted for:  database server
+hostname, database user, database user password, and database name.
+This script will use the 'mysql' program to create the database for
+you.  You will then need to set the appropriate parameters in the
+[cvsdb] section of your viewvc.conf file.
 """
 
 DATABASE_SCRIPT="""\
@@ -121,24 +122,27 @@
 """
 
 if __name__ == "__main__":
+  try:
     print INTRO_TEXT
-    
+
+    # Prompt for necessary information
+    host = raw_input("MySQL Hostname [default: localhost]: ") or ""
     user = raw_input("MySQL User: ")
     passwd = raw_input("MySQL Password: ")
-    dbase = raw_input("ViewVC Database Name [default: ViewVC]: ")
-    if not dbase:
-        dbase = "ViewVC"
+    dbase = raw_input("ViewVC Database Name [default: ViewVC]: ") or "ViewVC"
 
+    # Create the database
     dscript = string.replace(DATABASE_SCRIPT, "<dbname>", dbase)
-
+    host_option = host and "--host=%s" % (host) or ""
     if sys.platform == "win32":
-      # popen2.Popen3 is not provided on windows
-      cmd = "mysql --user=%s --password=%s" % (user, passwd)
-      mysql = os.popen(cmd, "w")
+      cmd = "mysql --user=%s --password=%s %s "\
+            % (user, passwd, host_option)
+      mysql = os.popen(cmd, "w") # popen2.Popen3 is not provided on windows
       mysql.write(dscript)
       status = mysql.close()
     else:
-      cmd = "{ mysql --user=%s --password=%s ; } 2>&1" % (user, passwd)
+      cmd = "{ mysql --user=%s --password=%s %s ; } 2>&1" \
+            % (user, passwd, host_option)
       pipes = popen2.Popen3(cmd)
       pipes.tochild.write(dscript)
       pipes.tochild.close()
@@ -146,9 +150,11 @@
       status = pipes.wait()
 
     if status:
-        print "[ERROR] the database did not create sucessfully."
-        sys.exit(1)
+      print "[ERROR] the database did not create sucessfully."
+      sys.exit(1)
 
     print "Database created successfully."
-    sys.exit(0)
+  except KeyboardInterrupt:
+    pass
+  sys.exit(0)
     

Modified: branches/VIEWCVS_DIST/bin/mod_python/query.py
==============================================================================
--- branches/VIEWCVS_DIST/bin/mod_python/query.py	(original)
+++ branches/VIEWCVS_DIST/bin/mod_python/query.py	Mon Nov  3 09:44:02 2008
@@ -42,9 +42,23 @@
   sys.path.insert(0, LIBRARY_DIR)
 
 import sapi
-import viewvc
-import query
-reload(query) # need reload because initial import loads this stub file
+import imp
+
+# Import real ViewVC module
+fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
+try:
+  viewvc = imp.load_module('viewvc', fp, pathname, description)
+finally:
+  if fp:
+    fp.close()
+
+# Import real ViewVC Query modules
+fp, pathname, description = imp.find_module('query', [LIBRARY_DIR])
+try:
+  query = imp.load_module('query', fp, pathname, description)
+finally:
+  if fp:
+    fp.close()
 
 cfg = viewvc.load_config(CONF_PATHNAME)
 

Modified: branches/VIEWCVS_DIST/bin/mod_python/viewvc.py
==============================================================================
--- branches/VIEWCVS_DIST/bin/mod_python/viewvc.py	(original)
+++ branches/VIEWCVS_DIST/bin/mod_python/viewvc.py	Mon Nov  3 09:44:02 2008
@@ -42,9 +42,15 @@
   sys.path.insert(0, LIBRARY_DIR)
 
 import sapi
-import viewvc
-reload(viewvc) # need reload because initial import loads this stub file
+import imp
 
+# Import real ViewVC module
+fp, pathname, description = imp.find_module('viewvc', [LIBRARY_DIR])
+try:
+  viewvc = imp.load_module('viewvc', fp, pathname, description)
+finally:
+  if fp:
+    fp.close()
 
 def index(req):
   server = sapi.ModPythonServer(req)

Modified: branches/VIEWCVS_DIST/bin/standalone.py
==============================================================================
--- branches/VIEWCVS_DIST/bin/standalone.py	(original)
+++ branches/VIEWCVS_DIST/bin/standalone.py	Mon Nov  3 09:44:02 2008
@@ -17,7 +17,7 @@
 
 __author__ = "Peter Funk <pf artcom-gmbh de>"
 __date__ = "11 November 2001"
-__version__ = "$Revision: 1590 $"
+__version__ = "$Revision: 1962 $"
 __credits__ = """Guido van Rossum, for an excellent programming language.
 Greg Stein, for writing ViewCVS in the first place.
 Ka-Ping Yee, for the GUI code and the framework stolen from pydoc.py.
@@ -63,6 +63,7 @@
     else:
         host = 'localhost'
     script_alias = 'viewvc'
+    config_file = None
 
 # --- web browser interface: ----------------------------------------------
 
@@ -284,7 +285,7 @@
         # XXX Move this code out of this function.
         # Early loading of configuration here.  Used to
         # allow tinkering with some configuration settings:
-        handle_config()
+        handle_config(options.config_file)
         if options.repositories:
             cfg.general.default_root = "Development"
             for repo_name in options.repositories.keys():
@@ -331,9 +332,9 @@
         pass
     print 'server stopped'
 
-def handle_config():
+def handle_config(config_file):
   global cfg
-  cfg = viewvc.load_config(CONF_PATHNAME)
+  cfg = viewvc.load_config(config_file or CONF_PATHNAME)
 
 # --- graphical interface: --------------------------------------------------
 
@@ -576,8 +577,9 @@
     class BadUsage(Exception): pass
 
     try:
-        opts, args = getopt.getopt(argv[1:], 'gdp:r:h:s:', 
-            ['gui', 'daemon', 'port=', 'repository=', 'script-alias='])
+        opts, args = getopt.getopt(argv[1:], 'gdc:p:r:h:s:', 
+            ['gui', 'daemon', 'config-file=', 'host=',
+             'port=', 'repository=', 'script-alias='])
         for opt, val in opts:
             if opt in ('-g', '--gui'):
                 options.start_gui = 1
@@ -601,6 +603,10 @@
             elif opt in ('-s', '--script-alias'):
                 options.script_alias = \
                     string.join(filter(None, string.split(val, '/')), '/')
+            elif opt in ('-c', '--config-file'):
+                options.config_file = val
+        if options.start_gui and options.config_file:
+            raise BadUsage, "--config-file option is not valid in GUI mode."
         if not options.start_gui and not options.port:
             raise BadUsage, "You must supply a valid port, or run in GUI mode."
         if options.daemon:
@@ -608,7 +614,7 @@
             if pid != 0:
                 sys.exit()  
         if options.start_gui:
-            gui(options.host, options.port)
+            gui(options.host, options.port, options.config_file)
             return
         elif options.port:
             def ready(server):
@@ -626,10 +632,16 @@
         sys.stderr.write("""Usage: %(cmd)s [OPTIONS]
 
 Run a simple, standalone HTTP server configured to serve up ViewVC
-requests.  ViewVC configuration is read from viewvc.conf file, if available.
+requests.
 
 Options:
 
+  --config-file=PATH (-c)    Use the file at PATH as the ViewVC configuration
+                             file.  If not specified, ViewVC will try to use
+                             the configuration file in its installation tree;
+                             otherwise, built-in default values are used.
+                             (Not valid in GUI mode.)
+                             
   --daemon (-d)              Background the server process.
   
   --host=HOST (-h)           Start the server listening on HOST.  You need

Modified: branches/VIEWCVS_DIST/bin/svndbadmin
==============================================================================
--- branches/VIEWCVS_DIST/bin/svndbadmin	(original)
+++ branches/VIEWCVS_DIST/bin/svndbadmin	Mon Nov  3 09:44:02 2008
@@ -66,6 +66,7 @@
 
 import cvsdb
 import viewvc
+import vclib
 
 class SvnRepo:
     """Class used to manage a connection to a SVN repository."""
@@ -278,7 +279,8 @@
        3. %s [-v] purge REPOS-PATH
 
 1.  Rebuild the commit database information for the repository located
-    at REPOS-PATH across all revisions.
+    at REPOS-PATH across all revisions, after first purging
+    information specific to that repository (if any).
 
 2.  Update the commit database information for the repository located
     at REPOS-PATH across all revisions or, optionally, only for the
@@ -324,8 +326,9 @@
 
     repository = args[2]
     if not os.path.exists(repository):
-        sys.stderr.write('ERROR: could not find repository %s\n' % repository)
+        sys.stderr.write('ERROR: could not find repository %s\n' % args[2])
         usage()
+    repository = vclib.svn.canonicalize_rootpath(repository)
 
     revs = []
     if len(sys.argv) > 3:

Modified: branches/VIEWCVS_DIST/docs/template-authoring-guide.html
==============================================================================
--- branches/VIEWCVS_DIST/docs/template-authoring-guide.html	(original)
+++ branches/VIEWCVS_DIST/docs/template-authoring-guide.html	Mon Nov  3 09:44:02 2008
@@ -59,13 +59,13 @@
     <li><a href="#variables-common">Common Template Variable Set (COMMON)</a></li>
     <li><a href="#variables-pathrev">Path Revision Form Variable Set (PATHREV)</a></li>
     <li><a href="#variables-paging">Paging Form Variable Set (PAGING)</a></li>
-    <li><a href="#variables-annotate">Annotation View (annotate.ezt)</a></li>
+    <li><a href="#variables-properties">Property Listing Variable Set (PROPERTIES)</a></li>
+    <li><a href="#variables-file">File Contents View (file.ezt)</a></li>
     <li><a href="#variables-graph">Revision Graph View (graph.ezt)</a></li>
     <li><a href="#variables-diff">File Difference View (diff.ezt)</a></li>
     <li><a href="#variables-directory">Directory Listing View (directory.ezt)</a></li>
     <li><a href="#variables-error">Error View (error.ezt)</a></li>
     <li><a href="#variables-log">Revision Log View (log.ezt)</a></li>
-    <li><a href="#variables-markup">File Contents View (markup.ezt)</a></li>
     <li><a href="#variables-query_results">Revision History Query Results View (query_results.ezt, rss.ezt)</a></li>
     <li><a href="#variables-query_form">Revision History Query Form View (query_form.ezt)</a></li>
     <li><a href="#variables-revision">Revision/ChangeSet View (revision.ezt)</a></li>
@@ -113,16 +113,6 @@
       of the configuration file.</td>
 </tr>
 <tr class="varlevel1">
-  <td class="varname">change_root_action</td>
-  <td>String</td>
-  <td>Form action URL for the root selection form.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">change_root_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the root selection form.</td>
-</tr>
-<tr class="varlevel1">
   <td class="varname">docroot</td>
   <td>String</td>
   <td>URL of the static documents directory, generally used for
@@ -160,6 +150,11 @@
       abstract name is <var>l10n</var>.</td>
 </tr>
 <tr class="varlevel1">
+  <td class="varname">lockinfo</td>
+  <td>String</td>
+  <td>Information about the lock status of the current resource.</td>
+</tr>
+<tr class="varlevel1">
   <td class="varname">log_href</td>
   <td>String</td>
   <td>URL of the ViewVC revision log view for the current
@@ -223,33 +218,10 @@
   <td>Name of the current repository (root).</td>
 </tr>
 <tr class="varlevel1">
-  <td class="varname">roots</td>
-  <td>List</td>
-  <td>Set of configured viewable repositories.</td>
-</tr>
-<tr class="varlevel2">
-  <td class="varname">roots.name</td>
-  <td>String</td>
-  <td>Name of a configured repository.</td>
-</tr>
-<tr class="varlevel2">
-  <td class="varname">roots.path</td>
+  <td class="varname">roots_href</td>
   <td>String</td>
-  <td>Server-local location of a configured repository.  WARNING:  Revealing
-      information to untrusted guests about the details of your server
-      configuration can have negative security implications.  Use this
-      token at your own risk.</td>
-</tr>
-<tr class="varlevel2">
-  <td class="varname">roots.type</td>
-  <td>String</td>
-  <td>Version control type of a configured repository.  Valid
-      values: <tt>cvs</tt>, <tt>svn</tt>.</td>
-</tr>
-<tr class="varlevel2">
-  <td class="varname">roots.href</td>
-  <td>String</td>
-  <td>URL of root directory view for a configured repository.</td>
+  <td>URL of ViewVC root listing view.  Valid only when ViewVC is
+      configured in roots-as-url-components mode.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">rootpath</td>
@@ -281,6 +253,11 @@
   <td>Link to the current object's parent directory view.</td>
 </tr>
 <tr class="varlevel1">
+  <td class="varname">username</td>
+  <td>String</td>
+  <td>Authenticated username of the requesting user.</td>
+</tr>
+<tr class="varlevel1">
   <td class="varname">view</td>
   <td>String</td>
   <td>Name of the current view.  Valid values: <tt>annotate</tt>
@@ -343,8 +320,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">pathrev_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the revision/tag selection form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the revision/tag selection form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">pathrev_clear_action</td>
@@ -353,8 +330,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">pathrev_clear_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the path revision clear button.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the path revision clear button.</td>
 </tr>
 </tbody>
 </table>
@@ -377,9 +354,9 @@
   <td>List of pages that make up the current directory or log view.</td>
 </tr>
 <tr class="varlevel2">
-  <td class="varname">picklist.start</td>
+  <td class="varname">picklist.count</td>
   <td>String</td>
-  <td>Name of first item on the page</td>
+  <td>Number of the first item on the page (indexed from 0)</td>
 </tr>
 <tr class="varlevel2">
   <td class="varname">picklist.end</td>
@@ -387,14 +364,21 @@
   <td>Name of last item on the page</td>
 </tr>
 <tr class="varlevel2">
+  <td class="varname">picklist.more</td>
+  <td>Boolean</td>
+  <td>If set, indicates that this picklist item is a placeholder for
+      an unspecified number of additional pages.  In this case,
+      <code>picklist.end</code> is undefined.</td>
+</tr>
+<tr class="varlevel2">
   <td class="varname">picklist.page</td>
   <td>String</td>
   <td>Page number (indexed from 1)</td>
 </tr>
 <tr class="varlevel2">
-  <td class="varname">picklist.count</td>
+  <td class="varname">picklist.start</td>
   <td>String</td>
-  <td>Number of the first item on the page (indexed from 0)</td>
+  <td>Name of first item on the page</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">picklist_len</td>
@@ -406,7 +390,44 @@
 </div>
 
 <div class="h3">
-<h3 id="variables-annotate">Annotation View (annotate.ezt)</h3>
+<h3 id="variables-properties">Property Listing Variable Set (PROPERTIES)</h3>
+<table>
+<thead>
+<tr>
+  <th>Variable</th>
+  <th>Type</th>
+  <th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="varlevel1">
+  <td class="varname">properties</td>
+  <td>List</td>
+  <td>List of item properties set on the current directory, minus
+      those with undisplayable names.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">properties.name</td>
+  <td>String</td>
+  <td>Name of an item property.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">properties.undisplayable</td>
+  <td>Boolean</td>
+  <td>Indicates whether or not the value of this property is
+      undisplayable (by virtue of not being UTF-8 text).</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">properties.value</td>
+  <td>String</td>
+  <td>Value of this property.</td>
+</tr>
+</tbody>
+</table>
+</div>
+
+<div class="h3">
+<h3 id="variables-file">File Contents View (file.ezt)</h3>
 <table>
 <thead>
 <tr>
@@ -418,7 +439,8 @@
 <tbody>
 <tr class="include">
   <td colspan="3">Includes all variables from the 
-     <a href="#variables-common">COMMON</a> variable set</td>
+     <a href="#variables-common">COMMON</a> and
+     <a href="#variables-properties">PROPERTIES</a> variable sets</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">ago</td>
@@ -426,6 +448,14 @@
   <td>Text description of the time elapsed since <var>date</var>.</td>
 </tr>
 <tr class="varlevel1">
+  <td class="varname">annotation</td>
+  <td>String</td>
+  <td>If set, indicates that annotations were requested.  Valid values
+      are "annotated" (annotation was successful), "binary" (file contents
+      are not line-based and human-readable), and "error" (something went
+      wrong during annotation).</td>
+</tr>
+<tr class="varlevel1">
   <td class="varname">author</td>
   <td>String</td>
   <td>Author of the revision being viewed.</td>
@@ -454,6 +484,13 @@
       being viewed.</td>
 </tr>
 <tr class="varlevel1">
+  <td class="varname">image_src_href</td>
+  <td>String</td>
+  <td>URL used to display the current revision of the file as an
+      embedded image.  (Set only if the file is not a web-viewable
+      image.)</td>
+</tr>
+<tr class="varlevel1">
   <td class="varname">lines</td>
   <td>List</td>
   <td>Set of objects containing information about the most recent
@@ -473,7 +510,7 @@
       the line.</td>
 </tr>
 <tr class="varlevel2">
-  <td class="varname">lines.diff_url</td>
+  <td class="varname">lines.diff_href</td>
   <td>String</td>
   <td>URL of the ViewVC file difference view which displays the
       modification of the line.</td>
@@ -687,8 +724,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">diff_format_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the diff format selection form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the diff format selection form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">left</td>
@@ -836,8 +873,9 @@
 <tr class="include">
   <td colspan="3">Includes all variables from the 
      <a href="#variables-common">COMMON</a>,
-     <a href="#variables-pathrev">PATHREV</a>, and 
-     <a href="#variables-paging">PAGING</a> variable sets</td>
+     <a href="#variables-pathrev">PATHREV</a>,
+     <a href="#variables-paging">PAGING</a>, and
+     <a href="#variables-properties">PROPERTIES</a> variable sets</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">attic_showing</td>
@@ -866,8 +904,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">dir_paging_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the page selection form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the page selection form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">entries</td>
@@ -923,6 +961,11 @@
       entry.</td>
 </tr>
 <tr class="varlevel2">
+  <td class="varname">entries.lockinfo</td>
+  <td>String</td>
+  <td>Information about the lock status of the directory entry.</td>
+</tr>
+<tr class="varlevel2">
   <td class="varname">entries.log</td>
   <td>String</td>
   <td>Log message of last modification to the directory entry.</td>
@@ -1059,8 +1102,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">search_re_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the regular expression search form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the regular expression search form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">show_attic_href</td>
@@ -1181,11 +1224,6 @@
      <a href="#variables-paging">PAGING</a> variable sets</td>
 </tr>
 <tr class="varlevel1">
-  <td class="varname">annotate_href</td>
-  <td>String</td>
-  <td>URL for annotate view of the HEAD revision of the file.</td>
-</tr>
-<tr class="varlevel1">
   <td class="varname">branch_tags</td>
   <td>List</td>
   <td>Names of branch tags in the file. CVS only.</td>
@@ -1210,19 +1248,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">diff_select_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the diff selection form.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">download_href</td>
-  <td>String</td>
-  <td>URL to download the HEAD revision of the file.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">download_text_href</td>
-  <td>String</td>
-  <td>URL to download the HEAD revision of the file as
-      <tt>text/plain</tt>.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the diff selection form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">entries</td>
@@ -1357,6 +1384,11 @@
   <td>URL to download the file revision as <tt>text/plain</tt>.</td>
 </tr>
 <tr class="varlevel2">
+  <td class="varname">entries.lockinfo</td>
+  <td>String</td>
+  <td>Information about the lock status of this revision.</td>
+</tr>
+<tr class="varlevel2">
   <td class="varname">entries.log</td>
   <td>String</td>
   <td>Revision log message.</td>
@@ -1451,6 +1483,33 @@
       for a directory revision.</td>
 </tr>
 <tr class="varlevel1">
+  <td class="varname">head_annotate_href</td>
+  <td>String</td>
+  <td>URL for annotate view of the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
+  <td class="varname">head_download_href</td>
+  <td>String</td>
+  <td>URL to download the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
+  <td class="varname">head_download_text_href</td>
+  <td>String</td>
+  <td>URL to download the HEAD revision of the file as
+      <tt>text/plain</tt>.</td>
+</tr>
+<tr class="varlevel1">
+  <td class="varname">head_prefer_markup</td>
+  <td>Boolean</td>
+  <td>Indicates whether to make the default HEAD file link a link to the markup
+      page instead of the checkout page.</td>
+</tr>
+<tr class="varlevel1">
+  <td class="varname">head_view_href</td>
+  <td>String</td>
+  <td>URL for markup view of the HEAD revision of the file.</td>
+</tr>
+<tr class="varlevel1">
   <td class="varname">human_readable</td>
   <td>Boolean</td>
   <td>Indicates whether or not currently selected diff format
@@ -1470,8 +1529,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">log_paging_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the page selection form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the page selection form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">logsort</td>
@@ -1486,8 +1545,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">logsort_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for the log sort drop down box</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for the log sort drop down box</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">mime_type</td>
@@ -1500,12 +1559,6 @@
   <td>Names of non-branch in the file. CVS only.</td>
 </tr>
 <tr class="varlevel1">
-  <td class="varname">prefer_markup</td>
-  <td>Boolean</td>
-  <td>Indicates whether to make the default file link a link to the markup
-      page instead of the checkout page.</td>
-</tr>
-<tr class="varlevel1">
   <td class="varname">rev_selected</td>
   <td>String</td>
   <td>Revision number currently selected for diffs.</td>
@@ -1531,8 +1584,8 @@
 <tr class="varlevel1">
   <td class="varname">tag_prefer_markup</td>
   <td>Boolean</td>
-  <td>Indicates whether to make the default file link a link to the markup
-      page instead of the checkout page.</td>
+  <td>Indicates whether to make the default sticky tag file link a
+      link to the markup page instead of the checkout page.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">tag_view_href</td>
@@ -1556,117 +1609,6 @@
   <td>String</td>
   <td>Tag name</td>
 </tr>
-<tr class="varlevel1">
-  <td class="varname">view_href</td>
-  <td>String</td>
-  <td>URL for markup view of the HEAD revision of the file.</td>
-</tr>
-</tbody>
-</table>
-</div>
-
-<div class="h3">
-<h3 id="variables-markup">File Contents View (markup.ezt)</h3>
-<table>
-<thead>
-<tr>
-  <th>Variable</th>
-  <th>Type</th>
-  <th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr class="include">
-  <td colspan="3">Includes all variables from the 
-     <a href="#variables-common">COMMON</a> variable set</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">ago</td>
-  <td>String</td>
-  <td>Text description of the time elapsed since <var>date</var>.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">author</td>
-  <td>String</td>
-  <td>Author of the revision being viewed.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">branch_points</td>
-  <td>String</td>
-  <td>List of branch tag names which branch off of the revision being
-      viewed (CVS only).</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">branches</td>
-  <td>List</td>
-  <td>If revision currently being viewed is on a branch, list of names
-      for the branch.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">changed</td>
-  <td>String</td>
-  <td>Numbers of lines added and removed since the previous revision.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">date</td>
-  <td>String</td>
-  <td>Date (in UTC if not otherwise configured) of the revision currently
-      being viewed.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">log</td>
-  <td>String</td>
-  <td>Log message of the revision currently being viewed.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">markup</td>
-  <td>File</td>
-  <td>Marked up contents of the current file revision.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">mime_type</td>
-  <td>String</td>
-  <td>MIME type of the current file.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">orig_path</td>
-  <td>String</td>
-  <td>When viewing an old file revision through a copy of the file,
-      this is the old file revision's original path.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">orig_href</td>
-  <td>String</td>
-  <td>URL of a ViewVC log view for <code>orig_path</code>.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">prev</td>
-  <td>String</td>
-  <td>Previous revision number.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">size</td>
-  <td>String</td>
-  <td>Size of the file revision, in bytes. Subversion only.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">state</td>
-  <td>String</td>
-  <td>State of the file revision. Possible values: <tt>dead</tt>, and
-      the empty string.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">tags</td>
-  <td>List</td>
-  <td>Names of tags that have been applied to the current file
-      revision.</td>
-</tr>
-<tr class="varlevel1">
-  <td class="varname">vendor_branch</td>
-  <td>Boolean</td>
-  <td>Indicates whether or not the current file revision is on a vendor
-      branch.</td>
-</tr>
 </tbody>
 </table>
 </div>
@@ -1784,9 +1726,19 @@
   <td>True if files list was cut short due to <tt>limit_changes</tt>.</td>
 </tr>
 <tr class="varlevel2">
+  <td class="varname">commits.minus</td>
+  <td>String</td>
+  <td>Total number of lines removed from files in this commit.</td>
+</tr>
+<tr class="varlevel2">
   <td class="varname">commits.num_files</td>
   <td>String</td>
-  <td>Number of files in the <var>commits.files</var> list.</td>
+  <td>Total number of files in the <var>commits.files</var> list.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">commits.plus</td>
+  <td>String</td>
+  <td>Number of lines added to files in this commit.</td>
 </tr>
 <tr class="varlevel2">
   <td class="varname">commits.rev</td>
@@ -1827,12 +1779,14 @@
 <tr class="varlevel1">
   <td class="varname">minus_count</td>
   <td>String</td>
-  <td>Total number of lines removed in the commit (over all files).</td>
+  <td>Total number of lines removed from all files across all returned
+      commits.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">plus_count</td>
   <td>String</td>
-  <td>Total number of lines added in the commit (over all files).</td>
+  <td>Total number of lines added to all files across all returned
+      commits.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">querysort</td>
@@ -1955,8 +1909,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">query_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for query form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for query form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">querysort</td>
@@ -2095,8 +2049,8 @@
 </tr>
 <tr class="varlevel1">
   <td class="varname">jump_rev_hidden_values</td>
-  <td>String</td>
-  <td>Hidden value HTML markup for revision jump form.</td>
+  <td>List</td>
+  <td>Hidden value name/value pairs for revision jump form.</td>
 </tr>
 <tr class="varlevel1">
   <td class="varname">limit_changes</td>
@@ -2153,6 +2107,35 @@
   <td colspan="3">Includes all variables from the 
      <a href="#variables-common">COMMON</a> variable set</td>
 </tr>
+<tr class="varlevel1">
+  <td class="varname">roots</td>
+  <td>List</td>
+  <td>Set of configured viewable repositories.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">roots.name</td>
+  <td>String</td>
+  <td>Name of a configured repository.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">roots.path</td>
+  <td>String</td>
+  <td>Server-local location of a configured repository.  WARNING:  Revealing
+      information to untrusted guests about the details of your server
+      configuration can have negative security implications.  Use this
+      token at your own risk.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">roots.type</td>
+  <td>String</td>
+  <td>Version control type of a configured repository.  Valid
+      values: <tt>cvs</tt>, <tt>svn</tt>.</td>
+</tr>
+<tr class="varlevel2">
+  <td class="varname">roots.href</td>
+  <td>String</td>
+  <td>URL of root directory view for a configured repository.</td>
+</tr>
 </tbody>
 </table>
 

Modified: branches/VIEWCVS_DIST/docs/upgrading-howto.html
==============================================================================
--- branches/VIEWCVS_DIST/docs/upgrading-howto.html	(original)
+++ branches/VIEWCVS_DIST/docs/upgrading-howto.html	Mon Nov  3 09:44:02 2008
@@ -109,14 +109,117 @@
 </div>
 
 <div class="h3">
-<h3>Mod_Python Stubs</h3>
+<h3>Path-Based Authorization / Forbidden Modules</h3>
     
-<p>The Mod_Python stub scripts haved been renamed from
-   <code>viewvc.py</code> and <code>query.py</code> to
-   <code>viewvc_mp.py</code> and <code>query_mp.py</code>,
-   respectively, to avoid triggering an Exception from Mod_Python's
-   module import loop detection logic.  You'll need to update your
-   Apache configuration files to point to the new script names.</p>
+<p>ViewVC 1.1 introduces a new pluggable authorization (authz)
+   subsystem which gives administrators greater control over the
+   accessibility of the information ViewVC displays in its output.
+   ViewVC provides a number of working authz modules and a framework for
+   configuring them.  But of specific interest to folks upgrading from
+   ViewVC 1.0 is that one of these new modules has replaced the
+   handling of forbidden modules.  As such, the <code>forbidden</code>
+   configuration option now lives under the configuration section
+   specific to that authz module.</p>
+
+<p>Migrating your existing configuration of forbidden modules should
+   be fairly straightforward:</p>
+
+<ol>
+
+   <li>In the new "authz-forbidden" section of viewvc.conf, set the
+       <code>forbidden</code> option to the same value as the
+       <code>forbidden</code> option in your ViewVC 1.0.x
+       configuration's "general" section.</li>
+
+   <li>In the new "authz-forbiddenre" section of viewvc.conf, set the
+       <code>forbiddenre</code> option to the same value as the
+       <code>forbiddenre</code> option in your ViewVC 1.0.x
+       configuration's "general" section.</li>
+
+   <li>Finally, ensure that that the new <code>authorizer</code>
+       option is set to either "forbidden" (which is the default) or
+       "forbiddenre", depending on which of those you were using in
+       ViewVC 1.0.x.</li>
+
+</ol>
+
+<p>Of course, you might wish to take advantage of another of the
+   provided authz modules.  Or, you might wish to write a brand new
+   one for your purposes.  The flexibility is yours.</p>
+
+<p><strong>Known Issues:</strong></p>
+
+<ul>
+
+   <li>ViewVC does not provide an <em>authentication</em> framework.
+       It does, however, inherit authenticated usernames as determined
+       by the HTTP server (Apache, e.g.) via the CGI environment.  So,
+       any authorization module that assigns privileges based on
+       usernames will work only if ViewVC is deployed in a way that
+       requires successful authentication (as opposed to allowing
+       anonymous access).</li>
+
+   <li>Currently, the root listing view only honors the global or
+       vhost-specific configurations, <em>not</em> any root-specific
+       configuration.  In the event that ViewVC is using root-specific
+       configuration for its authorization stuffs, this may cause
+       either the unintended leak of root names to users or the
+       inability to see roots at all.  However, for root-specific
+       ViewVC views, all configuration &mdash; include root-specific
+       configuration &mdash; is honored.  If you are concerned about
+       leaking root names in the root listing view, you might consider
+       disabling that view altogether by removing <code>roots</code>
+       from the list of views specified in the 
+       <code>allowed_views</code> configuration option.</li>
+
+   <li>The experimental module which allows ViewVC to serve up views
+       of remote Subversion repositories is not yet fully integrated
+       with the authorization subsystem, and almost certainly will
+       leak privileged data.  Sorry.  That's (one reason) why it's
+       experimental.</li>
+
+</ul>
+
+</div>
+
+<div class="h3">
+<h3>Syntax Highlighting</h3>
+
+<p>ViewVC 1.0.x supports syntax highlighting provided by multiple
+   third-party highlighting engines, including GNU enscript, GNU
+   source-highlight, highlight, php, and py2html.  Unfortunately, each
+   of those integrations worked differently than the others.  Some
+   supported line numbers, some didn't; some were under active
+   development and recognized newer languages; some weren't; each had
+   its own set of CSS stylations that needed to be customized;
+   etc.</p>
+
+<p>In ViewVC 1.1, we've dropped support for all of those integations
+   in favor of a single integration with <a
+   href="http://www.pygments.org/"; >Pygments</a>, a
+   Python-module-based syntax highlighting engine.  As such, the
+   configuration options for the various other engines (both those
+   that enabled the integration and those that specified the locations
+   of the third-party tools) have been removed from ViewVC, and have
+   been replaced by a single new configuration option:
+   <code>enable_syntax_coloration</code>.</p>
+
+<p>The list of removed options is as follows:</p>
+
+<ul>
+  <li>options/enscript_path</li>
+  <li>options/highlight_convert_tabs</li>
+  <li>options/highlight_path</li>
+  <li>options/markup_line_numbers</li>
+  <li>options/php_exe</li>
+  <li>options/py2html_path</li>
+  <li>options/use_enscript</li>
+  <li>options/use_highlight</li>
+  <li>options/use_php</li>
+  <li>options/use_py2html</li>
+  <li>options/use_pygments</li>
+  <li>options/use_source_highlight</li>
+</ul>
 
 </div>
 
@@ -149,32 +252,6 @@
 </div>
 
 <div class="h3">
-<h3>Forbidden Modules</h3>
-    
-<p>ViewVC 1.1 introduces a new pluggable authorization (authz)
-   subsystem which gives administrators greater control over the
-   accessibility of the information ViewVC displays in its output.
-   ViewVC provides a number of working authz modules and framework for
-   configuring them.  But of specific interest to folks upgrading from
-   ViewVC 1.0 is that one of these new modules has replaced the
-   handling of forbidden modules.  As such, the <code>forbidden</code>
-   configuration option now lives under the configuration section
-   specific to that authz module.</p>
-
-<p>Migrating your existing configuration of forbidden modules should
-   be fairly straightforward.  Simply ensure that that the new
-   <code>authorizer</code> option is set to "forbidden" (which is the
-   default), and in the new "authz-forbidden" section of viewvc.conf,
-   set the <code>forbidden</code> option to the same thing it was set
-   to when it lived in the "options" section.</p>
-
-<p>Of course, you might wish to take advantage of another of the
-   provided authz modules.  Or, you might wish to write a brand new
-   one for your purposes.  The flexibility is yours.</p>
-
-</div>
-
-<div class="h3">
 <h3>Configuration Options</h3>
 
 <p>This section covers changes to configuration options not already
@@ -188,17 +265,10 @@
    following options were added:</p>
 
 <ul>
-  <li>options/use_py2html</li>
   <li>utilities/cvsgraph</li>
   <li>utilities/cvsnt</li>
   <li>utilities/diff</li>
-  <li>utilities/enscript</li>
-  <li>utilities/gzip</li>
-  <li>utilities/highlight</li>
-  <li>utilities/php</li>
-  <li>utilities/py2html_dir</li>
   <li>utilities/rcs_dir</li>
-  <li>utilities/sed</li>
   <li>utilities/svn</li>
 </ul>
 
@@ -209,10 +279,6 @@
   <li>general/rcs_path</li>
   <li>general/svn_path</li>
   <li>options/cvsgraph_path</li>
-  <li>options/enscript_path</li>
-  <li>options/highlight_path</li>
-  <li>options/php_exe</li>
-  <li>options/py2html_path</li>
 </ul>
 
 <p>All the options which governed which ViewVC views were enabled have
@@ -233,6 +299,10 @@
 <p>The <code>use_rcsparse</code> option was moved from the "general"
    section to the "options" section.</p>
 
+<p>The <code>log_sort</code> option's value "cvs" has been renamed to
+   "none" (for general application across all supported version
+   control systems).</p>
+
 <p>Custom sections which define per-virtual-host configuration option
    overrides must now have their names prefixed with "vhost-".  Also,
    instead of a hyphen (-) between the virtual host name and the base
@@ -261,6 +331,7 @@
 <p>The following is a grab-bag of additional new options:</p>
 
 <ul>
+  <li>options/hide_errorful_entries</li>
   <li>options/mangle_email_addresses</li>
 </ul>
 
@@ -274,6 +345,16 @@
    Authoring Guide</a> for the current set of variables available to
    each templates.</p>
 
+<p>One notable change in ViewVC 1.1 is that the markup.ezt and
+   annotate.ezt templates have been combined into a single file.ezt
+   template.</p>
+
+<p>Also, the configuration options under the <code>[templates]</code>
+   section are now paths relative to the configured template directory
+   (either the value of the <code>options/template_dir</code>
+   option, or the default "templates" directory), instead of being
+   relative to the configuration location.</p>
+
 <table>
 <thead>
 <tr>
@@ -288,108 +369,68 @@
   <td><em>all templates</em></td>
   <td>added</td>
 </tr>
+<tr class="removed">
+  <td class="varname">change_root_action</td>
+  <td><em>all templates</em></td>
+  <td>removed</td>
+</tr>
+<tr class="removed">
+  <td class="varname">change_root_hidden_values</td>
+  <td><em>all templates</em></td>
+  <td>removed</td>
+</tr>
+<tr class="removed">
+  <td class="varname">roots</td>
+  <td><em>all templates</em> except roots.ezt</td>
+  <td>removed</td>
+</tr>
 <tr class="added">
   <td class="varname">roots.path</td>
-  <td><em>all templates</em></td>
+  <td>roots.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
   <td class="varname">queryform_href</td>
-  <td>annotate.ezt, diff.ezt, graph.ezt, log.ezt, log_table.ezt, markup.ezt, 
+  <td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt, 
       query_form.ezt, revision.ezt, roots.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
   <td class="varname">tarball_href</td>
-  <td>annotate.ezt, diff.ezt, graph.ezt, log.ezt, log_table.ezt, markup.ezt, 
+  <td>diff.ezt, file.ezt, graph.ezt, log.ezt, log_table.ezt,
       query_form.ezt, query_results.ezt, revision.ezt, roots.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
-  <td class="varname">mime_type</td>
-  <td>annotate.ezt</td>
+  <td class="varname">properties</td>
+  <td>directory.ezt, file.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
-  <td class="varname">log</td>
-  <td>annotate.ezt</td>
+  <td class="varname">properties.name</td>
+  <td>directory.ezt, file.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
-  <td class="varname">date</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">ago</td>
-  <td>annotate.ezt</td>
+  <td class="varname">properties.undisplayable</td>
+  <td>directory.ezt, file.ezt</td>
   <td>added</td>
 </tr>
 <tr class="added">
-  <td class="varname">author</td>
-  <td>annotate.ezt</td>
+  <td class="varname">properties.value</td>
+  <td>directory.ezt, file.ezt</td>
   <td>added</td>
 </tr>
-<tr class="added">
-  <td class="varname">branches</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">tags</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">branch_points</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">changed</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">size</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">state</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">vendor_branch</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">prev</td>
-  <td>annotate.ezt</td>
-  <td>added</td>
+<tr class="changed">
+  <td class="varname">diff_format_hidden_values</td>
+  <td>diff.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
 </tr>
 <tr class="changed">
   <td class="varname">diff_type</td>
   <td>diff.ezt</td>
   <td>new value: <code>f</code></td>
 </tr>
-<tr class="changed">
-  <td class="varname">entries.log</td>
-  <td>directory.ezt, dir_alternate.ezt</td>
-  <td>now always contains untruncated log message</td>
-</tr>
-<tr class="added">
-  <td class="varname">entries.short_log</td>
-  <td>directory.ezt, dir_alternate.ezt</td>
-  <td>added</td>
-</tr>
-<tr class="added">
-  <td class="varname">rss_link_href</td>
-  <td>query.ezt, rss.ezt</td>
-  <td>added</td>
-</tr>
 <tr class="renamed">
   <td class="varname">date_left</td>
   <td>diff.ezt</td>
@@ -500,6 +541,96 @@
   <td>diff.ezt</td>
   <td>added</td>
 </tr>
+<tr class="changed">
+  <td class="varname">dir_paging_hidden_values</td>
+  <td>directory.ezt, , dir_alternate.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">entries.log</td>
+  <td>directory.ezt, dir_alternate.ezt</td>
+  <td>now always contains untruncated log message</td>
+</tr>
+<tr class="added">
+  <td class="varname">entries.short_log</td>
+  <td>directory.ezt, dir_alternate.ezt</td>
+  <td>added</td>
+</tr>
+<tr class="changed">
+  <td class="varname">search_re_hidden_values</td>
+  <td>directory.ezt, dir_alternate.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">search_tag_hidden_values</td>
+  <td>directory.ezt, dir_alternate.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">pathrev_clear_hidden_values</td>
+  <td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">pathrev_hidden_values</td>
+  <td>log.ezt, log_table.ezt, directory.ezt, dir_alternate.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+  <td class="varname">annotate_href</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>renamed to <code>head_annotate_href</code></td>
+</tr>
+<tr class="changed">
+  <td class="varname">diff_form_hidden_values</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+  <td class="varname">download_href</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>renamed to <code>head_download_href</code></td>
+</tr>
+<tr class="renamed">
+  <td class="varname">download_text_href</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>renamed to <code>head_download_text_href</code></td>
+</tr>
+<tr class="changed">
+  <td class="varname">log_paging_hidden_values</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">logsort_hidden_values</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="renamed">
+  <td class="varname">prefer_markup</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>renamed to <code>head_prefer_markup</code></td>
+</tr>
+<tr class="renamed">
+  <td class="varname">view_href</td>
+  <td>log.ezt, log_table.ezt</td>
+  <td>renamed to <code>head_view_href</code></td>
+</tr>
+<tr class="added">
+  <td class="varname">rss_link_href</td>
+  <td>query.ezt, rss.ezt</td>
+  <td>added</td>
+</tr>
+<tr class="changed">
+  <td class="varname">query_hidden_values</td>
+  <td>query_form.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
+<tr class="changed">
+  <td class="varname">jump_rev_hidden_values</td>
+  <td>revision.ezt</td>
+  <td>now is an iterable list of objects with .name and .value attributes</td>
+</tr>
 </tbody>
 </table>
 

Modified: branches/VIEWCVS_DIST/docs/url-reference.html
==============================================================================
--- branches/VIEWCVS_DIST/docs/url-reference.html	(original)
+++ branches/VIEWCVS_DIST/docs/url-reference.html	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 <html>
 <head>
-<title>ViewVC 1.0 URL Reference</title>
+<title>ViewVC 1.1 URL Reference</title>
 <style>
 body {
   background-color: rgb(180,193,205);
@@ -88,7 +88,7 @@
   <ul>
     <li><a href="#compat-viewrev">'<code>view=rev</code>' Parameter &rArr; '<code>view=revision</code>'</a></li>
     <li><a href="#compat-cvsroot">'<code>cvsroot</code>' Parameter &rArr; '<code>root</code>'</a></li>
-    <li><a href="#compat-only_with_tag>'<code>only_with_tag</code>' Parameter &rArr; '<code>pathrev</code>'</a></li>
+    <li><a href="#compat-only_with_tag">'<code>only_with_tag</code>' Parameter &rArr; '<code>pathrev</code>'</a></li>
     <li><a href="#compat-oldcheckout">'<code>~checkout~</code>' Magic Path Prefix &rArr; '<code>*checkout*</code>'</a></li>
     <li><a href="#compat-checkout">'<code>*checkout*</code>' Magic Path Prefix &rArr; '<code>view=co</code>'</a></li>
     <li><a href="#compat-root">'<code>root</code>' Parameter &rArr; Root Path Component</a></li>
@@ -98,7 +98,7 @@
     <li><a href="#compat-tarball">'<code>tarball=1</code>' Parameter &rArr; '<code>view=tar</code>'</a></li>
     <li><a href="#compat-graph">'<code>graph=1</code>' Parameter &rArr; '<code>view=graph</code>'</a></li>
     <li><a href="#compat-makeimage">'<code>graph=1&makeimage=1</code>' Parameters &rArr; '<code>view=graphimg</code>'</a></li>
-    <li><a href="#compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
+    <li><a href="#compat-content_type">'<code>content-type=text/vnd.viewcvs-markup</code>' and '<code>content-type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'
     <li><a href="#compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</a></li>
   </ul>
 </div>
@@ -1013,6 +1013,17 @@
         of author match</td>
   </tr>
   <tr>
+    <td><code>comment=<var>COMMENT</var></code></td>
+    <td>optional</td>
+    <td>log message query string</td>
+  </tr>
+  <tr>
+    <td><code>comment_match=<var>COMMENT_MATCH</var></code></td>
+    <td>optional</td>
+    <td>"exact" "like" "glob" "regex" or "notregex" determining type
+        of log message match</td>
+  </tr>
+  <tr>
     <td><code>querysort=SORT</code></td>
     <td>optional</td>
     <td>"date" "author" or "file" determining order of query results</td>
@@ -1456,11 +1467,14 @@
 
 <h3 id="compat-content_type">'<code>content_type=text/vnd.viewcvs-markup</code>' and '<code>content_type=text/x-cvsweb-markup</code>' Parameters&rArr; '<code>view=markup</code>'</h3>
 
-<p><code>content_type=text/vnd.viewcvs-markup</code> and
-   <code>content_type=text/x-cvsweb-markup</code> parameters are
+<p><code>content-type=text/vnd.viewcvs-markup</code> and
+   <code>content-type=text/x-cvsweb-markup</code> parameters are
    treated like a <code>view=markup</code> parameter. There is
    currently no redirect when it is encountered, but there could be
-   one in the future.</p>
+   one in the future.  Other values of the <code>content-type</code>
+   parameter, which were used to dictate the MIME type of files
+   displayed in the checkout/download view prior to ViewVC 1.0.6, are
+   ignored.</p>
 
 <h3 id="compat-attic">'<code>Attic/FILE</code>' Paths &rArr; '<code>FILE</code>'</h3>
 

Modified: branches/VIEWCVS_DIST/lib/blame.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/blame.py	(original)
+++ branches/VIEWCVS_DIST/lib/blame.py	Mon Nov  3 09:44:02 2008
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 # Copyright (C) 2000 Curt Hagenlocher <curt hagenlocher org>
 #
 # By using this file, you agree to the terms and conditions set forth in
@@ -34,7 +34,6 @@
 import math
 import cgi
 import vclib
-import vclib.ccvs.blame
 
 
 re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
@@ -101,6 +100,7 @@
 
 
 def make_html(root, rcs_path):
+  import vclib.ccvs.blame
   bs = vclib.ccvs.blame.BlameSource(os.path.join(root, rcs_path))
 
   line = 0

Modified: branches/VIEWCVS_DIST/lib/config.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/config.py	(original)
+++ branches/VIEWCVS_DIST/lib/config.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -39,8 +39,7 @@
 
 class Config:
   _sections = ('general', 'utilities', 'options', 'cvsdb', 'templates')
-  _force_multi_value = ('cvs_roots', 'forbidden',
-                        'svn_roots', 'languages', 'kv_files',
+  _force_multi_value = ('cvs_roots', 'svn_roots', 'languages', 'kv_files',
                         'root_parents', 'allowed_views')
 
   def __init__(self):
@@ -163,18 +162,32 @@
       return
     self._process_root_options(self.parser, rootname)
 
+  def _get_parser_items(self, parser, section):
+    """Basically implement ConfigParser.items() for pre-Python-2.3 versions."""
+    try:
+      return self.parser.items(section)
+    except AttributeError:
+      d = {}
+      for option in parser.options(section):
+        d[option] = parser.get(section, option)
+      return d.items()
+    
   def get_authorizer_params(self, authorizer, rootname=None):
     if not self.conf_path:
       return {}
-    
+
     params = {}
     authz_section = 'authz-%s' % (authorizer)
+    for section in self.parser.sections():
+      if section == authz_section:
+        for key, value in self._get_parser_items(self.parser, section):
+          params[key] = value
     if rootname:
       root_authz_section = 'root-%s/authz-%s' % (rootname, authorizer)
-    for section in self.parser.sections():
-      if section == authz_section \
-         or (rootname and section == root_authz_section):
-        params.update(self.parser.items(section))
+      for section in self.parser.sections():
+        if section == root_authz_section:
+          for key, value in self._get_parser_items(self.parser, section):
+            params[key] = value
     return params
   
   def set_defaults(self):
@@ -185,7 +198,7 @@
     self.general.root_parents = []
     self.general.default_root = ''
     self.general.mime_types_file = ''
-    self.general.address = '<a href="mailto:user insert your domain here">No admin address has been configured</a>'
+    self.general.address = ''
     self.general.kv_files = [ ]
     self.general.languages = ['en-us']
 
@@ -196,36 +209,31 @@
       self.utilities.cvsnt = None
     self.utilities.svn = ''
     self.utilities.diff = ''
-    self.utilities.enscript = ''
-    self.utilities.highlight = ''
-    self.utilities.source_highlight = ''
-    self.utilities.py2html_dir = '.'
-    self.utilities.php = 'php'
     self.utilities.cvsgraph = ''
-    self.utilities.gzip = ''
-    self.utilities.sed = ''
 
     self.options.root_as_url_component = 1
     self.options.checkout_magic = 0
-    self.options.allowed_views = ['markup', 'annotate']
+    self.options.allowed_views = ['markup', 'annotate', 'roots']
     self.options.authorizer = 'forbidden'
     self.options.mangle_email_addresses = 0
     self.options.default_file_view = "log"
     self.options.http_expiration_time = 600
     self.options.generate_etags = 1
+    self.options.svn_config_dir = None
     self.options.use_rcsparse = 0
     self.options.sort_by = 'file'
     self.options.sort_group_dirs = 1
     self.options.hide_attic = 1
+    self.options.hide_errorful_entries = 0
     self.options.log_sort = 'date'
     self.options.diff_format = 'h'
     self.options.hide_cvsroot = 1
     self.options.hr_breakable = 1
     self.options.hr_funout = 1
-    self.options.hr_ignore_white = 1
+    self.options.hr_ignore_white = 0
     self.options.hr_ignore_keyword_subst = 1
     self.options.hr_intraline = 0
-    self.options.allow_compress = 1
+    self.options.allow_compress = 0
     self.options.template_dir = "templates"
     self.options.docroot = None
     self.options.show_subdir_lastmod = 0
@@ -234,27 +242,19 @@
     self.options.cross_copies = 0
     self.options.use_localtime = 0
     self.options.short_log_len = 80
-    self.options.use_py2html = 0
-    self.options.use_enscript = 0
-    self.options.use_highlight = 0
-    self.options.highlight_line_numbers = 1
-    self.options.highlight_convert_tabs = 2
-    self.options.use_source_highlight = 0
-    self.options.source_highlight_line_numbers = 1
-    self.options.use_php = 0
+    self.options.enable_syntax_coloration = 1
     self.options.use_cvsgraph = 0
     self.options.cvsgraph_conf = "cvsgraph.conf"
     self.options.use_re_search = 0
     self.options.use_pagesize = 0
     self.options.limit_changes = 100
 
-    self.templates.annotate = None
     self.templates.diff = None
     self.templates.directory = None
     self.templates.error = None
+    self.templates.file = None
     self.templates.graph = None
     self.templates.log = None
-    self.templates.markup = None
     self.templates.query = None
     self.templates.query_form = None
     self.templates.query_results = None
@@ -270,6 +270,7 @@
     self.cvsdb.readonly_passwd = '' 
     self.cvsdb.row_limit = 1000
     self.cvsdb.rss_row_limit = 100
+    self.cvsdb.check_database_for_root = 0
 
 def _startswith(somestr, substr):
   return somestr[:len(substr)] == substr

Modified: branches/VIEWCVS_DIST/lib/cvsdb.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/cvsdb.py	(original)
+++ branches/VIEWCVS_DIST/lib/cvsdb.py	Mon Nov  3 09:44:02 2008
@@ -17,6 +17,7 @@
 import fnmatch
 import re
 
+import vclib
 import dbi
 
 
@@ -447,9 +448,13 @@
 
         return commit
 
-    def sql_delete(self, table, key, value):
+    def sql_delete(self, table, key, value, keep_fkey = None):
         sql = "DELETE FROM %s WHERE %s=%%s" % (table, key)
         sql_args = (value, )
+        if keep_fkey:
+          sql += " AND %s NOT IN (SELECT %s FROM checkins WHERE %s = %%s)" \
+                 % (key, keep_fkey, keep_fkey)
+          sql_args = (value, value)
         cursor = self.db.cursor()
         cursor.execute(sql, sql_args)
         
@@ -470,16 +475,16 @@
                  plus_count, minus_count, description_id) = cursor.fetchone()
             except TypeError:
                 break
-            checkins.append([file_id, dir_id, branch_id, description_id])
+            checkins.append([file_id, dir_id, branch_id, description_id, who_id])
 
         #self.sql_delete('repositories', 'id', rep_id)
         self.sql_delete('checkins', 'repositoryid', rep_id)
         for checkin in checkins:
-            self.sql_delete('files', 'id', checkin[0])
-            self.sql_delete('dirs', 'id', checkin[1])
-            self.sql_delete('branches', 'id', checkin[2])
-            self.sql_delete('descs', 'id', checkin[3])
-
+            self.sql_delete('files', 'id', checkin[0], 'fileid')
+            self.sql_delete('dirs', 'id', checkin[1], 'dirid')
+            self.sql_delete('branches', 'id', checkin[2], 'branchid')
+            self.sql_delete('descs', 'id', checkin[3], 'descid')
+            self.sql_delete('people', 'id', checkin[4], 'whoid')
 
 ## the Commit class holds data on one commit, the representation is as
 ## close as possible to how it should be committed and retrieved to the
@@ -761,7 +766,8 @@
     directory = string.join(path_parts[:-1], "/")
     file = path_parts[-1]
 
-    revs = repository.itemlog(path_parts, revision, {"cvs_pass_rev": 1})
+    revs = repository.itemlog(path_parts, revision, vclib.SORTBY_DEFAULT,
+                              0, 0, {"cvs_pass_rev": 1})
     for rev in revs:
         commit = CreateCommit()
         commit.SetRepository(repository.rootpath)

Modified: branches/VIEWCVS_DIST/lib/debug.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/debug.py	(original)
+++ branches/VIEWCVS_DIST/lib/debug.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -68,12 +68,6 @@
     return "ViewVC Unrecoverable Error: %s" % self.msg
 
 
-class ViewVCNotAuthorizedException(ViewVCException):
-  def __init__(self, user, what):
-    msg = 'User "%s" is not authorized to see %s' % (user, what)
-    ViewVCException.__init__(self, msg, '501 Not Authorized')
-
-
 def PrintException(server, exc_data):
   status = exc_data['status']
   msg = exc_data['msg']

Modified: branches/VIEWCVS_DIST/lib/popen.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/popen.py	(original)
+++ branches/VIEWCVS_DIST/lib/popen.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC

Modified: branches/VIEWCVS_DIST/lib/query.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/query.py	(original)
+++ branches/VIEWCVS_DIST/lib/query.py	Mon Nov  3 09:44:02 2008
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*-python-*-
 #
-# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -390,6 +390,13 @@
     commits.append(build_commit(server, cfg, current_desc, files,
                                 cvsroots, viewvc_link))
 
+    # Strip out commits that don't have any files attached to them.  The
+    # files probably aren't present because they've been blocked via
+    # forbiddenness.
+    def _only_with_files(commit):
+        return len(commit.files) > 0
+    commits = filter(_only_with_files, commits)
+  
     return commits
 
 def main(server, cfg, viewvc_link):

Modified: branches/VIEWCVS_DIST/lib/vcauth/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vcauth/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vcauth/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -19,39 +19,31 @@
 class GenericViewVCAuthorizer:
   """Abstract class encapsulating version control authorization routines."""
   
-  def __init__(self, username, root, params={}):
+  def __init__(self, username=None, params={}):
     """Create a GenericViewVCAuthorizer object which will be used to
     validate that USERNAME has the permissions needed to view version
-    control repository ROOT (in whole or in part).  PARAMS is a
-    dictionary of custom parameters for the authorizer.
-
-    Raise ViewVCRootAccessNotAuthorized error if USERNAME isn't
-    allowed to see this repository at all."""
+    control repositories (in whole or in part).  PARAMS is a
+    dictionary of custom parameters for the authorizer."""
     pass
 
-  def check_path_access(self, path_parts, rev=None):
+  def check_root_access(self, rootname):
+    """Return 1 iff the associated username is permitted to read ROOTNAME."""
+    pass
+  
+  def check_path_access(self, rootname, path_parts, pathtype, rev=None):
     """Return 1 iff the associated username is permitted to read
-    revision REV of the path PATH_PARTS in the repository associated
-    with this authorizer."""
+    revision REV of the path PATH_PARTS (of type PATHTYPE) in
+    repository ROOTNAME."""
     pass
 
 
-class ViewVCRootAccessNotAuthorized(Exception):
-  def __init__(self, rootname, username):
-    self.rootname = rootname
-    self.username = username
-  def __str__(self):
-    return "Access to root '%s' by user '%s' is denied." \
-           % (self.rootname, self.username)
-
-
 
 ##############################################################################
 
 class ViewVCAuthorizer(GenericViewVCAuthorizer):
   """The uber-permissive authorizer."""
-  def __init__(self):
-    pass
+  def check_root_access(self, rootname):
+    return 1
     
-  def check_path_access(self, path_parts, rev=None):
+  def check_path_access(self, rootname, path_parts, pathtype, rev=None):
     return 1

Modified: branches/VIEWCVS_DIST/lib/vcauth/forbidden/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vcauth/forbidden/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vcauth/forbidden/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -16,25 +16,24 @@
 
 class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
   """A simple top-level module authorizer."""
-  def __init__(self, username, root, params={}):
+  def __init__(self, username, params={}):
     forbidden = params.get('forbidden', '')
-    self.root = root
     self.forbidden = map(string.strip,
                          filter(None, string.split(forbidden, ',')))
-    
-  def check_path_access(self, path_parts, rev=None):
+
+  def check_root_access(self, rootname):
+    return 1
+  
+  def check_path_access(self, rootname, path_parts, pathtype, rev=None):
     # No path?  No problem.
     if not path_parts:
       return 1
 
-    # If we have a single path part, we can't tell if this is a file
-    # or a directory.  So we ask our version control system.  If it's
-    # not a directory, we don't care about it.
-    if len(path_parts) == 1:
-      if self.root.itemtype(path_parts, rev) != vclib.DIR:
-        return 1
+    # Not a directory?  We aren't interested.
+    if pathtype != vclib.DIR:
+      return 1
 
-    # At this point we're looking a path we believe to be a directory.
+    # At this point we're looking at a directory path.
     module = path_parts[0]
     default = 1
     for pat in self.forbidden:

Added: branches/VIEWCVS_DIST/lib/vcauth/forbiddenre/__init__.py
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/lib/vcauth/forbiddenre/__init__.py	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,58 @@
+# -*-python-*-
+#
+# Copyright (C) 2008 The ViewCVS Group. All Rights Reserved.
+#
+# By using this file, you agree to the terms and conditions set forth in
+# the LICENSE.html file which can be found at the top level of the ViewVC
+# distribution or at http://viewvc.org/license-1.html.
+#
+# For more information, visit http://viewvc.org/
+#
+# -----------------------------------------------------------------------
+import vcauth
+import vclib
+import fnmatch
+import string
+import re
+
+
+def _split_regexp(restr):
+  """Return a 2-tuple consisting of a compiled regular expression
+  object and a boolean flag indicating if that object should be
+  interpreted inversely."""
+  if restr[0] == '!':
+    return re.compile(restr[1:]), 1
+  return re.compile(restr), 0
+
+
+class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
+  """A simple regular-expression-based authorizer."""
+  def __init__(self, username, params={}):
+    forbidden = params.get('forbiddenre', '')
+    self.forbidden = map(lambda x: _split_regexp(string.strip(x)),
+                         filter(None, string.split(forbidden, ',')))
+                         
+  def _check_root_path_access(self, root_path):
+    default = 1
+    for forbidden, negated in self.forbidden:
+      if negated:
+        default = 0
+        if forbidden.search(root_path):
+          return 1
+      elif forbidden.search(root_path):
+        return 0
+    return default
+      
+  def check_root_access(self, rootname):
+    return self._check_root_path_access(rootname)
+  
+  def check_path_access(self, rootname, path_parts, pathtype, rev=None):
+    root_path = rootname
+    if path_parts:
+      root_path = root_path + '/' + string.join(path_parts, '/')
+      if pathtype == vclib.DIR:
+        root_path = root_path + '/'
+    else:
+      root_path = root_path + '/'
+    return self._check_root_path_access(root_path)
+    

Modified: branches/VIEWCVS_DIST/lib/vcauth/svnauthz/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vcauth/svnauthz/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vcauth/svnauthz/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 2006-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -21,20 +21,34 @@
 class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
   """Subversion authz authorizer module"""
   
-  def __init__(self, username, root, params={}):
-    rootname = root.rootname()
-    self.paths = {}   # paths-in-root -> access boolean for USERNAME
+  def __init__(self, username, params={}):
+    self.username = username
+    self.rootpaths = { }  # {root -> { paths -> access boolean for USERNAME }}
     
     # Get the authz file location from a passed-in parameter.
-    authz_file = params.get('authzfile')
-    if not authz_file:
+    self.authz_file = params.get('authzfile')
+    if not self.authz_file:
       raise debug.ViewVCException("No authzfile configured")
-    if not os.path.exists(authz_file):
+    if not os.path.exists(self.authz_file):
       raise debug.ViewVCException("Configured authzfile file not found")
 
+  def _get_paths_for_root(self, rootname):
+    if self.rootpaths.has_key(rootname):
+      return self.rootpaths[rootname]
+
+    paths_for_root = { }
+    
     # Parse the authz file.
     cp = ConfigParser()
-    cp.read(authz_file)
+    cp.read(self.authz_file)
+
+    # Figure out if there are any aliases for the current username
+    aliases = []
+    if cp.has_section('aliases'):
+      for alias in cp.options('aliases'):
+        entry = cp.get('aliases', alias)
+        if entry == self.username:
+          aliases.append(alias)
 
     # Figure out which groups USERNAME has a part of.
     groups = []
@@ -69,12 +83,15 @@
         entries = string.split(cp.get('groups', groupname), ',')
         for entry in entries:
           entry = string.strip(entry)
-          if entry == username:
+          if entry == self.username:
             group_member = 1
             break
           elif entry[0:1] == "@" and _process_group(entry[1:]):
             group_member = 1
             break
+          elif entry[0:1] == "&" and entry[1:] in aliases:
+            group_member = 1
+            break
         if group_member:
           groups.append(groupname)
         return group_member
@@ -83,31 +100,31 @@
       for group in cp.options('groups'):
         _process_group(group)
 
-    # Read the other (non-"groups") sections, and figure out in which
-    # repositories USERNAME or his groups have read rights.
-    root_is_readable = 0
-    for section in cp.sections():
-
-      # Skip the "groups" section -- we handled that already.
-      if section == 'groups':
-        continue
-
-      # Skip sections not related to our rootname.  While we're at it,
-      # go ahead and figure out the repository path we're talking about.
-      if section.find(':') == -1:
-        path = section
-      else:
-        root, path = string.split(section, ':', 1)
-        if root != rootname:
-          continue
-
+    def _userspec_matches_user(userspec):
+      # If there is an inversion character, recurse and return the
+      # opposite result.
+      if userspec[0:1] == '~':
+        return not _userspec_matches_user(userspec[1:])
+
+      # See if the userspec applies to our current user.
+      return userspec == '*' \
+             or userspec == self.username \
+             or (self.username is not None and userspec == "$authenticated") \
+             or (self.username is None and userspec == "$anonymous") \
+             or (userspec[0:1] == "@" and userspec[1:] in groups) \
+             or (userspec[0:1] == "&" and userspec[1:] in aliases)
+      
+    def _process_access_section(section):
+      """Inline function for determining user access in a single
+      config secction.  Return a two-tuple (ALLOW, DENY) containing
+      the access determination for USERNAME in a given authz file
+      SECTION (if any)."""
+  
       # Figure if this path is explicitly allowed or denied to USERNAME.
       allow = deny = 0
       for user in cp.options(section):
         user = string.strip(user)
-        if user == '*' \
-           or user == username \
-           or (user[0:1] == "@" and user[1:] in groups):
+        if _userspec_matches_user(user):
           # See if the 'r' permission is among the ones granted to
           # USER.  If so, we can stop looking.  (Entry order is not
           # relevant -- we'll use the most permissive entry, meaning
@@ -116,28 +133,91 @@
           deny = not allow
           if allow:
             break
+      return allow, deny
+    
+    # Read the other (non-"groups") sections, and figure out in which
+    # repositories USERNAME or his groups have read rights.  We'll
+    # first check groups that have no specific repository designation,
+    # then superimpose those that have a repository designation which
+    # matches the one we're asking about.
+    root_sections = []
+    for section in cp.sections():
+
+      # Skip the "groups" section -- we handled that already.
+      if section == 'groups':
+        continue
+      
+      if section == 'aliases':
+        continue
+
+      # Process root-agnostic access sections; skip (but remember)
+      # root-specific ones that match our root; ignore altogether
+      # root-specific ones that don't match our root.  While we're at
+      # it, go ahead and figure out the repository path we're talking
+      # about.
+      if section.find(':') == -1:
+        path = section
+      else:
+        name, path = string.split(section, ':', 1)
+        if name == rootname:
+          root_sections.append(section)
+        continue
+
+      # Check for a specific access determination.
+      allow, deny = _process_access_section(section)
           
       # If we got an explicit access determination for this path and this
       # USERNAME, record it.
       if allow or deny:
-        if allow:
-          root_is_readable = 1
         if path != '/':
           path = '/' + string.join(filter(None, string.split(path, '/')), '/')
-        self.paths[path] = allow
+        paths_for_root[path] = allow
 
-    # If USERNAME can't see this root at all, raise an error.
+    # Okay.  Superimpose those root-specific values now.
+    for section in root_sections:
+
+      # Get the path again.
+      name, path = string.split(section, ':', 1)
+      
+      # Check for a specific access determination.
+      allow, deny = _process_access_section(section)
+                
+      # If we got an explicit access determination for this path and this
+      # USERNAME, record it.
+      if allow or deny:
+        if path != '/':
+          path = '/' + string.join(filter(None, string.split(path, '/')), '/')
+        paths_for_root[path] = allow
+
+    # If the root isn't readable, there's no point in caring about all
+    # the specific paths the user can't see.  Just point the rootname
+    # to a None paths dictionary.
+    root_is_readable = 0
+    for path in paths_for_root.keys():
+      if paths_for_root[path]:
+        root_is_readable = 1
+        break
     if not root_is_readable:
-      raise vcauth.ViewVCRootAccessNotAuthorized(rootname, username)
+      paths_for_root = None
+      
+    self.rootpaths[rootname] = paths_for_root
+    return paths_for_root
 
-  def check_path_access(self, path_parts, rev=None):
+  def check_root_access(self, rootname):
+    paths = self._get_paths_for_root(rootname)
+    return (paths is not None) and 1 or 0
+  
+  def check_path_access(self, rootname, path_parts, pathtype, rev=None):
     # Crawl upward from the path represented by PATH_PARTS toward to
     # the root of the repository, looking for an explicitly grant or
     # denial of access.
+    paths = self._get_paths_for_root(rootname)
+    if paths is None:
+      return 0
     parts = path_parts[:]
     while parts:
       path = '/' + string.join(parts, '/')
-      if self.paths.has_key(path):
-        return self.paths[path]
+      if paths.has_key(path):
+        return paths[path]
       del parts[-1]
-    return self.paths.get('/', 0)
+    return paths.get('/', 0)

Modified: branches/VIEWCVS_DIST/lib/vclib/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -37,6 +37,12 @@
 REPLACED   = 'replaced'
 MODIFIED   = 'modified'
 
+# log sort keys
+SORTBY_DEFAULT = 0  # default/no sorting
+SORTBY_DATE    = 1  # sorted by date, youngest first
+SORTBY_REV     = 2  # sorted by revision, youngest first
+
+
 # ======================================================================
 #
 class Repository:
@@ -50,6 +56,13 @@
 
   def rootpath(self):
     """Return the location of this repository."""
+
+  def authorizer(self):
+    """Return the vcauth.Authorizer object associated with this
+    repository, or None if no such association has been made."""
+    
+  def open(self):
+    """Open a connection to the repository."""
     
   def itemtype(self, path_parts, rev):
     """Return the type of the item (file or dir) at the given path and revision
@@ -94,7 +107,7 @@
     New properties will be set on all of the DirEntry objects in the entries
     list. At the very least, a "rev" property will be set to a revision
     number or None if the entry doesn't have a number. Other properties that
-    may be set include "date", "author", and "log".
+    may be set include "date", "author", "log", "size", and "lockinfo".
 
     The path is specified as a list of components, relative to the root
     of the repository. e.g. ["subdir1", "subdir2", "filename"]
@@ -108,7 +121,7 @@
     options is a dictionary of implementation specific options
     """
   
-  def itemlog(self, path_parts, rev, options):
+  def itemlog(self, path_parts, rev, sortby, first, limit, options):
     """Retrieve an item's log information
 
     The result is a list of Revision objects
@@ -118,9 +131,28 @@
 
     rev is the revision of the item to return information about
 
+    sortby indicates the way in which the returned list should be
+    sorted (SORTBY_DEFAULT, SORTBY_DATE, SORTBY_REV)
+
+    first is the 0-based index of the first Revision returned (after
+    sorting, if any, has occured)
+
+    limit is the maximum number of returned Revisions, or 0 to return
+    all available data
+    
     options is a dictionary of implementation specific options
     """
 
+  def itemprops(self, path_parts, rev):
+    """Return a dictionary mapping property names to property values
+    for properties stored on an item.
+
+    The path is specified as a list of components, relative to the root
+    of the repository. e.g. ["subdir1", "subdir2", "filename"]
+
+    rev is the revision of the item to return information about.
+    """
+    
   def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
     """Return a diff (in GNU diff format) of two file revisions
 
@@ -155,6 +187,17 @@
     doesn't support a global revision concept.
     """
 
+  def isexecutable(self, path_parts, rev):
+    """Return true iff a given revision of a versioned file is to be
+    considered an executable program or script.
+
+    The path is specified as a list of components, relative to the root
+    of the repository. e.g. ["subdir1", "subdir2", "filename"]
+
+    rev is the revision of the item to return information about
+    """
+    
+    
 # ======================================================================
 class DirEntry:
   """Instances represent items in a directory listing"""
@@ -173,7 +216,7 @@
 class Revision:
   """Instances holds information about revisions of versioned resources"""
 
-  def __init__(self, number, string, date, author, changed, log, size):
+  def __init__(self, number, string, date, author, changed, log, size, lockinfo):
     """Create a new Revision() item:
           NUMBER:  Revision in an integer-based, sortable format
           STRING:  Revision as a string
@@ -182,6 +225,7 @@
           CHANGED:  Lines-changed (contextual diff) information
           LOG:  Log message associated with the creation of this revision
           SIZE:  Size (in bytes) of this revision's fulltext (files only)
+          LOCKINFO:  Information about locks held on this revision
     """
     self.number = number
     self.string = string
@@ -190,6 +234,7 @@
     self.changed = changed
     self.log = log
     self.size = size
+    self.lockinfo = lockinfo
 
   def __cmp__(self, other):
     return cmp(self.number, other.number)
@@ -350,3 +395,26 @@
   def _label(self, (path, date, rev)):
     date = date and time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date))
     return "%s\t%s\t%s" % (path, date, rev)
+
+
+def check_root_access(repos):
+  """Return 1 iff the associated username is permitted to read REPOS,
+  as determined by consulting REPOS's Authorizer object (if any)."""
+
+  auth = repos.authorizer()
+  if not auth:
+    return 1
+  return auth.check_root_access(repos.rootname())
+  
+def check_path_access(repos, path_parts, pathtype=None, rev=None):
+  """Return 1 iff the associated username is permitted to read
+  revision REV of the path PATH_PARTS (of type PATHTYPE) in repository
+  REPOS, as determined by consulting REPOS's Authorizer object (if any)."""
+
+  auth = repos.authorizer()
+  if not auth:
+    return 1
+  if not pathtype:
+    pathtype = repos.itemtype(path_parts, rev)
+  return auth.check_path_access(repos.rootname(), path_parts, pathtype, rev)
+

Modified: branches/VIEWCVS_DIST/lib/vclib/ccvs/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/ccvs/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -9,347 +9,35 @@
 # For more information, visit http://viewvc.org/
 #
 # -----------------------------------------------------------------------
-
-"""
-This is a Version Control library driver for locally accessible cvs-repositories.
-"""
-
 import os
-import string
-import re
-import cStringIO
-import tempfile
-
-import vclib
-import rcsparse
-import blame
-
-### The functionality shared with bincvs should probably be moved to a
-### separate module
-from vclib.bincvs import CVSRepository, Revision, Tag, \
-                         _file_log, _log_path
-
-class CCVSRepository(CVSRepository):
-  def dirlogs(self, path_parts, rev, entries, options):
-    """see vclib.Repository.dirlogs docstring
-
-    rev can be a tag name or None. if set only information from revisions
-    matching the tag will be retrieved
-
-    Option values recognized by this implementation:
-
-      cvs_subdirs
-        boolean. true to fetch logs of the most recently modified file in each
-        subdirectory
-
-    Option values returned by this implementation:
-
-      cvs_tags, cvs_branches
-        lists of tag and branch names encountered in the directory
-    """
-    subdirs = options.get('cvs_subdirs', 0)
-
-    dirpath = self._getpath(path_parts)
-    alltags = {           # all the tags seen in the files of this dir
-      'MAIN' : '',
-      'HEAD' : '1.1'
-    }
-
-    for entry in entries:
-      entry.rev = entry.date = entry.author = entry.dead = entry.log = None
-      path = _log_path(entry, dirpath, subdirs)
-      if path:
-        entry.path = path
-        try:
-          rcsparse.parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
-        except IOError, e:
-          entry.errors.append("rcsparse error: %s" % e)
-        except RuntimeError, e:
-          entry.errors.append("rcsparse error: %s" % e)
-        except rcsparse.RCSStopParser:
-          pass
-
-    branches = options['cvs_branches'] = []
-    tags = options['cvs_tags'] = []
-    for name, rev in alltags.items():
-      if Tag(None, rev).is_branch:
-        branches.append(name)
-      else:
-        tags.append(name)
-
-  def itemlog(self, path_parts, rev, options):
-    """see vclib.Repository.itemlog docstring
-
-    rev parameter can be a revision number, a branch number, a tag name,
-    or None. If None, will return information about all revisions, otherwise,
-    will only return information about the specified revision or branch.
-
-    Option values returned by this implementation:
-
-      cvs_tags
-        dictionary of Tag objects for all tags encountered
-    """
-    path = self.rcsfile(path_parts, 1)
-    sink = TreeSink()
-    rcsparse.parse(open(path, 'rb'), sink)
-    filtered_revs = _file_log(sink.revs.values(), sink.tags,
-                              sink.default_branch, rev)
-    for rev in filtered_revs:
-      if rev.prev and len(rev.number) == 2:
-        rev.changed = rev.prev.next_changed
-    options['cvs_tags'] = sink.tags
-
-    return filtered_revs
-
-  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
-    temp1 = tempfile.mktemp()
-    open(temp1, 'wb').write(self.openfile(path_parts1, rev1)[0].getvalue())
-    temp2 = tempfile.mktemp()
-    open(temp2, 'wb').write(self.openfile(path_parts2, rev2)[0].getvalue())
-
-    r1 = self.itemlog(path_parts1, rev1, {})[-1]
-    r2 = self.itemlog(path_parts2, rev2, {})[-1]
-
-    info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
-    info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
-
-    diff_args = vclib._diff_args(type, options)
-
-    return vclib._diff_fp(temp1, temp2, info1, info2,
-                          self.utilities.diff or 'diff', diff_args)
-
-  def annotate(self, path_parts, rev=None):
-    source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
-    return source, source.revision
-
-  def revinfo(self, rev):
-    raise vclib.UnsupportedFeature
-
-  def openfile(self, path_parts, rev=None):
-    path = self.rcsfile(path_parts, 1)
-    sink = COSink(rev)
-    rcsparse.parse(open(path, 'rb'), sink)
-    revision = sink.last and sink.last.string
-    return cStringIO.StringIO(string.join(sink.sstext.text, "\n")), revision
-
-class MatchingSink(rcsparse.Sink):
-  """Superclass for sinks that search for revisions based on tag or number"""
-
-  def __init__(self, find):
-    """Initialize with tag name or revision number string to match against"""
-    if not find or find == 'MAIN' or find == 'HEAD':
-      self.find = None
-    else:
-      self.find = find
-
-    self.find_tag = None
-
-  def set_principal_branch(self, branch_number):
-    if self.find is None:
-      self.find_tag = Tag(None, branch_number)
-
-  def define_tag(self, name, revision):
-    if name == self.find:
-      self.find_tag = Tag(None, revision)
-
-  def admin_completed(self):
-    if self.find_tag is None:
-      if self.find is None:
-        self.find_tag = Tag(None, '')
-      else:
-        try:
-          self.find_tag = Tag(None, self.find)
-        except ValueError:
-          pass
-
-class InfoSink(MatchingSink):
-  def __init__(self, entry, tag, alltags):
-    MatchingSink.__init__(self, tag)
-    self.entry = entry
-    self.alltags = alltags
-    self.matching_rev = None
-    self.perfect_match = 0
-
-  def define_tag(self, name, revision):
-    MatchingSink.define_tag(self, name, revision)
-    self.alltags[name] = revision
-
-  def admin_completed(self):
-    MatchingSink.admin_completed(self)
-    if self.find_tag is None:
-      # tag we're looking for doesn't exist
-      raise rcsparse.RCSStopParser
-
-  def define_revision(self, revision, date, author, state, branches, next):
-    if self.perfect_match:
-      return
-
-    tag = self.find_tag
-    rev = Revision(revision, date, author, state == "dead")
-
-    # perfect match if revision number matches tag number or if revision is on
-    # trunk and tag points to trunk. imperfect match if tag refers to a branch
-    # and this revision is the highest revision so far found on that branch
-    perfect = ((rev.number == tag.number) or
-               (not tag.number and len(rev.number) == 2))
-    if perfect or (tag.is_branch and tag.number == rev.number[:-1] and
-                   (not self.matching_rev or
-                    rev.number > self.matching_rev.number)):
-      self.matching_rev = rev
-      self.perfect_match = perfect
-
-  def set_revision_info(self, revision, log, text):
-    if self.matching_rev:
-      if revision == self.matching_rev.string:
-        self.entry.rev = self.matching_rev.string
-        self.entry.date = self.matching_rev.date
-        self.entry.author = self.matching_rev.author
-        self.entry.dead = self.matching_rev.dead
-        self.entry.log = log
-        raise rcsparse.RCSStopParser
-    else:
-      raise rcsparse.RCSStopParser
-
-class TreeSink(rcsparse.Sink):
-  d_command = re.compile('^d(\d+)\\s(\\d+)')
-  a_command = re.compile('^a(\d+)\\s(\\d+)')
-
-  def __init__(self):
-    self.revs = { }
-    self.tags = { }
-    self.head = None
-    self.default_branch = None
-
-  def set_head_revision(self, revision):
-    self.head = revision
-
-  def set_principal_branch(self, branch_number):
-    self.default_branch = branch_number
-
-  def define_tag(self, name, revision):
-    # check !tags.has_key(tag_name)
-    self.tags[name] = revision
-
-  def define_revision(self, revision, date, author, state, branches, next):
-    # check !revs.has_key(revision)
-    self.revs[revision] = Revision(revision, date, author, state == "dead")
-
-  def set_revision_info(self, revision, log, text):
-    # check revs.has_key(revision)
-    rev = self.revs[revision]
-    rev.log = log
-
-    changed = None
-    added = 0
-    deled = 0
-    if self.head != revision:
-      changed = 1
-      lines = string.split(text, '\n')
-      idx = 0
-      while idx < len(lines):
-        command = lines[idx]
-        dmatch = self.d_command.match(command)
-        idx = idx + 1
-        if dmatch:
-          deled = deled + string.atoi(dmatch.group(2))
-        else:
-          amatch = self.a_command.match(command)
-          if amatch:
-            count = string.atoi(amatch.group(2))
-            added = added + count
-            idx = idx + count
-          elif command:
-            raise "error while parsing deltatext: %s" % command
-
-    if len(rev.number) == 2:
-      rev.next_changed = changed and "+%i -%i" % (deled, added)
-    else:
-      rev.changed = changed and "+%i -%i" % (added, deled)
-
-class StreamText:
-  d_command = re.compile('^d(\d+)\\s(\\d+)')
-  a_command = re.compile('^a(\d+)\\s(\\d+)')
-
-  def __init__(self, text):
-    self.text = string.split(text, "\n")
-
-  def command(self, cmd):
-    adjust = 0
-    add_lines_remaining = 0
-    diffs = string.split(cmd, "\n")
-    if diffs[-1] == "":
-      del diffs[-1]
-    if len(diffs) == 0:
-      return
-    if diffs[0] == "":
-      del diffs[0]
-    for command in diffs:
-      if add_lines_remaining > 0:
-        # Insertion lines from a prior "a" command
-        self.text.insert(start_line + adjust, command)
-        add_lines_remaining = add_lines_remaining - 1
-        adjust = adjust + 1
-        continue
-      dmatch = self.d_command.match(command)
-      amatch = self.a_command.match(command)
-      if dmatch:
-        # "d" - Delete command
-        start_line = string.atoi(dmatch.group(1))
-        count      = string.atoi(dmatch.group(2))
-        begin = start_line + adjust - 1
-        del self.text[begin:begin + count]
-        adjust = adjust - count
-      elif amatch:
-        # "a" - Add command
-        start_line = string.atoi(amatch.group(1))
-        count      = string.atoi(amatch.group(2))
-        add_lines_remaining = count
-      else:
-        raise RuntimeError, 'Error parsing diff commands'
-
-def secondnextdot(s, start):
-  # find the position the second dot after the start index.
-  return string.find(s, '.', string.find(s, '.', start) + 1)
-
-
-class COSink(MatchingSink):
-  def __init__(self, rev):
-    MatchingSink.__init__(self, rev)
-
-  def set_head_revision(self, revision):
-    self.head = Revision(revision)
-    self.last = None
-    self.sstext = None
-
-  def admin_completed(self):
-    MatchingSink.admin_completed(self)
-    if self.find_tag is None:
-      raise vclib.InvalidRevision(self.find)
-
-  def set_revision_info(self, revision, log, text):
-    tag = self.find_tag
-    rev = Revision(revision)
+import os.path
 
-    if rev.number == tag.number:
-      self.log = log
 
-    depth = len(rev.number)
+def canonicalize_rootpath(rootpath):
+  return os.path.normpath(rootpath)
 
-    if rev.number == self.head.number:
-      assert self.sstext is None
-      self.sstext = StreamText(text)
-    elif (depth == 2 and tag.number and rev.number >= tag.number[:depth]):
-      assert len(self.last.number) == 2
-      assert rev.number < self.last.number
-      self.sstext.command(text)
-    elif (depth > 2 and rev.number[:depth-1] == tag.number[:depth-1] and
-          (rev.number <= tag.number or len(tag.number) == depth-1)):
-      assert len(rev.number) - len(self.last.number) in (0, 2)
-      assert rev.number > self.last.number
-      self.sstext.command(text)
-    else:
-      rev = None
 
-    if rev:
-      #print "tag =", tag.number, "rev =", rev.number, "<br>"
-      self.last = rev
+def expand_root_parent(parent_path):
+  # Each subdirectory of PARENT_PATH that contains a child
+  # "CVSROOT/config" is added the set of returned roots.  Or, if the
+  # PARENT_PATH itself contains a child "CVSROOT/config", then all its
+  # subdirectories are returned as roots.
+  roots = {}
+  subpaths = os.listdir(parent_path)
+  cvsroot = os.path.exists(os.path.join(parent_path, "CVSROOT", "config"))
+  for rootname in subpaths:
+    rootpath = os.path.join(parent_path, rootname)
+    if cvsroot \
+       or (os.path.exists(os.path.join(rootpath, "CVSROOT", "config"))):
+      roots[rootname] = canonicalize_rootpath(rootpath)
+  return roots
+
+
+def CVSRepository(name, rootpath, authorizer, utilities, use_rcsparse):
+  rootpath = canonicalize_rootpath(rootpath)
+  if use_rcsparse:
+    import ccvs
+    return ccvs.CCVSRepository(name, rootpath, authorizer, utilities)
+  else:
+    import bincvs
+    return bincvs.BinCVSRepository(name, rootpath, authorizer, utilities)

Added: branches/VIEWCVS_DIST/lib/vclib/ccvs/bincvs.py
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/bincvs.py	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,1211 @@
+# -*-python-*-
+#
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
+#
+# By using this file, you agree to the terms and conditions set forth in
+# the LICENSE.html file which can be found at the top level of the ViewVC
+# distribution or at http://viewvc.org/license-1.html.
+#
+# For more information, visit http://viewvc.org/
+#
+# -----------------------------------------------------------------------
+
+"Version Control lib driver for locally accessible cvs-repositories."
+
+import vclib
+import vcauth
+import os
+import os.path
+import sys
+import stat
+import string
+import re
+import time
+
+# ViewVC libs
+import compat
+import popen
+
+class BaseCVSRepository(vclib.Repository):
+  def __init__(self, name, rootpath, authorizer, utilities):
+    if not os.path.isdir(rootpath):
+      raise vclib.ReposNotFound(name) 
+   
+    self.name = name
+    self.rootpath = rootpath
+    self.auth = authorizer
+    self.utilities = utilities
+
+    # See if this repository is even viewable, authz-wise.
+    if not vclib.check_root_access(self):
+      raise vclib.ReposNotFound(name)
+
+  def rootname(self):
+    return self.name
+
+  def rootpath(self):
+    return self.rootpath
+
+  def roottype(self):
+    return vclib.CVS
+
+  def authorizer(self):
+    return self.auth
+  
+  def itemtype(self, path_parts, rev):
+    basepath = self._getpath(path_parts)
+    kind = None
+    if os.path.isdir(basepath):
+      kind = vclib.DIR
+    elif os.path.isfile(basepath + ',v'):
+      kind = vclib.FILE
+    else:
+      atticpath = self._getpath(self._atticpath(path_parts))
+      if os.path.isfile(atticpath + ',v'):
+        kind = vclib.FILE
+    if not kind:
+      raise vclib.ItemNotFound(path_parts)
+    if not vclib.check_path_access(self, path_parts, kind, rev):
+      raise vclib.ItemNotFound(path_parts)
+    return kind
+
+  def itemprops(self, path_parts, rev):
+    self.itemtype(path_parts, rev)  # does auth-check
+    return {}  # CVS doesn't support properties
+  
+  def listdir(self, path_parts, rev, options):
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory."
+                        % (string.join(path_parts, "/")))
+    
+    # Only RCS files (*,v) and subdirs are returned.
+    data = [ ]
+    full_name = self._getpath(path_parts)
+    for file in os.listdir(full_name):
+      name = None
+      kind, errors = _check_path(os.path.join(full_name, file))
+      if kind == vclib.FILE:
+        if file[-2:] == ',v':
+          name = file[:-2]
+      elif kind == vclib.DIR:
+        if file != 'Attic' and file != 'CVS': # CVS directory is for fileattr
+          name = file
+      else:
+        name = file
+      if not name:
+        continue
+      if vclib.check_path_access(self, path_parts + [name], kind, rev):
+        data.append(CVSDirEntry(name, kind, errors, 0))
+
+    full_name = os.path.join(full_name, 'Attic')
+    if os.path.isdir(full_name):
+      for file in os.listdir(full_name):
+        name = None
+        kind, errors = _check_path(os.path.join(full_name, file))
+        if kind == vclib.FILE:
+          if file[-2:] == ',v':
+            name = file[:-2]
+        elif kind != vclib.DIR:
+          name = file
+        if not name:
+          continue
+        if vclib.check_path_access(self, path_parts + [name], kind, rev):
+          data.append(CVSDirEntry(name, kind, errors, 1))
+
+    return data
+    
+  def _getpath(self, path_parts):
+    return apply(os.path.join, (self.rootpath,) + tuple(path_parts))
+
+  def _atticpath(self, path_parts):
+    return path_parts[:-1] + ['Attic'] + path_parts[-1:]
+
+  def rcsfile(self, path_parts, root=0, v=1):
+    "Return path to RCS file"
+
+    ret_parts = path_parts
+    ret_file = self._getpath(ret_parts)
+    if not os.path.isfile(ret_file + ',v'):
+      ret_parts = self._atticpath(path_parts)
+      ret_file = self._getpath(ret_parts)
+      if not os.path.isfile(ret_file + ',v'):
+        raise vclib.ItemNotFound(path_parts)
+    if root:
+      ret = ret_file
+    else:
+      ret = string.join(ret_parts, "/")
+    if v:
+      ret = ret + ",v"
+    return ret
+
+  def isexecutable(self, path_parts, rev):
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+    rcsfile = self.rcsfile(path_parts, 1)
+    return os.access(rcsfile, os.X_OK)
+
+
+class BinCVSRepository(BaseCVSRepository):
+  def _get_tip_revision(self, rcs_file, rev=None):
+    """Get the (basically) youngest revision (filtered by REV)."""
+    args = rcs_file,
+    fp = self.rcs_popen('rlog', args, 'rt', 0)
+    filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
+    revs = []
+    while not eof:
+      revision, eof = _parse_log_entry(fp)
+      if revision:
+        revs.append(revision)
+    revs = _file_log(revs, tags, lockinfo, default_branch, rev)
+    if revs:
+      return revs[-1]
+    return None
+
+  def openfile(self, path_parts, rev):
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+    if not rev or rev == 'HEAD' or rev == 'MAIN':
+      rev_flag = '-p'
+    else:
+      rev_flag = '-p' + rev
+    full_name = self.rcsfile(path_parts, root=1, v=0)
+
+    used_rlog = 0
+    tip_rev = None  # used only if we have to fallback to using rlog
+
+    fp = self.rcs_popen('co', (rev_flag, full_name), 'rb') 
+    try:
+      filename, revision = _parse_co_header(fp)
+    except COMissingRevision:
+      # We got a "revision X.Y.Z absent" error from co.  This could be
+      # because we were asked to find a tip of a branch, which co
+      # doesn't seem to handle.  So we do rlog-gy stuff to figure out
+      # which revision the tip of the branch currently maps to.
+      ### TODO: Only do this when 'rev' is a branch symbol name?
+      if not used_rlog:
+        tip_rev = self._get_tip_revision(full_name + ',v', rev)
+        used_rlog = 1
+      if not tip_rev:
+        raise vclib.Error("Unable to find valid revision")
+      fp = self.rcs_popen('co', ('-p' + tip_rev.string, full_name), 'rb') 
+      filename, revision = _parse_co_header(fp)
+      
+    if filename is None:
+      # CVSNT's co exits without any output if a dead revision is requested.
+      # Bug at http://www.cvsnt.org/cgi-bin/bugzilla/show_bug.cgi?id=190
+      # As a workaround, we invoke rlog to find the first non-dead revision
+      # that precedes it and check out that revision instead.  Of course, 
+      # if we've already invoked rlog above, we just reuse its output.
+      if not used_rlog:
+        tip_rev = self._get_tip_revision(full_name + ',v', rev)
+        used_rlog = 1
+      if not (tip_rev and tip_rev.undead):
+        raise vclib.Error(
+          'Could not find non-dead revision preceding "%s"' % rev)
+      fp = self.rcs_popen('co', ('-p' + tip_rev.undead.string,
+                                 full_name), 'rb') 
+      filename, revision = _parse_co_header(fp)
+
+    if filename is None:
+      raise vclib.Error('Missing output from co (filename = "%s")' % full_name)
+
+    if not _paths_eq(filename, full_name):
+      raise vclib.Error(
+        'The filename from co ("%s") did not match (expected "%s")'
+        % (filename, full_name))
+
+    return fp, revision
+
+  def dirlogs(self, path_parts, rev, entries, options):
+    """see vclib.Repository.dirlogs docstring
+
+    rev can be a tag name or None. if set only information from revisions
+    matching the tag will be retrieved
+
+    Option values recognized by this implementation:
+
+      cvs_subdirs
+        boolean. true to fetch logs of the most recently modified file in each
+        subdirectory
+
+    Option values returned by this implementation:
+
+      cvs_tags, cvs_branches
+        lists of tag and branch names encountered in the directory
+    """
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory."
+                        % (string.join(path_parts, "/")))
+
+    subdirs = options.get('cvs_subdirs', 0)
+    entries_to_fetch = []
+    for entry in entries:
+      if vclib.check_path_access(self, path_parts + [entry.name], None, rev):
+        entries_to_fetch.append(entry)
+    alltags = _get_logs(self, path_parts, entries_to_fetch, rev, subdirs)
+    branches = options['cvs_branches'] = []
+    tags = options['cvs_tags'] = []
+    for name, rev in alltags.items():
+      if Tag(None, rev).is_branch:
+        branches.append(name)
+      else:
+        tags.append(name)
+
+  def itemlog(self, path_parts, rev, sortby, first, limit, options):
+    """see vclib.Repository.itemlog docstring
+
+    rev parameter can be a revision number, a branch number, a tag name,
+    or None. If None, will return information about all revisions, otherwise,
+    will only return information about the specified revision or branch.
+
+    Option values recognized by this implementation:
+
+      cvs_pass_rev
+        boolean, default false. set to true to pass rev parameter as -r
+        argument to rlog, this is more efficient but causes less
+        information to be returned
+
+    Option values returned by this implementation:
+
+      cvs_tags
+        dictionary of Tag objects for all tags encountered
+    """
+
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+    
+    # Invoke rlog
+    rcsfile = self.rcsfile(path_parts, 1)
+    if rev and options.get('cvs_pass_rev', 0):
+      args = '-r' + rev, rcsfile
+    else:
+      args = rcsfile,
+
+    fp = self.rcs_popen('rlog', args, 'rt', 0)
+    filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
+
+    # Retrieve revision objects
+    revs = []
+    while not eof:
+      revision, eof = _parse_log_entry(fp)
+      if revision:
+        revs.append(revision)
+
+    filtered_revs = _file_log(revs, tags, lockinfo, default_branch, rev)
+
+    options['cvs_tags'] = tags
+    if sortby == vclib.SORTBY_DATE:
+      filtered_revs.sort(_logsort_date_cmp)
+    elif sortby == vclib.SORTBY_REV:
+      filtered_revs.sort(_logsort_rev_cmp)
+
+    if len(filtered_revs) < first:
+      return []
+    if limit:
+      return filtered_revs[first:first+limit]
+    return filtered_revs
+
+  def rcs_popen(self, rcs_cmd, rcs_args, mode, capture_err=1):
+    if self.utilities.cvsnt:
+      cmd = self.utilities.cvsnt
+      args = ['rcsfile', rcs_cmd]
+      args.extend(list(rcs_args))
+    else:
+      cmd = os.path.join(self.utilities.rcs_dir, rcs_cmd)
+      args = rcs_args
+    return popen.popen(cmd, args, mode, capture_err)
+
+  def annotate(self, path_parts, rev=None):
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+                        
+    from vclib.ccvs import blame
+    source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
+    return source, source.revision
+
+  def revinfo(self, rev):
+    raise vclib.UnsupportedFeature
+  
+  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
+    """see vclib.Repository.rawdiff docstring
+
+    Option values recognized by this implementation:
+
+      ignore_keyword_subst - boolean, ignore keyword substitution
+    """
+    if self.itemtype(path_parts1, rev1) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts1, "/")))
+    if self.itemtype(path_parts2, rev2) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts2, "/")))
+    
+    args = vclib._diff_args(type, options)
+    if options.get('ignore_keyword_subst', 0):
+      args.append('-kk')
+
+    rcsfile = self.rcsfile(path_parts1, 1)
+    if path_parts1 != path_parts2:
+      raise NotImplementedError, "cannot diff across paths in cvs"
+    args.extend(['-r' + rev1, '-r' + rev2, rcsfile])
+    
+    fp = self.rcs_popen('rcsdiff', args, 'rt')
+
+    # Eat up the non-GNU-diff-y headers.
+    while 1:
+      line = fp.readline()
+      if not line or line[0:5] == 'diff ':
+        break
+    return fp
+  
+
+class CVSDirEntry(vclib.DirEntry):
+  def __init__(self, name, kind, errors, in_attic, absent=0):
+    vclib.DirEntry.__init__(self, name, kind, errors)
+    self.in_attic = in_attic
+    self.absent = absent # meaning, no revisions found on requested tag
+
+class Revision(vclib.Revision):
+  def __init__(self, revstr, date=None, author=None, dead=None,
+               changed=None, log=None):
+    vclib.Revision.__init__(self, _revision_tuple(revstr), revstr,
+                            date, author, changed, log, None, None)
+    self.dead = dead
+
+class Tag:
+  def __init__(self, name, revstr):
+    self.name = name
+    self.number = _tag_tuple(revstr)
+    self.is_branch = len(self.number) % 2 == 1 or not self.number
+
+
+# ======================================================================
+# Functions for dealing with Revision and Tag objects
+
+def _logsort_date_cmp(rev1, rev2):
+  # sort on date; secondary on revision number
+  return -cmp(rev1.date, rev2.date) or -cmp(rev1.number, rev2.number)
+
+def _logsort_rev_cmp(rev1, rev2):
+  # sort highest revision first
+  return -cmp(rev1.number, rev2.number)
+
+def _match_revs_tags(revlist, taglist):
+  """Match up a list of Revision objects with a list of Tag objects
+
+  Sets the following properties on each Revision in revlist:
+    "tags"
+      list of non-branch tags which refer to this revision
+      example: if revision is 1.2.3.4, tags is a list of all 1.2.3.4 tags
+
+    "branches"
+      list of branch tags which refer to this revision's branch
+      example: if revision is 1.2.3.4, branches is a list of all 1.2.3 tags
+
+    "branch_points"
+      list of branch tags which branch off of this revision
+      example: if revision is 1.2, it's a list of tags like 1.2.3 and 1.2.4
+
+    "prev"
+      reference to the previous revision, possibly None
+      example: if revision is 1.2.3.4, prev is 1.2.3.3
+
+    "next"
+      reference to next revision, possibly None
+      example: if revision is 1.2.3.4, next is 1.2.3.5
+
+    "parent"
+      reference to revision this one branches off of, possibly None
+      example: if revision is 1.2.3.4, parent is 1.2
+
+    "undead"
+      If the revision is dead, then this is a reference to the first 
+      previous revision which isn't dead, otherwise it's a reference
+      to itself. If all the previous revisions are dead it's None. 
+
+    "branch_number"
+      tuple representing branch number or empty tuple if on trunk
+      example: if revision is 1.2.3.4, branch_number is (1, 2, 3)
+
+  Each tag in taglist gets these properties set:
+    "co_rev"
+      reference to revision that would be retrieved if tag were checked out
+
+    "branch_rev"
+      reference to revision branched off of, only set for branch tags
+      example: if tag is 1.2.3, branch_rev points to 1.2 revision
+
+    "aliases"
+      list of tags that have the same number
+  """
+
+  # map of branch numbers to lists of corresponding branch Tags
+  branch_dict = {}
+
+  # map of revision numbers to lists of non-branch Tags
+  tag_dict = {}
+
+  # map of revision numbers to lists of branch Tags
+  branch_point_dict = {}
+
+  # toss tags into "branch_dict", "tag_dict", and "branch_point_dict"
+  # set "aliases" property and default "co_rev" and "branch_rev" values
+  for tag in taglist:
+    tag.co_rev = None
+    if tag.is_branch:
+      tag.branch_rev = None
+      _dict_list_add(branch_point_dict, tag.number[:-1], tag)
+      tag.aliases = _dict_list_add(branch_dict, tag.number, tag)
+    else:
+      tag.aliases = _dict_list_add(tag_dict, tag.number, tag)
+
+  # sort the revisions so the loop below can work properly
+  revlist.sort()
+
+  # array of the most recently encountered revision objects indexed by depth
+  history = []
+
+  # loop through revisions, setting properties and storing state in "history"
+  for rev in revlist:
+    depth = len(rev.number) / 2 - 1
+
+    # set "prev" and "next" properties
+    rev.prev = rev.next = None
+    if depth < len(history):
+      prev = history[depth]
+      if prev and (depth == 0 or rev.number[:-1] == prev.number[:-1]):
+        rev.prev = prev
+        prev.next = rev
+
+    # set "parent"
+    rev.parent = None
+    if depth and depth <= len(history):
+      parent = history[depth-1]
+      if parent and parent.number == rev.number[:-2]:
+        rev.parent = history[depth-1]
+
+    # set "undead"
+    if rev.dead:
+      prev = rev.prev or rev.parent
+      rev.undead = prev and prev.undead
+    else:
+      rev.undead = rev
+
+    # set "tags" and "branch_points"
+    rev.tags = tag_dict.get(rev.number, [])
+    rev.branch_points = branch_point_dict.get(rev.number, [])
+
+    # set "branches" and "branch_number"
+    if rev.prev:
+      rev.branches = rev.prev.branches
+      rev.branch_number = rev.prev.branch_number
+    else:
+      rev.branch_number = depth and rev.number[:-1] or ()
+      try:
+        rev.branches = branch_dict[rev.branch_number]
+      except KeyError:
+        rev.branches = []
+
+    # set "co_rev" and "branch_rev"
+    for tag in rev.tags:
+      tag.co_rev = rev
+
+    for tag in rev.branch_points:
+      tag.co_rev = rev
+      tag.branch_rev = rev
+
+    # This loop only needs to be run for revisions at the heads of branches,
+    # but for the simplicity's sake, it actually runs for every revision on
+    # a branch. The later revisions overwrite values set by the earlier ones.
+    for branch in rev.branches:
+      branch.co_rev = rev
+
+    # end of outer loop, store most recent revision in "history" array
+    while len(history) <= depth:
+      history.append(None)
+    history[depth] = rev
+
+def _add_tag(tag_name, revision):
+  """Create a new tag object and associate it with a revision"""
+  if revision:
+    tag = Tag(tag_name, revision.string)
+    tag.aliases = revision.tags
+    revision.tags.append(tag)
+  else:
+    tag = Tag(tag_name, None)
+    tag.aliases = []
+  tag.co_rev = revision
+  tag.is_branch = 0
+  return tag
+
+def _remove_tag(tag):
+  """Remove a tag's associations"""
+  tag.aliases.remove(tag)
+  if tag.is_branch and tag.branch_rev:
+    tag.branch_rev.branch_points.remove(tag)
+
+def _revision_tuple(revision_string):
+  """convert a revision number into a tuple of integers"""
+  t = tuple(map(int, string.split(revision_string, '.')))
+  if len(t) % 2 == 0:
+    return t
+  raise ValueError
+
+def _tag_tuple(revision_string):
+  """convert a revision number or branch number into a tuple of integers"""
+  if revision_string:
+    t = map(int, string.split(revision_string, '.'))
+    l = len(t)
+    if l == 1:
+      return ()
+    if l > 2 and t[-2] == 0 and l % 2 == 0:
+      del t[-2]
+    return tuple(t)
+  return ()
+
+def _dict_list_add(dict, idx, elem):
+  try:
+    list = dict[idx]
+  except KeyError:
+    list = dict[idx] = [elem]
+  else:
+    list.append(elem)
+  return list
+
+
+# ======================================================================
+# Functions for parsing output from RCS utilities
+
+
+class COMalformedOutput(vclib.Error):
+  pass
+class COMissingRevision(vclib.Error):
+  pass
+
+### suck up other warnings in _re_co_warning?
+_re_co_filename = re.compile(r'^(.*),v\s+-->\s+(?:(?:standard output)|(?:stdout))\s*\n?$')
+_re_co_warning = re.compile(r'^.*co: .*,v: warning: Unknown phrases like .*\n$')
+_re_co_missing_rev = re.compile(r'^.*co: .*,v: revision.*absent\n$')
+_re_co_side_branches = re.compile(r'^.*co: .*,v: no side branches present for [\d\.]+\n$')
+_re_co_revision = re.compile(r'^revision\s+([\d\.]+)\s*\n$')
+
+def _parse_co_header(fp):
+  """Parse RCS co header.
+
+  fp is a file (pipe) opened for reading the co standard error stream.
+
+  Returns: (filename, revision) or (None, None) if output is empty
+  """
+
+  # header from co:
+  #
+  #/home/cvsroot/mod_dav/dav_shared_stub.c,v  -->  standard output
+  #revision 1.1
+  #
+  # Sometimes, the following line might occur at line 2:
+  #co: INSTALL,v: warning: Unknown phrases like `permissions ...;' are present.
+
+  # parse the output header
+  filename = None
+
+  # look for a filename in the first line (if there is a first line).
+  line = fp.readline()
+  if not line:
+    return None, None
+  match = _re_co_filename.match(line)
+  if not match:
+    raise COMalformedOutput, "Unable to find filename in co output stream"
+  filename = match.group(1)
+
+  # look through subsequent lines for a revision.  we might encounter
+  # some ignorable or problematic lines along the way.
+  while 1:
+    line = fp.readline()
+    if not line:
+      break
+    # look for a revision.
+    match = _re_co_revision.match(line)
+    if match:
+      return filename, match.group(1)
+    elif _re_co_missing_rev.match(line) or _re_co_side_branches.match(line):
+      raise COMissingRevision, "Got missing revision error from co output stream"
+    elif _re_co_warning.match(line):
+      pass
+    else:
+      break
+    
+  raise COMalformedOutput, "Unable to find revision in co output stream"
+
+# if your rlog doesn't use 77 '=' characters, then this must change
+LOG_END_MARKER = '=' * 77 + '\n'
+ENTRY_END_MARKER = '-' * 28 + '\n'
+
+_EOF_FILE = 'end of file entries'       # no more entries for this RCS file
+_EOF_LOG = 'end of log'                 # hit the true EOF on the pipe
+_EOF_ERROR = 'error message found'      # rlog issued an error
+
+# rlog error messages look like
+#
+#   rlog: filename/goes/here,v: error message
+#   rlog: filename/goes/here,v:123: error message
+#
+# so we should be able to match them with a regex like
+#
+#   ^rlog\: (.*)(?:\:\d+)?\: (.*)$
+#
+# But for some reason the windows version of rlog omits the "rlog: " prefix
+# for the first error message when the standard error stream has been 
+# redirected to a file or pipe. (the prefix is present in subsequent errors
+# and when rlog is run from the console). So the expression below is more
+# complicated
+_re_log_error = re.compile(r'^(?:rlog\: )*(.*,v)(?:\:\d+)?\: (.*)$')
+
+# CVSNT error messages look like:
+# cvs rcsfile: `C:/path/to/file,v' does not appear to be a valid rcs file
+# cvs [rcsfile aborted]: C:/path/to/file,v: No such file or directory
+# cvs [rcsfile aborted]: cannot open C:/path/to/file,v: Permission denied
+_re_cvsnt_error = re.compile(r'^(?:cvs rcsfile\: |cvs \[rcsfile aborted\]: )'
+                             r'(?:\`(.*,v)\' |cannot open (.*,v)\: |(.*,v)\: |)'
+                             r'(.*)$')
+
+def _parse_log_header(fp):
+  """Parse and RCS/CVS log header.
+
+  fp is a file (pipe) opened for reading the log information.
+
+  On entry, fp should point to the start of a log entry.
+  On exit, fp will have consumed the separator line between the header and
+  the first revision log.
+
+  If there is no revision information (e.g. the "-h" switch was passed to
+  rlog), then fp will consumed the file separator line on exit.
+
+  Returns: filename, default branch, tag dictionary, lock dictionary,
+  rlog error message, and eof flag
+  """
+  
+  filename = head = branch = msg = ""
+  taginfo = { }   # tag name => number
+  lockinfo = { }  # revision => locker
+  state = 0       # 0 = base, 1 = parsing symbols, 2 = parsing locks
+  eof = None
+
+  while 1:
+    line = fp.readline()
+    if not line:
+      # the true end-of-file
+      eof = _EOF_LOG
+      break
+
+    if state == 1:
+      if line[0] == '\t':
+        [ tag, rev ] = map(string.strip, string.split(line, ':'))
+        taginfo[tag] = rev
+      else:
+        # oops. this line isn't tag info. stop parsing tags.
+        state = 0
+
+    if state == 2:
+      if line[0] == '\t':
+        [ locker, rev ] = map(string.strip, string.split(line, ':'))
+        lockinfo[rev] = locker
+      else:
+        # oops. this line isn't lock info. stop parsing tags.
+        state = 0
+      
+    if state == 0:
+      if line[:9] == 'RCS file:':
+        filename = line[10:-1]
+      elif line[:5] == 'head:':
+        head = line[6:-1]
+      elif line[:7] == 'branch:':
+        branch = line[8:-1]
+      elif line[:6] == 'locks:':
+        # start parsing the lock information
+        state = 2
+      elif line[:14] == 'symbolic names':
+        # start parsing the tag information
+        state = 1
+      elif line == ENTRY_END_MARKER:
+        # end of the headers
+        break
+      elif line == LOG_END_MARKER:
+        # end of this file's log information
+        eof = _EOF_FILE
+        break
+      else:
+        error = _re_cvsnt_error.match(line)
+        if error:
+          p1, p2, p3, msg = error.groups()
+          filename = p1 or p2 or p3
+          if not filename:
+            raise vclib.Error("Could not get filename from CVSNT error:\n%s"
+                               % line)
+          eof = _EOF_ERROR
+          break
+
+        error = _re_log_error.match(line)
+        if error:
+          filename, msg = error.groups()
+          if msg[:30] == 'warning: Unknown phrases like ':
+            # don't worry about this warning. it can happen with some RCS
+            # files that have unknown fields in them (e.g. "permissions 644;"
+            continue
+          eof = _EOF_ERROR
+          break
+
+  return filename, branch, taginfo, lockinfo, msg, eof
+
+_re_log_info = re.compile(r'^date:\s+([^;]+);'
+                          r'\s+author:\s+([^;]+);'
+                          r'\s+state:\s+([^;]+);'
+                          r'(\s+lines:\s+([0-9\s+-]+);?)?'
+                          r'(\s+commitid:\s+([a-zA-Z0-9]+))?\n$')
+### _re_rev should be updated to extract the "locked" flag
+_re_rev = re.compile(r'^revision\s+([0-9.]+).*')
+def _parse_log_entry(fp):
+  """Parse a single log entry.
+
+  On entry, fp should point to the first line of the entry (the "revision"
+  line).
+  On exit, fp will have consumed the log separator line (dashes) or the
+  end-of-file marker (equals).
+
+  Returns: Revision object and eof flag (see _EOF_*)
+  """
+  rev = None
+  line = fp.readline()
+  if not line:
+    return None, _EOF_LOG
+  if line == LOG_END_MARKER:
+    # Needed because some versions of RCS precede LOG_END_MARKER
+    # with ENTRY_END_MARKER
+    return None, _EOF_FILE
+  if line[:8] == 'revision':
+    match = _re_rev.match(line)
+    if not match:
+      return None, _EOF_LOG
+    rev = match.group(1)
+
+    line = fp.readline()
+    if not line:
+      return None, _EOF_LOG
+    match = _re_log_info.match(line)
+
+  eof = None
+  log = ''
+  while 1:
+    line = fp.readline()
+    if not line:
+      # true end-of-file
+      eof = _EOF_LOG
+      break
+    if line[:9] == 'branches:':
+      continue
+    if line == ENTRY_END_MARKER:
+      break
+    if line == LOG_END_MARKER:
+      # end of this file's log information
+      eof = _EOF_FILE
+      break
+
+    log = log + line
+
+  if not rev or not match:
+    # there was a parsing error
+    return None, eof
+
+  # parse out a time tuple for the local time
+  tm = compat.cvs_strptime(match.group(1))
+
+  # rlog seems to assume that two-digit years are 1900-based (so, "04"
+  # comes out as "1904", not "2004").
+  EPOCH = 1970
+  if tm[0] < EPOCH:
+    tm = list(tm)
+    if (tm[0] - 1900) < 70:
+      tm[0] = tm[0] + 100
+    if tm[0] < EPOCH:
+      raise ValueError, 'invalid year'
+  date = compat.timegm(tm)
+
+  return Revision(rev, date,
+                  # author, state, lines changed
+                  match.group(2), match.group(3) == "dead", match.group(5),
+                  log), eof
+
+def _skip_file(fp):
+  "Skip the rest of a file's log information."
+  while 1:
+    line = fp.readline()
+    if not line:
+      break
+    if line == LOG_END_MARKER:
+      break
+
+def _paths_eq(path1, path2):
+  "See if two path strings are the same"
+  # This function is neccessary because CVSNT (since version 2.0.29)
+  # converts paths passed as arguments to use upper case drive
+  # letter and forward slashes
+  return os.path.normcase(path1) == os.path.normcase(path2)
+
+
+# ======================================================================
+# Functions for interpreting and manipulating log information
+
+def _file_log(revs, taginfo, lockinfo, cur_branch, filter):
+  """Augment list of Revisions and a dictionary of Tags"""
+
+  # Add artificial ViewVC tag MAIN. If the file has a default branch, then
+  # MAIN acts like a branch tag pointing to that branch. Otherwise MAIN acts
+  # like a branch tag that points to the trunk. (Note: A default branch is
+  # just a branch number specified in an RCS file that tells CVS and RCS
+  # what branch to use for checkout and update operations by default, when
+  # there's no revision argument or sticky branch to override it. Default
+  # branches get set by "cvs import" to point to newly created vendor
+  # branches. Sometimes they are also set manually with "cvs admin -b")
+  taginfo['MAIN'] = cur_branch
+
+  # Create tag objects
+  for name, num in taginfo.items():
+    taginfo[name] = Tag(name, num)
+  tags = taginfo.values()
+
+  # Set view_tag to a Tag object in order to filter results. We can filter by
+  # revision number or branch number
+  if filter:
+    try:
+      view_tag = Tag(None, filter)
+    except ValueError:
+      view_tag = None
+    else:
+      tags.append(view_tag)  
+
+  # Match up tags and revisions
+  _match_revs_tags(revs, tags)
+
+  # Match up lockinfo and revision
+  for rev in revs:
+    rev.lockinfo = lockinfo.get(rev.string)
+      
+  # Add artificial ViewVC tag HEAD, which acts like a non-branch tag pointing
+  # at the latest revision on the MAIN branch. The HEAD revision doesn't have
+  # anything to do with the "head" revision number specified in the RCS file
+  # and in rlog output. HEAD refers to the revision that the CVS and RCS co
+  # commands will check out by default, whereas the "head" field just refers
+  # to the highest revision on the trunk.  
+  taginfo['HEAD'] = _add_tag('HEAD', taginfo['MAIN'].co_rev)
+
+  # Determine what revisions to return
+  if filter:
+    # If view_tag isn't set, it means filter is not a valid revision or
+    # branch number. Check taginfo to see if filter is set to a valid tag
+    # name. If so, filter by that tag, otherwise raise an error.
+    if not view_tag:
+      try:
+        view_tag = taginfo[filter]
+      except KeyError:
+        raise vclib.Error('Invalid tag or revision number "%s"' % filter)
+    filtered_revs = [ ]
+
+    # only include revisions on the tag branch or it's parent branches
+    if view_tag.is_branch:
+      branch = view_tag.number
+    elif len(view_tag.number) > 2:
+      branch = view_tag.number[:-1]
+    else:
+      branch = ()
+
+    # for a normal tag, include all tag revision and all preceding revisions.
+    # for a branch tag, include revisions on branch, branch point revision,
+    # and all preceding revisions
+    for rev in revs:
+      if (rev.number == view_tag.number
+          or rev.branch_number == view_tag.number
+          or (rev.number < view_tag.number
+              and rev.branch_number == branch[:len(rev.branch_number)])):
+        filtered_revs.append(rev)
+
+    # get rid of the view_tag if it was only created for filtering
+    if view_tag.name is None:
+      _remove_tag(view_tag)
+  else:
+    filtered_revs = revs
+  
+  return filtered_revs
+
+def _get_logs(repos, dir_path_parts, entries, view_tag, get_dirs):
+  alltags = {           # all the tags seen in the files of this dir
+    'MAIN' : '',
+    'HEAD' : '1.1'
+    }
+
+  entries_idx = 0
+  entries_len = len(entries)
+  max_args = 100
+
+  while 1:
+    chunk = []
+
+    while len(chunk) < max_args and entries_idx < entries_len:
+      entry = entries[entries_idx]
+      path = _log_path(entry, repos._getpath(dir_path_parts), get_dirs)
+      if path:
+        entry.path = path
+        entry.idx = entries_idx
+        chunk.append(entry)
+
+      # set properties even if we don't retrieve logs
+      entry.rev = entry.date = entry.author = None
+      entry.dead = entry.log = entry.lockinfo = None
+
+      entries_idx = entries_idx + 1
+
+    if not chunk:
+      return alltags
+
+    args = []
+    if not view_tag:
+      # NOTE: can't pass tag on command line since a tag may contain "-"
+      #       we'll search the output for the appropriate revision
+      # fetch the latest revision on the default branch
+      args.append('-r')
+    args.extend(map(lambda x: x.path, chunk))
+    rlog = repos.rcs_popen('rlog', args, 'rt')
+
+    # consume each file found in the resulting log
+    chunk_idx = 0
+    while chunk_idx < len(chunk):
+      file = chunk[chunk_idx]
+      filename, default_branch, taginfo, lockinfo, msg, eof \
+        = _parse_log_header(rlog)
+
+      if eof == _EOF_LOG:
+        # the rlog output ended early. this can happen on errors that rlog 
+        # thinks are so serious that it stops parsing the current file and
+        # refuses to parse any of the files that come after it. one of the
+        # errors that triggers this obnoxious behavior looks like:
+        #
+        # rlog: c:\cvsroot\dir\file,v:8: unknown expand mode u
+        # rlog aborted
+
+        # if current file has errors, restart on the next one
+        if file.errors:
+          chunk_idx = chunk_idx + 1
+          if chunk_idx < len(chunk):
+            entries_idx = chunk[chunk_idx].idx
+          break
+
+        # otherwise just error out
+        raise vclib.Error('Rlog output ended early. Expected RCS file "%s"'
+                          % file.path)
+
+      # if rlog filename doesn't match current file and we already have an
+      # error message about this file, move on to the next file
+      while not (file and _paths_eq(file.path, filename)):
+        if file and file.errors:
+          chunk_idx = chunk_idx + 1
+          file = chunk_idx < len(chunk) and chunk[chunk_idx] or None
+          continue
+
+        raise vclib.Error('Error parsing rlog output. Expected RCS file %s'
+                          ', found %s' % (file and file.path, filename))
+
+      # if we get an rlog error message, restart loop without advancing
+      # chunk_idx cause there might be more output about the same file
+      if eof == _EOF_ERROR:
+        file.errors.append("rlog error: %s" % msg)
+        continue
+
+      if view_tag == 'MAIN' or view_tag == 'HEAD':
+        tag = Tag(None, default_branch)
+      elif taginfo.has_key(view_tag):
+        tag = Tag(None, taginfo[view_tag])
+      elif view_tag:
+        # the tag wasn't found, so skip this file
+        _skip_file(rlog)
+        eof = 1
+      else:
+        tag = None
+
+      # we don't care about the specific values -- just the keys and whether
+      # the values point to branches or revisions. this the fastest way to 
+      # merge the set of keys and keep values that allow us to make the 
+      # distinction between branch tags and normal tags
+      alltags.update(taginfo)
+
+      # read all of the log entries until we find the revision we want
+      wanted_entry = None
+      while not eof:
+
+        # fetch one of the log entries
+        entry, eof = _parse_log_entry(rlog)
+
+        if not entry:
+          # parsing error
+          break
+
+        # A perfect match is a revision on the branch being viewed or
+        # a revision having the tag being viewed or any revision
+        # when nothing is being viewed. When there's a perfect match
+        # we set the wanted_entry value and break out of the loop.
+        # An imperfect match is a revision at the branch point of a
+        # branch being viewed. When there's an imperfect match we
+        # also set the wanted_entry value but keep looping in case
+        # something better comes along.
+        perfect = not tag or entry.number == tag.number or       \
+                  (len(entry.number) == 2 and not tag.number) or \
+                  entry.number[:-1] == tag.number
+        if perfect or entry.number == tag.number[:-1]:
+          wanted_entry = entry
+          if perfect:
+            break
+
+      if wanted_entry:
+        file.rev = wanted_entry.string
+        file.date = wanted_entry.date
+        file.author = wanted_entry.author
+        file.dead = file.kind == vclib.FILE and wanted_entry.dead
+        file.absent = 0
+        file.log = wanted_entry.log
+        file.lockinfo = lockinfo.get(file.rev)
+        # suppress rlog errors if we find a usable revision in the end
+        del file.errors[:]
+      elif file.kind == vclib.FILE:
+        file.dead = 0
+        #file.errors.append("No revisions exist on %s" % (view_tag or "MAIN"))
+        file.absent = 1
+        
+      # done with this file now, skip the rest of this file's revisions
+      if not eof:
+        _skip_file(rlog)
+
+      # end of while loop, advance index
+      chunk_idx = chunk_idx + 1
+
+    rlog.close()
+
+def _log_path(entry, dirpath, getdirs):
+  path = name = None
+  if not entry.errors:
+    if entry.kind == vclib.FILE:
+      path = entry.in_attic and 'Attic' or ''
+      name = entry.name
+    elif entry.kind == vclib.DIR and getdirs:
+      entry.newest_file = _newest_file(os.path.join(dirpath, entry.name))
+      if entry.newest_file:
+        path = entry.name
+        name = entry.newest_file
+
+  if name:
+    return os.path.join(dirpath, path, name + ',v')
+  return None
+
+
+# ======================================================================
+# Functions for dealing with the filesystem
+
+if sys.platform == "win32":
+  def _check_path(path):
+    kind = None
+    errors = []
+
+    if os.path.isfile(path):
+      kind = vclib.FILE
+    elif os.path.isdir(path):
+      kind = vclib.DIR
+    else:
+      errors.append("error: path is not a file or directory")
+
+    if not os.access(path, os.R_OK):
+      errors.append("error: path is not accessible")
+
+    return kind, errors
+
+else:
+  _uid = os.getuid()
+  _gid = os.getgid()
+
+  def _check_path(pathname):
+    try:
+      info = os.stat(pathname)
+    except os.error, e:
+      return None, ["stat error: %s" % e]
+
+    kind = None
+    errors = []
+
+    mode = info[stat.ST_MODE]
+    isdir = stat.S_ISDIR(mode)
+    isreg = stat.S_ISREG(mode)
+    if isreg or isdir:
+      #
+      # Quick version of access() where we use existing stat() data.
+      #
+      # This might not be perfect -- the OS may return slightly different
+      # results for some bizarre reason. However, we make a good show of
+      # "can I read this file/dir?" by checking the various perm bits.
+      #
+      # NOTE: if the UID matches, then we must match the user bits -- we
+      # cannot defer to group or other bits. Similarly, if the GID matches,
+      # then we must have read access in the group bits.
+      #
+      # If the UID or GID don't match, we need to check the
+      # results of an os.access() call, in case the web server process
+      # is in the group that owns the directory.
+      #
+      if isdir:
+        mask = stat.S_IROTH | stat.S_IXOTH
+      else:
+        mask = stat.S_IROTH
+
+      if info[stat.ST_UID] == _uid:
+        if ((mode >> 6) & mask) != mask:
+          errors.append("error: path is not accessible to user %i" % _uid)
+      elif info[stat.ST_GID] == _gid:
+        if ((mode >> 3) & mask) != mask:
+          errors.append("error: path is not accessible to group %i" % _gid)
+      # If the process running the web server is a member of
+      # the group stat.ST_GID access may be granted.
+      # so the fall back to os.access is needed to figure this out.
+      elif (mode & mask) != mask:
+        if not os.access(pathname, isdir and (os.R_OK | os.X_OK) or os.R_OK):
+          errors.append("error: path is not accessible")
+
+      if isdir:
+        kind = vclib.DIR
+      else:
+        kind = vclib.FILE
+
+    else:
+      errors.append("error: path is not a file or directory")
+
+    return kind, errors
+
+def _newest_file(dirpath):
+  """Find the last modified RCS file in a directory"""
+  newest_file = None
+  newest_time = 0
+
+  ### FIXME:  This sucker is leaking unauthorized paths! ###
+  
+  for subfile in os.listdir(dirpath):
+    ### filter CVS locks? stale NFS handles?
+    if subfile[-2:] != ',v':
+      continue
+    path = os.path.join(dirpath, subfile)
+    info = os.stat(path)
+    if not stat.S_ISREG(info[stat.ST_MODE]):
+      continue
+    if info[stat.ST_MTIME] > newest_time:
+      kind, verboten = _check_path(path)
+      if kind == vclib.FILE and not verboten:
+        newest_file = subfile[:-2]
+        newest_time = info[stat.ST_MTIME]
+
+  return newest_file

Modified: branches/VIEWCVS_DIST/lib/vclib/ccvs/blame.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/ccvs/blame.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/blame.py	Mon Nov  3 09:44:02 2008
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 # Copyright (C) 2000 Curt Hagenlocher <curt hagenlocher org>
 #
 # By using this file, you agree to the terms and conditions set forth in

Added: branches/VIEWCVS_DIST/lib/vclib/ccvs/ccvs.py
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/ccvs.py	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,398 @@
+# -*-python-*-
+#
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
+#
+# By using this file, you agree to the terms and conditions set forth in
+# the LICENSE.html file which can be found at the top level of the ViewVC
+# distribution or at http://viewvc.org/license-1.html.
+#
+# For more information, visit http://viewvc.org/
+#
+# -----------------------------------------------------------------------
+
+import os
+import string
+import re
+import cStringIO
+import tempfile
+
+import vclib
+import rcsparse
+import blame
+
+### The functionality shared with bincvs should probably be moved to a
+### separate module
+from bincvs import BaseCVSRepository, Revision, Tag, _file_log, _log_path, _logsort_date_cmp, _logsort_rev_cmp
+
+class CCVSRepository(BaseCVSRepository):
+  def dirlogs(self, path_parts, rev, entries, options):
+    """see vclib.Repository.dirlogs docstring
+
+    rev can be a tag name or None. if set only information from revisions
+    matching the tag will be retrieved
+
+    Option values recognized by this implementation:
+
+      cvs_subdirs
+        boolean. true to fetch logs of the most recently modified file in each
+        subdirectory
+
+    Option values returned by this implementation:
+
+      cvs_tags, cvs_branches
+        lists of tag and branch names encountered in the directory
+    """
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory."
+                        % (string.join(path_parts, "/")))
+    entries_to_fetch = []
+    for entry in entries:
+      if vclib.check_path_access(self, path_parts + [entry.name], None, rev):
+        entries_to_fetch.append(entry)
+
+    subdirs = options.get('cvs_subdirs', 0)
+
+    dirpath = self._getpath(path_parts)
+    alltags = {           # all the tags seen in the files of this dir
+      'MAIN' : '',
+      'HEAD' : '1.1'
+    }
+
+    for entry in entries_to_fetch:
+      entry.rev = entry.date = entry.author = None
+      entry.dead = entry.absent = entry.log = entry.lockinfo = None
+      path = _log_path(entry, dirpath, subdirs)
+      if path:
+        entry.path = path
+        try:
+          rcsparse.parse(open(path, 'rb'), InfoSink(entry, rev, alltags))
+        except IOError, e:
+          entry.errors.append("rcsparse error: %s" % e)
+        except RuntimeError, e:
+          entry.errors.append("rcsparse error: %s" % e)
+        except rcsparse.RCSStopParser:
+          pass
+
+    branches = options['cvs_branches'] = []
+    tags = options['cvs_tags'] = []
+    for name, rev in alltags.items():
+      if Tag(None, rev).is_branch:
+        branches.append(name)
+      else:
+        tags.append(name)
+
+  def itemlog(self, path_parts, rev, sortby, first, limit, options):
+    """see vclib.Repository.itemlog docstring
+
+    rev parameter can be a revision number, a branch number, a tag name,
+    or None. If None, will return information about all revisions, otherwise,
+    will only return information about the specified revision or branch.
+
+    Option values returned by this implementation:
+
+      cvs_tags
+        dictionary of Tag objects for all tags encountered
+    """
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+
+    path = self.rcsfile(path_parts, 1)
+    sink = TreeSink()
+    rcsparse.parse(open(path, 'rb'), sink)
+    filtered_revs = _file_log(sink.revs.values(), sink.tags, sink.lockinfo,
+                              sink.default_branch, rev)
+    for rev in filtered_revs:
+      if rev.prev and len(rev.number) == 2:
+        rev.changed = rev.prev.next_changed
+    options['cvs_tags'] = sink.tags
+
+    if sortby == vclib.SORTBY_DATE:
+      filtered_revs.sort(_logsort_date_cmp)
+    elif sortby == vclib.SORTBY_REV:
+      filtered_revs.sort(_logsort_rev_cmp)
+      
+    if len(filtered_revs) < first:
+      return []
+    if limit:
+      return filtered_revs[first:first+limit]
+    return filtered_revs
+
+  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
+    if self.itemtype(path_parts1, rev1) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts1, "/")))
+    if self.itemtype(path_parts2, rev2) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts2, "/")))
+    
+    temp1 = tempfile.mktemp()
+    open(temp1, 'wb').write(self.openfile(path_parts1, rev1)[0].getvalue())
+    temp2 = tempfile.mktemp()
+    open(temp2, 'wb').write(self.openfile(path_parts2, rev2)[0].getvalue())
+
+    r1 = self.itemlog(path_parts1, rev1, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
+    r2 = self.itemlog(path_parts2, rev2, vclib.SORTBY_DEFAULT, 0, 0, {})[-1]
+
+    info1 = (self.rcsfile(path_parts1, root=1, v=0), r1.date, r1.string)
+    info2 = (self.rcsfile(path_parts2, root=1, v=0), r2.date, r2.string)
+
+    diff_args = vclib._diff_args(type, options)
+
+    return vclib._diff_fp(temp1, temp2, info1, info2,
+                          self.utilities.diff or 'diff', diff_args)
+
+  def annotate(self, path_parts, rev=None):
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+    source = blame.BlameSource(self.rcsfile(path_parts, 1), rev)
+    return source, source.revision
+
+  def revinfo(self, rev):
+    raise vclib.UnsupportedFeature
+
+  def openfile(self, path_parts, rev=None):
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file."
+                        % (string.join(path_parts, "/")))
+    path = self.rcsfile(path_parts, 1)
+    sink = COSink(rev)
+    rcsparse.parse(open(path, 'rb'), sink)
+    revision = sink.last and sink.last.string
+    return cStringIO.StringIO(string.join(sink.sstext.text, "\n")), revision
+
+class MatchingSink(rcsparse.Sink):
+  """Superclass for sinks that search for revisions based on tag or number"""
+
+  def __init__(self, find):
+    """Initialize with tag name or revision number string to match against"""
+    if not find or find == 'MAIN' or find == 'HEAD':
+      self.find = None
+    else:
+      self.find = find
+
+    self.find_tag = None
+
+  def set_principal_branch(self, branch_number):
+    if self.find is None:
+      self.find_tag = Tag(None, branch_number)
+
+  def define_tag(self, name, revision):
+    if name == self.find:
+      self.find_tag = Tag(None, revision)
+
+  def admin_completed(self):
+    if self.find_tag is None:
+      if self.find is None:
+        self.find_tag = Tag(None, '')
+      else:
+        try:
+          self.find_tag = Tag(None, self.find)
+        except ValueError:
+          pass
+
+class InfoSink(MatchingSink):
+  def __init__(self, entry, tag, alltags):
+    MatchingSink.__init__(self, tag)
+    self.entry = entry
+    self.alltags = alltags
+    self.matching_rev = None
+    self.perfect_match = 0
+    self.lockinfo = { }
+
+  def define_tag(self, name, revision):
+    MatchingSink.define_tag(self, name, revision)
+    self.alltags[name] = revision
+
+  def admin_completed(self):
+    MatchingSink.admin_completed(self)
+    if self.find_tag is None:
+      # tag we're looking for doesn't exist
+      if self.entry.kind == vclib.FILE:
+        self.entry.absent = 1
+      raise rcsparse.RCSStopParser
+
+  def set_locker(self, rev, locker):
+    self.lockinfo[rev] = locker
+    
+  def define_revision(self, revision, date, author, state, branches, next):
+    if self.perfect_match:
+      return
+
+    tag = self.find_tag
+    rev = Revision(revision, date, author, state == "dead")
+    rev.lockinfo = self.lockinfo.get(revision)
+    
+    # perfect match if revision number matches tag number or if revision is on
+    # trunk and tag points to trunk. imperfect match if tag refers to a branch
+    # and this revision is the highest revision so far found on that branch
+    perfect = ((rev.number == tag.number) or
+               (not tag.number and len(rev.number) == 2))
+    if perfect or (tag.is_branch and tag.number == rev.number[:-1] and
+                   (not self.matching_rev or
+                    rev.number > self.matching_rev.number)):
+      self.matching_rev = rev
+      self.perfect_match = perfect
+
+  def set_revision_info(self, revision, log, text):
+    if self.matching_rev:
+      if revision == self.matching_rev.string:
+        self.entry.rev = self.matching_rev.string
+        self.entry.date = self.matching_rev.date
+        self.entry.author = self.matching_rev.author
+        self.entry.dead = self.matching_rev.dead
+        self.entry.lockinfo = self.matching_rev.lockinfo
+        self.entry.absent = 0
+        self.entry.log = log
+        raise rcsparse.RCSStopParser
+    else:
+      raise rcsparse.RCSStopParser
+
+class TreeSink(rcsparse.Sink):
+  d_command = re.compile('^d(\d+)\\s(\\d+)')
+  a_command = re.compile('^a(\d+)\\s(\\d+)')
+
+  def __init__(self):
+    self.revs = { }
+    self.tags = { }
+    self.head = None
+    self.default_branch = None
+    self.lockinfo = { }
+    
+  def set_head_revision(self, revision):
+    self.head = revision
+
+  def set_principal_branch(self, branch_number):
+    self.default_branch = branch_number
+
+  def set_locker(self, rev, locker):
+    self.lockinfo[rev] = locker
+    
+  def define_tag(self, name, revision):
+    # check !tags.has_key(tag_name)
+    self.tags[name] = revision
+
+  def define_revision(self, revision, date, author, state, branches, next):
+    # check !revs.has_key(revision)
+    self.revs[revision] = Revision(revision, date, author, state == "dead")
+
+  def set_revision_info(self, revision, log, text):
+    # check revs.has_key(revision)
+    rev = self.revs[revision]
+    rev.log = log
+
+    changed = None
+    added = 0
+    deled = 0
+    if self.head != revision:
+      changed = 1
+      lines = string.split(text, '\n')
+      idx = 0
+      while idx < len(lines):
+        command = lines[idx]
+        dmatch = self.d_command.match(command)
+        idx = idx + 1
+        if dmatch:
+          deled = deled + string.atoi(dmatch.group(2))
+        else:
+          amatch = self.a_command.match(command)
+          if amatch:
+            count = string.atoi(amatch.group(2))
+            added = added + count
+            idx = idx + count
+          elif command:
+            raise "error while parsing deltatext: %s" % command
+
+    if len(rev.number) == 2:
+      rev.next_changed = changed and "+%i -%i" % (deled, added)
+    else:
+      rev.changed = changed and "+%i -%i" % (added, deled)
+
+class StreamText:
+  d_command = re.compile('^d(\d+)\\s(\\d+)')
+  a_command = re.compile('^a(\d+)\\s(\\d+)')
+
+  def __init__(self, text):
+    self.text = string.split(text, "\n")
+
+  def command(self, cmd):
+    adjust = 0
+    add_lines_remaining = 0
+    diffs = string.split(cmd, "\n")
+    if diffs[-1] == "":
+      del diffs[-1]
+    if len(diffs) == 0:
+      return
+    if diffs[0] == "":
+      del diffs[0]
+    for command in diffs:
+      if add_lines_remaining > 0:
+        # Insertion lines from a prior "a" command
+        self.text.insert(start_line + adjust, command)
+        add_lines_remaining = add_lines_remaining - 1
+        adjust = adjust + 1
+        continue
+      dmatch = self.d_command.match(command)
+      amatch = self.a_command.match(command)
+      if dmatch:
+        # "d" - Delete command
+        start_line = string.atoi(dmatch.group(1))
+        count      = string.atoi(dmatch.group(2))
+        begin = start_line + adjust - 1
+        del self.text[begin:begin + count]
+        adjust = adjust - count
+      elif amatch:
+        # "a" - Add command
+        start_line = string.atoi(amatch.group(1))
+        count      = string.atoi(amatch.group(2))
+        add_lines_remaining = count
+      else:
+        raise RuntimeError, 'Error parsing diff commands'
+
+def secondnextdot(s, start):
+  # find the position the second dot after the start index.
+  return string.find(s, '.', string.find(s, '.', start) + 1)
+
+
+class COSink(MatchingSink):
+  def __init__(self, rev):
+    MatchingSink.__init__(self, rev)
+
+  def set_head_revision(self, revision):
+    self.head = Revision(revision)
+    self.last = None
+    self.sstext = None
+
+  def admin_completed(self):
+    MatchingSink.admin_completed(self)
+    if self.find_tag is None:
+      raise vclib.InvalidRevision(self.find)
+
+  def set_revision_info(self, revision, log, text):
+    tag = self.find_tag
+    rev = Revision(revision)
+
+    if rev.number == tag.number:
+      self.log = log
+
+    depth = len(rev.number)
+
+    if rev.number == self.head.number:
+      assert self.sstext is None
+      self.sstext = StreamText(text)
+    elif (depth == 2 and tag.number and rev.number >= tag.number[:depth]):
+      assert len(self.last.number) == 2
+      assert rev.number < self.last.number
+      self.sstext.command(text)
+    elif (depth > 2 and rev.number[:depth-1] == tag.number[:depth-1] and
+          (rev.number <= tag.number or len(tag.number) == depth-1)):
+      assert len(rev.number) - len(self.last.number) in (0, 2)
+      assert rev.number > self.last.number
+      self.sstext.command(text)
+    else:
+      rev = None
+
+    if rev:
+      #print "tag =", tag.number, "rev =", rev.number, "<br>"
+      self.last = rev

Modified: branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/common.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/common.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/common.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC

Modified: branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/default.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/default.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/default.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC

Modified: branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/texttools.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/texttools.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/ccvs/rcsparse/texttools.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC

Modified: branches/VIEWCVS_DIST/lib/vclib/svn/__init__.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/vclib/svn/__init__.py	(original)
+++ branches/VIEWCVS_DIST/lib/vclib/svn/__init__.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -10,657 +10,46 @@
 #
 # -----------------------------------------------------------------------
 
-"Version Control lib driver for locally accessible Subversion repositories"
+"Version Control lib driver for Subversion repositories"
 
-import vclib
 import os
 import os.path
-import string
-import cStringIO
-import signal
-import time
-import tempfile
-import popen
 import re
-from svn import fs, repos, core, client, delta
 
+_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
 
-### Require Subversion 1.3.1 or better.
-if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
-  raise Exception, "Version requirement not met (needs 1.3.1 or better)"
-
-  
-def _allow_all(root, path, pool):
-  """Generic authz_read_func that permits access to all paths"""
-  return 1
-
-
-def _fs_path_join(base, relative):
-  # Subversion filesystem paths are '/'-delimited, regardless of OS.
-  joined_path = base + '/' + relative
-  parts = filter(None, string.split(joined_path, '/'))
-  return string.join(parts, '/')
-
-
-def _cleanup_path(path):
-  """Return a cleaned-up Subversion filesystem path"""
-  return string.join(filter(None, string.split(path, '/')), '/')
-  
-
-def _compare_paths(path1, path2):
-  path1_len = len (path1);
-  path2_len = len (path2);
-  min_len = min(path1_len, path2_len)
-  i = 0
-
-  # Are the paths exactly the same?
-  if path1 == path2:
-    return 0
-  
-  # Skip past common prefix
-  while (i < min_len) and (path1[i] == path2[i]):
-    i = i + 1
-
-  # Children of paths are greater than their parents, but less than
-  # greater siblings of their parents
-  char1 = '\0'
-  char2 = '\0'
-  if (i < path1_len):
-    char1 = path1[i]
-  if (i < path2_len):
-    char2 = path2[i]
-    
-  if (char1 == '/') and (i == path2_len):
-    return 1
-  if (char2 == '/') and (i == path1_len):
-    return -1
-  if (i < path1_len) and (char1 == '/'):
-    return -1
-  if (i < path2_len) and (char2 == '/'):
-    return 1
-
-  # Common prefix was skipped above, next character is compared to
-  # determine order
-  return cmp(char1, char2)
-
-
-def _rev2optrev(rev):
-  assert type(rev) is int
-  rt = core.svn_opt_revision_t()
-  rt.kind = core.svn_opt_revision_number
-  rt.value.number = rev
-  return rt
-
-
-def _rootpath2url(rootpath, path):
-  rootpath = os.path.abspath(rootpath)
-  if rootpath and rootpath[0] != '/':
-    rootpath = '/' + rootpath
-  if os.sep != '/':
-    rootpath = string.replace(rootpath, os.sep, '/')
-  return 'file://' + string.join([rootpath, path], "/")
-
-
-def _datestr_to_date(datestr):
+def canonicalize_rootpath(rootpath):
   try:
-    return core.svn_time_from_cstring(datestr) / 1000000
+    import svn.core
+    return svn.core.svn_path_canonicalize(rootpath)
   except:
-    return None
-
-  
-def _fs_rev_props(fsptr, rev):
-  author = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_AUTHOR)
-  msg = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_LOG)
-  date = fs.revision_prop(fsptr, rev, core.SVN_PROP_REVISION_DATE)
-  return date, author, msg
-
-
-def date_from_rev(svnrepos, rev):
-  if (rev < 0) or (rev > svnrepos.youngest):
-    raise vclib.InvalidRevision(rev)
-  return _datestr_to_date(fs.revision_prop(svnrepos.fs_ptr, rev,
-                                           core.SVN_PROP_REVISION_DATE))
-
-
-def get_location(svnrepos, path, rev, old_rev):
-  try:
-    results = repos.svn_repos_trace_node_locations(svnrepos.fs_ptr, path,
-                                                   rev, [old_rev], _allow_all)
-  except core.SubversionException, e:
-    if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
-      raise vclib.ItemNotFound(path)
-    raise
-
-  try:
-    old_path = results[old_rev]
-  except KeyError:
-    raise vclib.ItemNotFound(path)
-
-  return _cleanup_path(old_path)
-
+    if re.search(_re_url, rootpath):
+      return rootpath[-1] == '/' and rootpath[:-1] or rootpath
+    return os.path.normpath(rootpath)
 
-def last_rev(svnrepos, path, peg_revision, limit_revision=None):
-  """Given PATH, known to exist in PEG_REVISION, find the youngest
-  revision older than, or equal to, LIMIT_REVISION in which path
-  exists.  Return that revision, and the path at which PATH exists in
-  that revision."""
-  
-  # Here's the plan, man.  In the trivial case (where PEG_REVISION is
-  # the same as LIMIT_REVISION), this is a no-brainer.  If
-  # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
-  # history tracing code to find the right location.  If, however,
-  # LIMIT_REVISION is younger than PEG_REVISION, we suffer from
-  # Subversion's lack of forward history searching.  Our workaround,
-  # ugly as it may be, involves a binary search through the revisions
-  # between PEG_REVISION and LIMIT_REVISION to find our last live
-  # revision.
-  peg_revision = svnrepos._getrev(peg_revision)
-  limit_revision = svnrepos._getrev(limit_revision)
-  try:
-    if peg_revision == limit_revision:
-      return peg_revision, path
-    elif peg_revision > limit_revision:
-      fsroot = svnrepos._getroot(peg_revision)
-      history = fs.node_history(fsroot, path)
-      while history:
-        path, peg_revision = fs.history_location(history)
-        if peg_revision <= limit_revision:
-          return max(peg_revision, limit_revision), _cleanup_path(path)
-        history = fs.history_prev(history, 1)
-      return peg_revision, _cleanup_path(path)
-    else:
-      orig_id = fs.node_id(svnrepos._getroot(peg_revision), path)
-      while peg_revision != limit_revision:
-        mid = (peg_revision + 1 + limit_revision) / 2
-        try:
-          mid_id = fs.node_id(svnrepos._getroot(mid), path)
-        except core.SubversionException, e:
-          if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
-            cmp = -1
-          else:
-            raise
-        else:
-          ### Not quite right.  Need a comparison function that only returns
-          ### true when the two nodes are the same copy, not just related.
-          cmp = fs.compare_ids(orig_id, mid_id)
-
-        if cmp in (0, 1):
-          peg_revision = mid
-        else:
-          limit_revision = mid - 1
 
-      return peg_revision, path
-  finally:
+def expand_root_parent(parent_path):
+  roots = {}
+  if re.search(_re_url, parent_path):
     pass
-
-
-def created_rev(svnrepos, full_name, rev):
-  return fs.node_created_rev(svnrepos._getroot(rev), full_name)
-
-
-class Revision(vclib.Revision):
-  "Hold state for each revision's log entry."
-  def __init__(self, rev, date, author, msg, size,
-               filename, copy_path, copy_rev):
-    vclib.Revision.__init__(self, rev, str(rev), date, author, None, msg, size)
-    self.filename = filename
-    self.copy_path = copy_path
-    self.copy_rev = copy_rev
-
-
-class NodeHistory:
-  def __init__(self, fs_ptr, show_all_logs):
-    self.histories = {}
-    self.fs_ptr = fs_ptr
-    self.show_all_logs = show_all_logs
-    
-  def add_history(self, path, revision, pool):
-    # If filtering, only add the path and revision to the histories
-    # list if they were actually changed in this revision (where
-    # change means the path itself was changed, or one of its parents
-    # was copied).  This is useful for omitting bubble-up directory
-    # changes.
-    if not self.show_all_logs:
-      rev_root = fs.revision_root(self.fs_ptr, revision)
-      changed_paths = fs.paths_changed(rev_root)
-      paths = changed_paths.keys()
-      if path not in paths:
-        # Look for a copied parent
-        test_path = path
-        found = 0
-        while 1:
-          off = string.rfind(test_path, '/')
-          if off < 0:
-            break
-          test_path = test_path[0:off]
-          if test_path in paths:
-            copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path)
-            if copyfrom_rev >= 0 and copyfrom_path:
-              found = 1
-              break
-        if not found:
-          return
-    self.histories[revision] = _cleanup_path(path)
-    
-  
-def _get_history(svnrepos, full_name, rev, options={}):
-  fsroot = svnrepos._getroot(rev)
-  show_all_logs = options.get('svn_show_all_dir_logs', 0)
-  if not show_all_logs:
-    # See if the path is a file or directory.
-    kind = fs.check_path(fsroot, full_name)
-    if kind is core.svn_node_file:
-      show_all_logs = 1
-      
-  # Instantiate a NodeHistory collector object.
-  history = NodeHistory(svnrepos.fs_ptr, show_all_logs)
-
-  # Do we want to cross copy history?
-  cross_copies = options.get('svn_cross_copies', 0)
-
-  # Get the history items for PATH.
-  repos.svn_repos_history(svnrepos.fs_ptr, full_name, history.add_history,
-                          1, rev, cross_copies)
-  return history.histories
-
-
-def _log_helper(svnrepos, rev, path):
-  rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
-
-  # Was this path rev the target of a copy?
-  copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
-
-  # Assemble our LogEntry
-  datestr, author, msg = _fs_rev_props(svnrepos.fs_ptr, rev)
-  date = _datestr_to_date(datestr)
-  if fs.is_file(rev_root, path):
-    size = fs.file_length(rev_root, path)
   else:
-    size = None
-  entry = Revision(rev, date, author, msg, size, path,
-                   copyfrom_path and _cleanup_path(copyfrom_path),
-                   copyfrom_rev)
-  return entry
-  
-
-def _fetch_log(svnrepos, full_name, which_rev, options):
-  revs = []
-
-  if options.get('svn_latest_log', 0):
-    rev = _log_helper(svnrepos, which_rev, full_name)
-    if rev:
-      revs.append(rev)
+    # Any subdirectories of PARENT_PATH which themselves have a child
+    # "format" are returned as roots.
+    subpaths = os.listdir(parent_path)
+    for rootname in subpaths:
+      rootpath = os.path.join(parent_path, rootname)
+      if os.path.exists(os.path.join(rootpath, "format")):
+        roots[rootname] = canonicalize_rootpath(rootpath)
+  return roots
+
+
+def SubversionRepository(name, rootpath, authorizer, utilities, config_dir):
+  rootpath = canonicalize_rootpath(rootpath)
+  if re.search(_re_url, rootpath):
+    import svn_ra
+    return svn_ra.RemoteSubversionRepository(name, rootpath, authorizer,
+                                             utilities, config_dir)
   else:
-    history_set = _get_history(svnrepos, full_name, which_rev, options)
-    history_revs = history_set.keys()
-    history_revs.sort()
-    history_revs.reverse()
-    for history_rev in history_revs:
-      rev = _log_helper(svnrepos, history_rev, history_set[history_rev])
-      if rev:
-        revs.append(rev)
-  return revs
-
-def _get_last_history_rev(fsroot, path):
-  history = fs.node_history(fsroot, path)
-  history = fs.history_prev(history, 0)
-  history_path, history_rev = fs.history_location(history)
-  return history_rev
-  
-def get_youngest_revision(svnrepos):
-  return svnrepos.youngest
-
-def temp_checkout(svnrepos, path, rev):
-  """Check out file revision to temporary file"""
-  temp = tempfile.mktemp()
-  fp = open(temp, 'wb')
-  try:
-    root = svnrepos._getroot(rev)
-    stream = fs.file_contents(root, path)
-    try:
-      while 1:
-        chunk = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE)
-        if not chunk:
-          break
-        fp.write(chunk)
-    finally:
-      core.svn_stream_close(stream)
-  finally:
-    fp.close()
-  return temp
-
-class FileContentsPipe:
-  def __init__(self, root, path):
-    self._stream = fs.file_contents(root, path)
-    self._eof = 0
-
-  def read(self, len=None):
-    chunk = None
-    if not self._eof:
-      if len is None:
-        buffer = cStringIO.StringIO()
-        try:
-          while 1:
-            hunk = core.svn_stream_read(self._stream, 8192)
-            if not hunk:
-              break
-            buffer.write(hunk)
-          chunk = buffer.getvalue()
-        finally:
-          buffer.close()
-
-      else:
-        chunk = core.svn_stream_read(self._stream, len)   
-    if not chunk:
-      self._eof = 1
-    return chunk
-  
-  def readline(self):
-    chunk = None
-    if not self._eof:
-      chunk, self._eof = core.svn_stream_readline(self._stream, '\n')
-      if not self._eof:
-        chunk = chunk + '\n'
-    if not chunk:
-      self._eof = 1
-    return chunk
-
-  def readlines(self):
-    lines = []
-    while True:
-      line = self.readline()
-      if not line:
-        break
-      lines.append(line)
-    return lines
-
-  def close(self):
-    return core.svn_stream_close(self._stream)
-
-  def eof(self):
-    return self._eof
-
-
-class BlameSource:
-  def __init__(self, local_url, rev, first_rev):
-    self.idx = -1
-    self.first_rev = first_rev
-    self.blame_data = []
-
-    ctx = client.ctx_t()
-    core.svn_config_ensure(None)
-    ctx.config = core.svn_config_get_config(None)
-    ctx.auth_baton = core.svn_auth_open([])
-    try:
-      client.blame2(local_url, _rev2optrev(rev), _rev2optrev(1),
-                    _rev2optrev(rev), self._blame_cb, ctx)
-    except vclib.svn.core.SubversionException, e:
-      if e.apr_err == vclib.svn.core.SVN_ERR_CLIENT_IS_BINARY_FILE:
-        raise vclib.NonTextualFileContents
-      raise
-
-  def _blame_cb(self, line_no, rev, author, date, text, pool):
-    prev_rev = None
-    if rev > self.first_rev:
-      prev_rev = rev - 1
-    self.blame_data.append(vclib.Annotation(text, line_no, rev,
-                                            prev_rev, author, None))
-
-  def __getitem__(self, idx):
-    if idx != self.idx + 1:
-      raise BlameSequencingError()
-    self.idx = idx
-    return self.blame_data[idx]
-
-
-class BlameSequencingError(Exception):
-  pass
-
-
-class SVNChangedPath(vclib.ChangedPath):
-  """Wrapper around vclib.ChangedPath which handles path splitting."""
-  
-  def __init__(self, path, rev, pathtype, base_path, base_rev,
-               action, copied, text_changed, props_changed):
-    path_parts = filter(None, string.split(path or '', '/'))
-    base_path_parts = filter(None, string.split(base_path or '', '/'))
-    vclib.ChangedPath.__init__(self, path_parts, rev, pathtype,
-                               base_path_parts, base_rev, action,
-                               copied, text_changed, props_changed)
-
-  
-class SubversionRepository(vclib.Repository):
-  def __init__(self, name, rootpath, utilities):
-    if not os.path.isdir(rootpath):
-      raise vclib.ReposNotFound(name)
-
-    # Initialize some stuff.
-    self.rootpath = rootpath
-    self.name = name
-    self.svn_client_path = utilities.svn or 'svn'
-    self.diff_cmd = utilities.diff or 'diff'
-
-    # Register a handler for SIGTERM so we can have a chance to
-    # cleanup.  If ViewVC takes too long to start generating CGI
-    # output, Apache will grow impatient and SIGTERM it.  While we
-    # don't mind getting told to bail, we want to gracefully close the
-    # repository before we bail.
-    def _sigterm_handler(signum, frame, self=self):
-      self._close()
-      sys.exit(-1)
-    try:
-      signal.signal(signal.SIGTERM, _sigterm_handler)
-    except ValueError:
-      # This is probably "ValueError: signal only works in main
-      # thread", which will get thrown by the likes of mod_python
-      # when trying to install a signal handler from a thread that
-      # isn't the main one.  We'll just not care.
-      pass
-
-    # Open the repository and init some other variables.
-    self.repos = repos.svn_repos_open(rootpath)
-    self.fs_ptr = repos.svn_repos_fs(self.repos)
-    self.youngest = fs.youngest_rev(self.fs_ptr)
-    self._fsroots = {}
-
-  def rootname(self):
-    return self.name
-
-  def rootpath(self):
-    return self.rootpath
-
-  def roottype(self):
-    return vclib.SVN
-
-  def itemtype(self, path_parts, rev):
-    rev = self._getrev(rev)
-    basepath = self._getpath(path_parts)
-    kind = fs.check_path(self._getroot(rev), basepath)
-    if kind == core.svn_node_dir:
-      return vclib.DIR
-    if kind == core.svn_node_file:
-      return vclib.FILE
-    raise vclib.ItemNotFound(path_parts)
-
-  def openfile(self, path_parts, rev):
-    path = self._getpath(path_parts)
-    rev = self._getrev(rev)
-    fsroot = self._getroot(rev)
-    revision = str(_get_last_history_rev(fsroot, path))
-    fp = FileContentsPipe(fsroot, path)
-    return fp, revision
-
-  def listdir(self, path_parts, rev, options):
-    basepath = self._getpath(path_parts)
-    if self.itemtype(path_parts, rev) != vclib.DIR:
-      raise vclib.Error("Path '%s' is not a directory." % basepath)
-
-    rev = self._getrev(rev)
-    fsroot = self._getroot(rev)
-    dirents = fs.dir_entries(fsroot, basepath)
-    entries = [ ]
-    for entry in dirents.values():
-      if entry.kind == core.svn_node_dir:
-        kind = vclib.DIR
-      elif entry.kind == core.svn_node_file:
-        kind = vclib.FILE              
-      entries.append(vclib.DirEntry(entry.name, kind))
-    return entries
-
-  def dirlogs(self, path_parts, rev, entries, options):
-    fsroot = self._getroot(self._getrev(rev))
-    for entry in entries:
-      path = self._getpath(path_parts + [entry.name])
-      rev = _get_last_history_rev(fsroot, path)
-      datestr, author, msg = _fs_rev_props(self.fs_ptr, rev)
-      date = _datestr_to_date(datestr)
-      entry.rev = str(rev)
-      entry.date = date
-      entry.author = author
-      entry.log = msg
-      if entry.kind == vclib.FILE:
-        entry.size = fs.file_length(fsroot, path)
-
-  def itemlog(self, path_parts, rev, options):
-    """see vclib.Repository.itemlog docstring
-
-    Option values recognized by this implementation
-
-      svn_show_all_dir_logs
-        boolean, default false. if set for a directory path, will include
-        revisions where files underneath the directory have changed
-
-      svn_cross_copies
-        boolean, default false. if set for a path created by a copy, will
-        include revisions from before the copy
-
-      svn_latest_log
-        boolean, default false. if set will return only newest single log
-        entry
-    """
-    path = self._getpath(path_parts)
-    rev = self._getrev(rev)
-
-    revs = _fetch_log(self, path, rev, options)
-    revs.sort()
-    prev = None
-    for rev in revs:
-      rev.prev = prev
-      prev = rev
-    return revs
-
-  def annotate(self, path_parts, rev):
-    path = self._getpath(path_parts)
-    rev = self._getrev(rev)
-    fsroot = self._getroot(rev)
-
-    history_set = _get_history(self, path, rev, {'svn_cross_copies': 1})
-    history_revs = history_set.keys()
-    history_revs.sort()
-    revision = history_revs[-1]
-    first_rev = history_revs[0]
-    source = BlameSource(_rootpath2url(self.rootpath, path), rev, first_rev)
-    return source, revision
-
-  def revinfo(self, rev):
-    fsroot = self._getroot(rev)
-
-    # Get the changes for the revision
-    editor = repos.ChangeCollector(self.fs_ptr, fsroot)
-    e_ptr, e_baton = delta.make_editor(editor)
-    repos.svn_repos_replay(fsroot, e_ptr, e_baton)
-    changes = editor.get_changes()
-    changedpaths = {}
-    
-    # Now get the revision property info.  Would use
-    # editor.get_root_props(), but something is broken there...
-    datestr, author, msg = _fs_rev_props(self.fs_ptr, rev)
-
-    # Copy the Subversion changes into a new hash, converting them into
-    # ChangedPath objects.
-    for path in changes.keys():
-      change = changes[path]
-      if change.path:
-        change.path = _cleanup_path(change.path)
-      if change.base_path:
-        change.base_path = _cleanup_path(change.base_path)
-      is_copy = 0
-      if not hasattr(change, 'action'): # new to subversion 1.4.0
-        action = vclib.MODIFIED
-        if not change.path:
-          action = vclib.DELETED
-        elif change.added:
-          action = vclib.ADDED
-          replace_check_path = path
-          if change.base_path and change.base_rev:
-            replace_check_path = change.base_path
-          if changedpaths.has_key(replace_check_path) \
-             and changedpaths[replace_check_path].action == vclib.DELETED:
-            action = vclib.REPLACED
-      else:
-        if change.action == repos.CHANGE_ACTION_ADD:
-          action = vclib.ADDED
-        elif change.action == repos.CHANGE_ACTION_DELETE:
-          action = vclib.DELETED
-        elif change.action == repos.CHANGE_ACTION_REPLACE:
-          action = vclib.REPLACED
-        else:
-          action = vclib.MODIFIED
-      if (action == vclib.ADDED or action == vclib.REPLACED) \
-         and change.base_path \
-         and change.base_rev:
-        is_copy = 1
-      if change.item_kind == core.svn_node_dir:
-        pathtype = vclib.DIR
-      elif change.item_kind == core.svn_node_file:
-        pathtype = vclib.FILE
-      else:
-        pathtype = None
-      
-      changedpaths[path] = SVNChangedPath(path, rev, pathtype,
-                                          change.base_path,
-                                          change.base_rev, action,
-                                          is_copy, change.text_changed,
-                                          change.prop_changes)
-    
-    # Return our tuple: date, author, msg, changes
-    return _datestr_to_date(datestr), author, msg, changedpaths.values()
-
-  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
-    p1 = self._getpath(path_parts1)
-    p2 = self._getpath(path_parts2)
-    r1 = self._getrev(rev1)
-    r2 = self._getrev(rev2)
-    args = vclib._diff_args(type, options)
-
-    try:
-      temp1 = temp_checkout(self, p1, r1)
-      temp2 = temp_checkout(self, p2, r2)
-      info1 = p1, date_from_rev(self, r1), r1
-      info2 = p2, date_from_rev(self, r2), r2
-      return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
-    except vclib.svn.core.SubversionException, e:
-      if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
-        raise vclib.InvalidRevision
-      raise
-
-  def _getpath(self, path_parts):
-    return string.join(path_parts, '/')
-
-  def _getrev(self, rev):
-    if rev is None or rev == 'HEAD':
-      return self.youngest
-    try:
-      rev = int(rev)
-    except ValueError:
-      raise vclib.InvalidRevision(rev)
-    if (rev < 0) or (rev > self.youngest):
-      raise vclib.InvalidRevision(rev)
-    return rev
-
-  def _getroot(self, rev):
-    try:
-      return self._fsroots[rev]
-    except KeyError:
-      r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
-      return r
+    import svn_repos
+    return svn_repos.LocalSubversionRepository(name, rootpath, authorizer,
+                                               utilities, config_dir)

Added: branches/VIEWCVS_DIST/lib/vclib/svn/svn_ra.py
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/lib/vclib/svn/svn_ra.py	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,546 @@
+# -*-python-*-
+#
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
+#
+# By using this file, you agree to the terms and conditions set forth in
+# the LICENSE.html file which can be found at the top level of the ViewVC
+# distribution or at http://viewvc.org/license-1.html.
+#
+# For more information, visit http://viewvc.org/
+#
+# -----------------------------------------------------------------------
+
+"Version Control lib driver for remotely accessible Subversion repositories."
+
+import vclib
+import sys
+import os
+import string
+import re
+import tempfile
+import popen2
+import time
+import urllib
+from svn_repos import Revision, SVNChangedPath, _datestr_to_date, _compare_paths, _path_parts, _cleanup_path, _rev2optrev
+from svn import core, delta, client, wc, ra
+
+
+### Require Subversion 1.3.1 or better. (for svn_ra_get_locations support)
+if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
+  raise Exception, "Version requirement not met (needs 1.3.1 or better)"
+
+
+### BEGIN COMPATABILITY CODE ###
+
+try:
+  SVN_INVALID_REVNUM = core.SVN_INVALID_REVNUM
+except AttributeError: # The 1.4.x bindings are missing core.SVN_INVALID_REVNUM
+  SVN_INVALID_REVNUM = -1
+
+def list_directory(url, peg_rev, rev, flag, ctx):
+  try:
+    dirents, locks = client.svn_client_ls3(url, peg_rev, rev, flag, ctx)
+  except TypeError: # 1.4.x bindings are goofed
+    dirents = client.svn_client_ls3(None, url, peg_rev, rev, flag, ctx)
+    locks = {}
+  return dirents, locks  
+
+def get_directory_props(ra_session, path, rev):
+  try:
+    dirents, fetched_rev, props = ra.svn_ra_get_dir(ra_session, path, rev)
+  except ValueError: # older bindings are goofed
+    props = ra.svn_ra_get_dir(ra_session, path, rev)
+  return props
+
+### END COMPATABILITY CODE ###
+
+
+class LogCollector:
+  ### TODO: Make this thing authz-aware
+  
+  def __init__(self, path, show_all_logs, lockinfo):
+    # This class uses leading slashes for paths internally
+    if not path:
+      self.path = '/'
+    else:
+      self.path = path[0] == '/' and path or '/' + path
+    self.logs = []
+    self.show_all_logs = show_all_logs
+    self.lockinfo = lockinfo
+    
+  def add_log(self, paths, revision, author, date, message, pool):
+    # Changed paths have leading slashes
+    changed_paths = paths.keys()
+    changed_paths.sort(lambda a, b: _compare_paths(a, b))
+    this_path = None
+    if self.path in changed_paths:
+      this_path = self.path
+      change = paths[self.path]
+      if change.copyfrom_path:
+        this_path = change.copyfrom_path
+    for changed_path in changed_paths:
+      if changed_path != self.path:
+        # If a parent of our path was copied, our "next previous"
+        # (huh?) path will exist elsewhere (under the copy source).
+        if (string.rfind(self.path, changed_path) == 0) and \
+               self.path[len(changed_path)] == '/':
+          change = paths[changed_path]
+          if change.copyfrom_path:
+            this_path = change.copyfrom_path + self.path[len(changed_path):]
+    if self.show_all_logs or this_path:
+      entry = Revision(revision, _datestr_to_date(date), author, message, None,
+                       self.lockinfo, self.path[1:], None, None)
+      self.logs.append(entry)
+    if this_path:
+      self.path = this_path
+    
+def temp_checkout(svnrepos, path, rev):
+  """Check out file revision to temporary file"""
+  temp = tempfile.mktemp()
+  stream = core.svn_stream_from_aprfile(temp)
+  url = svnrepos._geturl(path)
+  client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev),
+                        svnrepos.ctx)
+  core.svn_stream_close(stream)
+  return temp
+
+class SelfCleanFP:
+  def __init__(self, path):
+    self._fp = open(path, 'r')
+    self._path = path
+    self._eof = 0
+    
+  def read(self, len=None):
+    if len:
+      chunk = self._fp.read(len)
+    else:
+      chunk = self._fp.read()
+    if chunk == '':
+      self._eof = 1
+    return chunk
+  
+  def readline(self):
+    chunk = self._fp.readline()
+    if chunk == '':
+      self._eof = 1
+    return chunk
+
+  def readlines(self):
+    lines = self._fp.readlines()
+    self._eof = 1
+    return lines
+    
+  def close(self):
+    self._fp.close()
+    os.remove(self._path)
+
+  def __del__(self):
+    self.close()
+    
+  def eof(self):
+    return self._eof
+
+
+class RemoteSubversionRepository(vclib.Repository):
+  def __init__(self, name, rootpath, authorizer, utilities, config_dir):
+    self.name = name
+    self.rootpath = rootpath
+    self.auth = authorizer
+    self.diff_cmd = utilities.diff or 'diff'
+    self.config_dir = config_dir or None
+
+    # See if this repository is even viewable, authz-wise.
+    if not vclib.check_root_access(self):
+      raise vclib.ReposNotFound(name)
+
+  def open(self):
+    # Setup the client context baton, complete with non-prompting authstuffs.
+    # TODO: svn_cmdline_setup_auth_baton() is mo' better (when available)
+    core.svn_config_ensure(self.config_dir)
+    self.ctx = client.svn_client_ctx_t()
+    self.ctx.auth_baton = core.svn_auth_open([
+      client.svn_client_get_simple_provider(),
+      client.svn_client_get_username_provider(),
+      client.svn_client_get_ssl_server_trust_file_provider(),
+      client.svn_client_get_ssl_client_cert_file_provider(),
+      client.svn_client_get_ssl_client_cert_pw_file_provider(),
+      ])
+    self.ctx.config = core.svn_config_get_config(self.config_dir)
+    if self.config_dir is not None:
+      core.svn_auth_set_parameter(self.ctx.auth_baton,
+                                  core.SVN_AUTH_PARAM_CONFIG_DIR,
+                                  self.config_dir)
+    ra_callbacks = ra.svn_ra_callbacks_t()
+    ra_callbacks.auth_baton = self.ctx.auth_baton
+    self.ra_session = ra.svn_ra_open(self.rootpath, ra_callbacks, None,
+                                     self.ctx.config)
+    self.youngest = ra.svn_ra_get_latest_revnum(self.ra_session)
+    self._dirent_cache = { }
+    self._revinfo_cache = { }
+    
+  def rootname(self):
+    return self.name
+
+  def rootpath(self):
+    return self.rootpath
+
+  def roottype(self):
+    return vclib.SVN
+
+  def authorizer(self):
+    return self.auth
+  
+  def itemtype(self, path_parts, rev):
+    pathtype = None
+    if not len(path_parts):
+      pathtype = vclib.DIR
+    else:
+      path = self._getpath(path_parts)
+      rev = self._getrev(rev)
+      try:
+        kind = ra.svn_ra_check_path(self.ra_session, path, rev)
+        if kind == core.svn_node_file:
+          pathtype = vclib.FILE
+        elif kind == core.svn_node_dir:
+          pathtype = vclib.DIR
+      except:
+        pass
+    if pathtype is None:
+      raise vclib.ItemNotFound(path_parts)
+    if not vclib.check_path_access(self, path_parts, pathtype, rev):
+      raise vclib.ItemNotFound(path_parts)
+    return pathtype
+
+  def openfile(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file." % path)
+    rev = self._getrev(rev)
+    url = self._geturl(path)
+    tmp_file = tempfile.mktemp()
+    stream = core.svn_stream_from_aprfile(tmp_file)
+    ### rev here should be the last history revision of the URL
+    client.svn_client_cat(core.Stream(stream), url, _rev2optrev(rev), self.ctx)
+    core.svn_stream_close(stream)
+    return SelfCleanFP(tmp_file), self._get_last_history_rev(path_parts, rev)
+
+  def listdir(self, path_parts, rev, options):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory." % path)
+    rev = self._getrev(rev)
+    entries = [ ]
+    dirents, locks = self._get_dirents(path, rev)
+    for name in dirents.keys():
+      entry = dirents[name]
+      if entry.kind == core.svn_node_dir:
+        kind = vclib.DIR
+      elif entry.kind == core.svn_node_file:
+        kind = vclib.FILE
+      if vclib.check_path_access(self, path_parts + [name], kind, rev):
+        entries.append(vclib.DirEntry(name, kind))
+    return entries
+
+  def dirlogs(self, path_parts, rev, entries, options):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory." % path)
+    rev = self._getrev(rev)
+    dirents, locks = self._get_dirents(path, rev)
+    for entry in entries:
+      entry_path_parts = path_parts + [entry.name]
+      if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
+        continue
+      dirent = dirents[entry.name]
+      entry.date, entry.author, entry.log, changes = \
+                  self.revinfo(dirent.created_rev)
+      entry.rev = dirent.created_rev
+      entry.size = dirent.size
+      entry.lockinfo = None
+      if locks.has_key(entry.name):
+        entry.lockinfo = locks[entry.name].owner
+
+  def itemlog(self, path_parts, rev, sortby, first, limit, options):
+    assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV   
+    path_type = self.itemtype(path_parts, rev) # does auth-check
+    path = self._getpath(path_parts)
+    rev = self._getrev(rev)
+    url = self._geturl(path)
+
+    # Use ls3 to fetch the lock status for this item.
+    lockinfo = None
+    basename = path_parts and path_parts[-1] or ""
+    dirents, locks = list_directory(url, _rev2optrev(rev),
+                                    _rev2optrev(rev), 0, self.ctx)
+    if locks.has_key(basename):
+      lockinfo = locks[basename].owner
+
+    # It's okay if we're told to not show all logs on a file -- all
+    # the revisions should match correctly anyway.
+    lc = LogCollector(path, options.get('svn_show_all_dir_logs', 0), lockinfo)
+
+    cross_copies = options.get('svn_cross_copies', 0)
+    log_limit = 0
+    if limit:
+      log_limit = first + limit
+    client.svn_client_log2([url], _rev2optrev(rev), _rev2optrev(1),
+                           log_limit, 1, not cross_copies,
+                           lc.add_log, self.ctx)
+    revs = lc.logs
+    revs.sort()
+    prev = None
+    for rev in revs:
+      rev.prev = prev
+      prev = rev
+    revs.reverse()
+
+    if len(revs) < first:
+      return []
+    if limit:
+      return revs[first:first+limit]
+    return revs
+
+  def itemprops(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    path_type = self.itemtype(path_parts, rev) # does auth-check
+    rev = self._getrev(rev)
+    url = self._geturl(path)
+    pairs = client.svn_client_proplist2(url, _rev2optrev(rev),
+                                        _rev2optrev(rev), 0, self.ctx)
+    return pairs and pairs[0][1] or {}
+  
+  def annotate(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file." % path)
+    rev = self._getrev(rev)
+    url = self._geturl(path)
+
+    blame_data = []
+
+    def _blame_cb(line_no, revision, author, date,
+                  line, pool, blame_data=blame_data):
+      prev_rev = None
+      if revision > 1:
+        prev_rev = revision - 1
+      blame_data.append(vclib.Annotation(line, line_no+1, revision, prev_rev,
+                                         author, None))
+      
+    client.svn_client_blame(url, _rev2optrev(1), _rev2optrev(rev),
+                            _blame_cb, self.ctx)
+
+    return blame_data, rev
+
+  def revinfo(self, rev):
+    rev = self._getrev(rev)
+    cached_info = self._revinfo_cache.get(rev)
+    if not cached_info:
+      cached_info = self._revinfo_raw(rev)
+      self._revinfo_cache[rev] = cached_info
+    return cached_info[0], cached_info[1], cached_info[2], cached_info[3]
+    
+  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
+    p1 = self._getpath(path_parts1)
+    p2 = self._getpath(path_parts2)
+    r1 = self._getrev(rev1)
+    r2 = self._getrev(rev2)
+    if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
+      raise vclib.ItemNotFound(path_parts1)
+    if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
+      raise vclib.ItemNotFound(path_parts2)
+
+    args = vclib._diff_args(type, options)
+
+    def _date_from_rev(rev):
+      date, author, msg, changes = self.revinfo(rev)
+      return date
+    
+    try:
+      temp1 = temp_checkout(self, p1, r1)
+      temp2 = temp_checkout(self, p2, r2)
+      info1 = p1, _date_from_rev(r1), r1
+      info2 = p2, _date_from_rev(r2), r2
+      return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
+    except core.SubversionException, e:
+      if e.apr_err == vclib.svn.core.SVN_ERR_FS_NOT_FOUND:
+        raise vclib.InvalidRevision
+      raise
+
+  def isexecutable(self, path_parts, rev):
+    props = self.itemprops(path_parts, rev) # does authz-check
+    return props.has_key(core.SVN_PROP_EXECUTABLE)
+  
+  def _getpath(self, path_parts):
+    return string.join(path_parts, '/')
+
+  def _getrev(self, rev):
+    if rev is None or rev == 'HEAD':
+      return self.youngest
+    try:
+      rev = int(rev)
+    except ValueError:
+      raise vclib.InvalidRevision(rev)
+    if (rev < 0) or (rev > self.youngest):
+      raise vclib.InvalidRevision(rev)
+    return rev
+
+  def _geturl(self, path=None):
+    if not path:
+      return self.rootpath
+    return self.rootpath + '/' + urllib.quote(path, "/*~")
+
+  def _get_dirents(self, path, rev):
+    """Return a 2-type of dirents and locks, possibly reading/writing
+    from a local cache of that information."""
+
+    dir_url = self._geturl(path)
+    if path:
+      key = str(rev) + '/' + path
+    else:
+      key = str(rev)
+    dirents_locks = self._dirent_cache.get(key)
+    if not dirents_locks:
+      dirents, locks = list_directory(dir_url, _rev2optrev(rev),
+                                      _rev2optrev(rev), 0, self.ctx)
+      dirents_locks = [dirents, locks]
+      self._dirent_cache[key] = dirents_locks
+    return dirents_locks[0], dirents_locks[1]
+
+  def _get_last_history_rev(self, path_parts, rev):
+    url = self._geturl(self._getpath(path_parts))
+    optrev = _rev2optrev(rev)
+    revisions = []
+    def _info_cb(path, info, pool, retval=revisions):
+      revisions.append(info.last_changed_rev)
+    client.svn_client_info(url, optrev, optrev, _info_cb, 0, self.ctx)
+    return revisions[0]
+    
+  def _revinfo_raw(self, rev):
+    # return 5-tuple (date, author, message, changes)
+    optrev = _rev2optrev(rev)
+    revs = []
+
+    def _log_cb(changed_paths, revision, author,
+                datestr, message, pool, retval=revs):
+      date = _datestr_to_date(datestr)
+      action_map = { 'D' : vclib.DELETED,
+                     'A' : vclib.ADDED,
+                     'R' : vclib.REPLACED,
+                     'M' : vclib.MODIFIED,
+                     }
+      paths = (changed_paths or {}).keys()
+      paths.sort(lambda a, b: _compare_paths(a, b))
+      changes = []
+      found_readable = found_unreadable = 0
+      for path in paths:
+        pathtype = None
+        change = changed_paths[path]
+        action = action_map.get(change.action, vclib.MODIFIED)
+        ### Wrong, diddily wrong wrong wrong.  Can you say,
+        ### "Manufacturing data left and right because it hurts to
+        ### figure out the right stuff?"
+        if change.copyfrom_path and change.copyfrom_rev:
+          is_copy = 1
+          base_path = change.copyfrom_path
+          base_rev = change.copyfrom_rev
+        elif action == vclib.ADDED or action == vclib.REPLACED:
+          is_copy = 0
+          base_path = base_rev = None
+        else:
+          is_copy = 0
+          base_path = path
+          base_rev = revision - 1
+
+        ### Check authz rules (we lie about the path type)
+        parts = _path_parts(path)
+        if vclib.check_path_access(self, parts, vclib.FILE, revision):
+          if is_copy and base_path and (base_path != path):
+            parts = _path_parts(base_path)
+            if vclib.check_path_access(self, parts, vclib.FILE, base_rev):
+              is_copy = 0
+              base_path = None
+              base_rev = None
+          changes.append(SVNChangedPath(path, revision, pathtype, base_path,
+                                        base_rev, action, is_copy, 0, 0))
+          found_readable = 1
+        else:
+          found_unreadable = 1
+
+      if found_unreadable:
+        message = None
+        if not found_readable:
+          author = None
+          date = None
+      revs.append([date, author, message, changes])
+
+    client.svn_client_log([self.rootpath], optrev, optrev,
+                          1, 0, _log_cb, self.ctx)
+    return revs[0][0], revs[0][1], revs[0][2], revs[0][3]
+
+  ##--- custom --##
+
+  def get_youngest_revision(self):
+    return self.youngest
+  
+  def get_location(self, path, rev, old_rev):
+    try:
+      results = ra.get_locations(self.ra_session, path, rev, [old_rev])
+    except core.SubversionException, e:
+      if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
+        raise vclib.ItemNotFound(path)
+      raise
+    try:
+      old_path = results[old_rev]
+    except KeyError:
+      raise vclib.ItemNotFound(path)
+  
+    return _cleanup_path(old_path)
+  
+  def created_rev(self, path, rev):
+    # NOTE: We can't use svn_client_propget here because the
+    # interfaces in that layer strip out the properties not meant for
+    # human consumption (such as svn:entry:committed-rev, which we are
+    # using here to get the created revision of PATH REV).
+    kind = ra.svn_ra_check_path(self.ra_session, path, rev)
+    if kind == core.svn_node_none:
+      raise vclib.ItemNotFound(_path_parts(path))
+    elif kind == core.svn_node_dir:
+      props = get_directory_props(self.ra_session, path, rev)
+    elif kind == core.svn_node_file:
+      fetched_rev, props = ra.svn_ra_get_file(self.ra_session, path, rev, None)
+    return int(props.get(core.SVN_PROP_ENTRY_COMMITTED_REV,
+                         SVN_INVALID_REVNUM))
+
+  def last_rev(self, path, peg_revision, limit_revision=None):
+    """Given PATH, known to exist in PEG_REVISION, find the youngest
+    revision older than, or equal to, LIMIT_REVISION in which path
+    exists.  Return that revision, and the path at which PATH exists in
+    that revision."""
+    
+    # Here's the plan, man.  In the trivial case (where PEG_REVISION is
+    # the same as LIMIT_REVISION), this is a no-brainer.  If
+    # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
+    # history tracing code to find the right location.  If, however,
+    # LIMIT_REVISION is younger than PEG_REVISION, we suffer from
+    # Subversion's lack of forward history searching.  Our workaround,
+    # ugly as it may be, involves a binary search through the revisions
+    # between PEG_REVISION and LIMIT_REVISION to find our last live
+    # revision.
+    peg_revision = self._getrev(peg_revision)
+    limit_revision = self._getrev(limit_revision)
+    if peg_revision == limit_revision:
+      return peg_revision, path
+    elif peg_revision > limit_revision:
+      path = self.get_location(path, peg_revision, limit_revision)
+      return limit_revision, path
+    else:
+      direction = 1
+      while peg_revision != limit_revision:
+        mid = (peg_revision + 1 + limit_revision) / 2
+        try:
+          path = self.get_location(path, peg_revision, mid)
+        except vclib.ItemNotFound:
+          limit_revision = mid - 1
+        else:
+          peg_revision = mid
+      return peg_revision, path

Added: branches/VIEWCVS_DIST/lib/vclib/svn/svn_repos.py
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/lib/vclib/svn/svn_repos.py	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,778 @@
+# -*-python-*-
+#
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
+#
+# By using this file, you agree to the terms and conditions set forth in
+# the LICENSE.html file which can be found at the top level of the ViewVC
+# distribution or at http://viewvc.org/license-1.html.
+#
+# For more information, visit http://viewvc.org/
+#
+# -----------------------------------------------------------------------
+
+"Version Control lib driver for locally accessible Subversion repositories"
+
+import vclib
+import os
+import os.path
+import stat
+import string
+import cStringIO
+import signal
+import shutil
+import time
+import tempfile
+import popen
+import re
+from svn import fs, repos, core, client, delta
+
+
+### Require Subversion 1.3.1 or better.
+if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_PATCH) < (1, 3, 1):
+  raise Exception, "Version requirement not met (needs 1.3.1 or better)"
+
+  
+def _allow_all(root, path, pool):
+  """Generic authz_read_func that permits access to all paths"""
+  return 1
+
+
+def _path_parts(path):
+  return filter(None, string.split(path, '/'))
+
+
+def _cleanup_path(path):
+  """Return a cleaned-up Subversion filesystem path"""
+  return string.join(_path_parts(path), '/')
+  
+
+def _fs_path_join(base, relative):
+  return _cleanup_path(base + '/' + relative)
+
+
+def _compare_paths(path1, path2):
+  path1_len = len (path1);
+  path2_len = len (path2);
+  min_len = min(path1_len, path2_len)
+  i = 0
+
+  # Are the paths exactly the same?
+  if path1 == path2:
+    return 0
+  
+  # Skip past common prefix
+  while (i < min_len) and (path1[i] == path2[i]):
+    i = i + 1
+
+  # Children of paths are greater than their parents, but less than
+  # greater siblings of their parents
+  char1 = '\0'
+  char2 = '\0'
+  if (i < path1_len):
+    char1 = path1[i]
+  if (i < path2_len):
+    char2 = path2[i]
+    
+  if (char1 == '/') and (i == path2_len):
+    return 1
+  if (char2 == '/') and (i == path1_len):
+    return -1
+  if (i < path1_len) and (char1 == '/'):
+    return -1
+  if (i < path2_len) and (char2 == '/'):
+    return 1
+
+  # Common prefix was skipped above, next character is compared to
+  # determine order
+  return cmp(char1, char2)
+
+
+def _rev2optrev(rev):
+  assert type(rev) is int
+  rt = core.svn_opt_revision_t()
+  rt.kind = core.svn_opt_revision_number
+  rt.value.number = rev
+  return rt
+
+
+def _rootpath2url(rootpath, path):
+  rootpath = os.path.abspath(rootpath)
+  if rootpath and rootpath[0] != '/':
+    rootpath = '/' + rootpath
+  if os.sep != '/':
+    rootpath = string.replace(rootpath, os.sep, '/')
+  return 'file://' + string.join([rootpath, path], "/")
+
+
+def _datestr_to_date(datestr):
+  try:
+    return core.svn_time_from_cstring(datestr) / 1000000
+  except:
+    return None
+
+  
+class Revision(vclib.Revision):
+  "Hold state for each revision's log entry."
+  def __init__(self, rev, date, author, msg, size, lockinfo,
+               filename, copy_path, copy_rev):
+    vclib.Revision.__init__(self, rev, str(rev), date, author, None,
+                            msg, size, lockinfo)
+    self.filename = filename
+    self.copy_path = copy_path
+    self.copy_rev = copy_rev
+
+
+class NodeHistory:
+  """An iterable object that returns 2-tuples of (revision, path)
+  locations along a node's change history, ordered from youngest to
+  oldest."""
+  
+  def __init__(self, fs_ptr, show_all_logs, limit=0):
+    self.histories = []
+    self.fs_ptr = fs_ptr
+    self.show_all_logs = show_all_logs
+    self.oldest_rev = None
+    self.limit = limit
+    
+  def add_history(self, path, revision, pool):
+    # If filtering, only add the path and revision to the histories
+    # list if they were actually changed in this revision (where
+    # change means the path itself was changed, or one of its parents
+    # was copied).  This is useful for omitting bubble-up directory
+    # changes.
+    if not self.oldest_rev:
+      self.oldest_rev = revision
+    else:
+      assert(revision < self.oldest_rev)
+      
+    if not self.show_all_logs:
+      rev_root = fs.revision_root(self.fs_ptr, revision)
+      changed_paths = fs.paths_changed(rev_root)
+      paths = changed_paths.keys()
+      if path not in paths:
+        # Look for a copied parent
+        test_path = path
+        found = 0
+        while 1:
+          off = string.rfind(test_path, '/')
+          if off < 0:
+            break
+          test_path = test_path[0:off]
+          if test_path in paths:
+            copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, test_path)
+            if copyfrom_rev >= 0 and copyfrom_path:
+              found = 1
+              break
+        if not found:
+          return
+    self.histories.append([revision, _cleanup_path(path)])
+    if self.limit and len(self.histories) == self.limit:
+      raise core.SubversionException("", core.SVN_ERR_CEASE_INVOCATION)
+
+  def __getitem__(self, idx):
+    return self.histories[idx]
+
+
+def _get_history(svnrepos, path, rev, path_type, limit=0, options={}):
+  rev_paths = []
+  fsroot = svnrepos._getroot(rev)
+  show_all_logs = options.get('svn_show_all_dir_logs', 0)
+  if not show_all_logs:
+    # See if the path is a file or directory.
+    kind = fs.check_path(fsroot, path)
+    if kind is core.svn_node_file:
+      show_all_logs = 1
+      
+  # Instantiate a NodeHistory collector object, and use it to collect
+  # history items for PATH REV 
+  history = NodeHistory(svnrepos.fs_ptr, show_all_logs, limit)
+  try:
+    repos.svn_repos_history(svnrepos.fs_ptr, path, history.add_history,
+                            1, rev, options.get('svn_cross_copies', 0))
+  except core.SubversionException, e:
+    if e.apr_err != core.SVN_ERR_CEASE_INVOCATION:
+      raise
+
+  # Now, iterate over those history items, checking for changes of
+  # location, pruning as necessitated by authz rules.
+  for hist_rev, hist_path in history:
+    path_parts = _path_parts(hist_path)
+    if not vclib.check_path_access(svnrepos, path_parts, path_type, hist_rev):
+      break
+    rev_paths.append([hist_rev, hist_path])
+  return rev_paths
+
+
+def _log_helper(svnrepos, path, rev, lockinfo):
+  rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
+
+  # Was this path rev the target of a copy?
+  copyfrom_rev, copyfrom_path = fs.copied_from(rev_root, path)
+
+  # Assemble our LogEntry
+  date, author, msg, changes = svnrepos.revinfo(rev)
+  if fs.is_file(rev_root, path):
+    size = fs.file_length(rev_root, path)
+  else:
+    size = None
+  entry = Revision(rev, date, author, msg, size, lockinfo, path,
+                   copyfrom_path and _cleanup_path(copyfrom_path),
+                   copyfrom_rev)
+  return entry
+  
+
+def _get_last_history_rev(fsroot, path):
+  history = fs.node_history(fsroot, path)
+  history = fs.history_prev(history, 0)
+  history_path, history_rev = fs.history_location(history)
+  return history_rev
+  
+def temp_checkout(svnrepos, path, rev):
+  """Check out file revision to temporary file"""
+  temp = tempfile.mktemp()
+  fp = open(temp, 'wb')
+  try:
+    root = svnrepos._getroot(rev)
+    stream = fs.file_contents(root, path)
+    try:
+      while 1:
+        chunk = core.svn_stream_read(stream, core.SVN_STREAM_CHUNK_SIZE)
+        if not chunk:
+          break
+        fp.write(chunk)
+    finally:
+      core.svn_stream_close(stream)
+  finally:
+    fp.close()
+  return temp
+
+class FileContentsPipe:
+  def __init__(self, root, path):
+    self._stream = fs.file_contents(root, path)
+    self._eof = 0
+
+  def read(self, len=None):
+    chunk = None
+    if not self._eof:
+      if len is None:
+        buffer = cStringIO.StringIO()
+        try:
+          while 1:
+            hunk = core.svn_stream_read(self._stream, 8192)
+            if not hunk:
+              break
+            buffer.write(hunk)
+          chunk = buffer.getvalue()
+        finally:
+          buffer.close()
+
+      else:
+        chunk = core.svn_stream_read(self._stream, len)   
+    if not chunk:
+      self._eof = 1
+    return chunk
+  
+  def readline(self):
+    chunk = None
+    if not self._eof:
+      chunk, self._eof = core.svn_stream_readline(self._stream, '\n')
+      if not self._eof:
+        chunk = chunk + '\n'
+    if not chunk:
+      self._eof = 1
+    return chunk
+
+  def readlines(self):
+    lines = []
+    while True:
+      line = self.readline()
+      if not line:
+        break
+      lines.append(line)
+    return lines
+
+  def close(self):
+    return core.svn_stream_close(self._stream)
+
+  def eof(self):
+    return self._eof
+
+
+class BlameSource:
+  def __init__(self, local_url, rev, first_rev):
+    self.idx = -1
+    self.first_rev = first_rev
+    self.blame_data = []
+
+    ctx = client.ctx_t()
+    core.svn_config_ensure(None)
+    ctx.config = core.svn_config_get_config(None)
+    ctx.auth_baton = core.svn_auth_open([])
+    try:
+      ### TODO: Is this use of FIRST_REV always what we want?  Should we
+      ### pass 1 here instead and do filtering later?
+      client.blame2(local_url, _rev2optrev(rev), _rev2optrev(first_rev),
+                    _rev2optrev(rev), self._blame_cb, ctx)
+    except core.SubversionException, e:
+      if e.apr_err == core.SVN_ERR_CLIENT_IS_BINARY_FILE:
+        raise vclib.NonTextualFileContents
+      raise
+
+  def _blame_cb(self, line_no, rev, author, date, text, pool):
+    prev_rev = None
+    if rev > self.first_rev:
+      prev_rev = rev - 1
+    self.blame_data.append(vclib.Annotation(text, line_no + 1, rev,
+                                            prev_rev, author, None))
+
+  def __getitem__(self, idx):
+    if idx != self.idx + 1:
+      raise BlameSequencingError()
+    self.idx = idx
+    return self.blame_data[idx]
+
+
+class BlameSequencingError(Exception):
+  pass
+
+
+class SVNChangedPath(vclib.ChangedPath):
+  """Wrapper around vclib.ChangedPath which handles path splitting."""
+  
+  def __init__(self, path, rev, pathtype, base_path, base_rev,
+               action, copied, text_changed, props_changed):
+    path_parts = _path_parts(path or '')
+    base_path_parts = _path_parts(base_path or '')
+    vclib.ChangedPath.__init__(self, path_parts, rev, pathtype,
+                               base_path_parts, base_rev, action,
+                               copied, text_changed, props_changed)
+
+  
+class LocalSubversionRepository(vclib.Repository):
+  def __init__(self, name, rootpath, authorizer, utilities, config_dir):
+    if not (os.path.isdir(rootpath) \
+            and os.path.isfile(os.path.join(rootpath, 'format'))):
+      raise vclib.ReposNotFound(name)
+
+    # Initialize some stuff.
+    self.rootpath = rootpath
+    self.name = name
+    self.auth = authorizer
+    self.svn_client_path = utilities.svn or 'svn'
+    self.diff_cmd = utilities.diff or 'diff'
+    self.config_dir = config_dir
+
+    # See if this repository is even viewable, authz-wise.
+    if not vclib.check_root_access(self):
+      raise vclib.ReposNotFound(name)
+
+  def open(self):
+    # Register a handler for SIGTERM so we can have a chance to
+    # cleanup.  If ViewVC takes too long to start generating CGI
+    # output, Apache will grow impatient and SIGTERM it.  While we
+    # don't mind getting told to bail, we want to gracefully close the
+    # repository before we bail.
+    def _sigterm_handler(signum, frame, self=self):
+      sys.exit(-1)
+    try:
+      signal.signal(signal.SIGTERM, _sigterm_handler)
+    except ValueError:
+      # This is probably "ValueError: signal only works in main
+      # thread", which will get thrown by the likes of mod_python
+      # when trying to install a signal handler from a thread that
+      # isn't the main one.  We'll just not care.
+      pass
+
+    # Open the repository and init some other variables.
+    self.repos = repos.svn_repos_open(self.rootpath)
+    self.fs_ptr = repos.svn_repos_fs(self.repos)
+    self.youngest = fs.youngest_rev(self.fs_ptr)
+    self._fsroots = {}
+    self._revinfo_cache = {}
+
+  def rootname(self):
+    return self.name
+
+  def rootpath(self):
+    return self.rootpath
+
+  def roottype(self):
+    return vclib.SVN
+
+  def authorizer(self):
+    return self.auth
+  
+  def itemtype(self, path_parts, rev):
+    rev = self._getrev(rev)
+    basepath = self._getpath(path_parts)
+    kind = fs.check_path(self._getroot(rev), basepath)
+    pathtype = None
+    if kind == core.svn_node_dir:
+      pathtype = vclib.DIR
+    elif kind == core.svn_node_file:
+      pathtype = vclib.FILE
+    else:
+      raise vclib.ItemNotFound(path_parts)
+    if not vclib.check_path_access(self, path_parts, pathtype, rev):
+      raise vclib.ItemNotFound(path_parts)
+    return pathtype
+
+  def openfile(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.FILE:  # does auth-check
+      raise vclib.Error("Path '%s' is not a file." % path)
+    rev = self._getrev(rev)
+    fsroot = self._getroot(rev)
+    revision = str(_get_last_history_rev(fsroot, path))
+    fp = FileContentsPipe(fsroot, path)
+    return fp, revision
+
+  def listdir(self, path_parts, rev, options):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory." % path)
+    rev = self._getrev(rev)
+    fsroot = self._getroot(rev)
+    dirents = fs.dir_entries(fsroot, path)
+    entries = [ ]
+    for entry in dirents.values():
+      if entry.kind == core.svn_node_dir:
+        kind = vclib.DIR
+      elif entry.kind == core.svn_node_file:
+        kind = vclib.FILE
+      if vclib.check_path_access(self, path_parts + [entry.name], kind, rev):
+        entries.append(vclib.DirEntry(entry.name, kind))
+    return entries
+
+  def dirlogs(self, path_parts, rev, entries, options):
+    path = self._getpath(path_parts)
+    if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
+      raise vclib.Error("Path '%s' is not a directory." % path)
+    fsroot = self._getroot(self._getrev(rev))
+    rev = self._getrev(rev)
+    for entry in entries:
+      entry_path_parts = path_parts + [entry.name]
+      if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
+        continue
+      path = self._getpath(entry_path_parts)
+      entry_rev = _get_last_history_rev(fsroot, path)
+      date, author, msg, changes = self.revinfo(entry_rev)
+      entry.rev = str(entry_rev)
+      entry.date = date
+      entry.author = author
+      entry.log = msg
+      if entry.kind == vclib.FILE:
+        entry.size = fs.file_length(fsroot, path)
+      lock = fs.get_lock(self.fs_ptr, path)
+      entry.lockinfo = lock and lock.owner or None
+
+  def itemlog(self, path_parts, rev, sortby, first, limit, options):
+    """see vclib.Repository.itemlog docstring
+
+    Option values recognized by this implementation
+
+      svn_show_all_dir_logs
+        boolean, default false. if set for a directory path, will include
+        revisions where files underneath the directory have changed
+
+      svn_cross_copies
+        boolean, default false. if set for a path created by a copy, will
+        include revisions from before the copy
+
+      svn_latest_log
+        boolean, default false. if set will return only newest single log
+        entry
+    """
+    assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV   
+
+    path = self._getpath(path_parts)
+    path_type = self.itemtype(path_parts, rev)  # does auth-check
+    rev = self._getrev(rev)
+    revs = []
+    lockinfo = None
+
+    # See if this path is locked.
+    try:
+      lock = fs.get_lock(self.fs_ptr, path)
+      if lock:
+        lockinfo = lock.owner
+    except NameError:
+      pass
+
+    # If our caller only wants the latest log, we'll invoke
+    # _log_helper for just the one revision.  Otherwise, we go off
+    # into history-fetching mode.  ### TODO: we could stand to have a
+    # 'limit' parameter here as numeric cut-off for the depth of our
+    # history search.
+    if options.get('svn_latest_log', 0):
+      revision = _log_helper(self, path, rev, lockinfo)
+      if revision:
+        revision.prev = None
+        revs.append(revision)
+    else:
+      history = _get_history(self, path, rev, path_type,
+                             first + limit, options)
+      if len(history) < first:
+        history = []
+      if limit:
+        history = history[first:first+limit]
+
+      for hist_rev, hist_path in history:
+        revision = _log_helper(self, hist_path, hist_rev, lockinfo)
+        if revision:
+          # If we have unreadable copyfrom data, obscure it.
+          if revision.copy_path is not None:
+            cp_parts = _path_parts(revision.copy_path)
+            if not vclib.check_path_access(self, cp_parts, path_type,
+                                           revision.copy_rev):
+              revision.copy_path = revision.copy_rev = None
+          revision.prev = None
+          if len(revs):
+            revs[-1].prev = revision
+          revs.append(revision)
+    return revs
+
+  def itemprops(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    path_type = self.itemtype(path_parts, rev)  # does auth-check
+    rev = self._getrev(rev)
+    fsroot = self._getroot(rev)
+    return fs.node_proplist(fsroot, path)
+  
+  def annotate(self, path_parts, rev):
+    path = self._getpath(path_parts)
+    path_type = self.itemtype(path_parts, rev)  # does auth-check
+    if path_type != vclib.FILE:
+      raise vclib.Error("Path '%s' is not a file." % path)
+    rev = self._getrev(rev)
+    fsroot = self._getroot(rev)
+    history = _get_history(self, path, rev, path_type, 0,
+                           {'svn_cross_copies': 1})
+    youngest_rev, youngest_path = history[0]
+    oldest_rev, oldest_path = history[-1]
+    source = BlameSource(_rootpath2url(self.rootpath, path),
+                         youngest_rev, oldest_rev)
+    return source, youngest_rev
+
+  def _revinfo_raw(self, rev):
+    fsroot = self._getroot(rev)
+
+    # Get the changes for the revision
+    editor = repos.ChangeCollector(self.fs_ptr, fsroot)
+    e_ptr, e_baton = delta.make_editor(editor)
+    repos.svn_repos_replay(fsroot, e_ptr, e_baton)
+    changes = editor.get_changes()
+    changedpaths = {}
+    
+    # Now get the revision property info.  Would use
+    # editor.get_root_props(), but something is broken there...
+    revprops = fs.revision_proplist(self.fs_ptr, rev)
+    msg = revprops.get(core.SVN_PROP_REVISION_LOG)
+    author = revprops.get(core.SVN_PROP_REVISION_AUTHOR)
+    datestr = revprops.get(core.SVN_PROP_REVISION_DATE)
+
+    # Copy the Subversion changes into a new hash, converting them into
+    # ChangedPath objects.
+    found_readable = found_unreadable = 0
+    for path in changes.keys():
+      change = changes[path]
+      if change.path:
+        change.path = _cleanup_path(change.path)
+      if change.base_path:
+        change.base_path = _cleanup_path(change.base_path)
+      is_copy = 0
+      if not hasattr(change, 'action'): # new to subversion 1.4.0
+        action = vclib.MODIFIED
+        if not change.path:
+          action = vclib.DELETED
+        elif change.added:
+          action = vclib.ADDED
+          replace_check_path = path
+          if change.base_path and change.base_rev:
+            replace_check_path = change.base_path
+          if changedpaths.has_key(replace_check_path) \
+             and changedpaths[replace_check_path].action == vclib.DELETED:
+            action = vclib.REPLACED
+      else:
+        if change.action == repos.CHANGE_ACTION_ADD:
+          action = vclib.ADDED
+        elif change.action == repos.CHANGE_ACTION_DELETE:
+          action = vclib.DELETED
+        elif change.action == repos.CHANGE_ACTION_REPLACE:
+          action = vclib.REPLACED
+        else:
+          action = vclib.MODIFIED
+      if (action == vclib.ADDED or action == vclib.REPLACED) \
+         and change.base_path \
+         and change.base_rev:
+        is_copy = 1
+      if change.item_kind == core.svn_node_dir:
+        pathtype = vclib.DIR
+      elif change.item_kind == core.svn_node_file:
+        pathtype = vclib.FILE
+      else:
+        pathtype = None
+
+      parts = _path_parts(path)
+      if vclib.check_path_access(self, parts, pathtype, rev):
+        if is_copy and change.base_path and (change.base_path != path):
+          parts = _path_parts(change.base_path)
+          if not vclib.check_path_access(self, parts, pathtype, change.base_rev):
+            is_copy = 0
+            change.base_path = None
+            change.base_rev = None
+        changedpaths[path] = SVNChangedPath(path, rev, pathtype,
+                                            change.base_path,
+                                            change.base_rev, action,
+                                            is_copy, change.text_changed,
+                                            change.prop_changes)
+        found_readable = 1
+      else:
+        found_unreadable = 1
+
+    # Return our tuple, auth-filtered: date, author, msg, changes
+    if found_unreadable:
+      msg = None
+      if not found_readable:
+        author = None
+        datestr = None
+
+    date = _datestr_to_date(datestr)
+    return date, author, msg, changedpaths.values()
+
+  def revinfo(self, rev):
+    rev = self._getrev(rev)
+    cached_info = self._revinfo_cache.get(rev)
+    if not cached_info:
+      cached_info = self._revinfo_raw(rev)
+      self._revinfo_cache[rev] = cached_info
+    return cached_info[0], cached_info[1], cached_info[2], cached_info[3]
+  
+  def rawdiff(self, path_parts1, rev1, path_parts2, rev2, type, options={}):
+    p1 = self._getpath(path_parts1)
+    p2 = self._getpath(path_parts2)
+    r1 = self._getrev(rev1)
+    r2 = self._getrev(rev2)
+    if not vclib.check_path_access(self, path_parts1, vclib.FILE, rev1):
+      raise vclib.ItemNotFound(path_parts1)
+    if not vclib.check_path_access(self, path_parts2, vclib.FILE, rev2):
+      raise vclib.ItemNotFound(path_parts2)
+    
+    args = vclib._diff_args(type, options)
+
+    def _date_from_rev(rev):
+      date, author, msg, changes = self.revinfo(rev)
+      return date
+
+    try:
+      temp1 = temp_checkout(self, p1, r1)
+      temp2 = temp_checkout(self, p2, r2)
+      info1 = p1, _date_from_rev(r1), r1
+      info2 = p2, _date_from_rev(r2), r2
+      return vclib._diff_fp(temp1, temp2, info1, info2, self.diff_cmd, args)
+    except core.SubversionException, e:
+      if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
+        raise vclib.InvalidRevision
+      raise
+
+  def isexecutable(self, path_parts, rev):
+    props = self.itemprops(path_parts, rev) # does authz-check
+    return props.has_key(core.SVN_PROP_EXECUTABLE)
+  
+  def _getpath(self, path_parts):
+    return string.join(path_parts, '/')
+
+  def _getrev(self, rev):
+    if rev is None or rev == 'HEAD':
+      return self.youngest
+    try:
+      rev = int(rev)
+    except ValueError:
+      raise vclib.InvalidRevision(rev)
+    if (rev < 0) or (rev > self.youngest):
+      raise vclib.InvalidRevision(rev)
+    return rev
+
+  def _getroot(self, rev):
+    try:
+      return self._fsroots[rev]
+    except KeyError:
+      r = self._fsroots[rev] = fs.revision_root(self.fs_ptr, rev)
+      return r
+
+  ##--- custom --##
+
+  def get_youngest_revision(self):
+    return self.youngest
+
+  def get_location(self, path, rev, old_rev):
+    try:
+      results = repos.svn_repos_trace_node_locations(self.fs_ptr, path,
+                                                     rev, [old_rev], _allow_all)
+    except core.SubversionException, e:
+      if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
+        raise vclib.ItemNotFound(path)
+      raise
+    try:
+      old_path = results[old_rev]
+    except KeyError:
+      raise vclib.ItemNotFound(path)
+  
+    return _cleanup_path(old_path)
+  
+  def created_rev(self, full_name, rev):
+    return fs.node_created_rev(self._getroot(rev), full_name)
+  
+  def last_rev(self, path, peg_revision, limit_revision=None):
+    """Given PATH, known to exist in PEG_REVISION, find the youngest
+    revision older than, or equal to, LIMIT_REVISION in which path
+    exists.  Return that revision, and the path at which PATH exists in
+    that revision."""
+    
+    # Here's the plan, man.  In the trivial case (where PEG_REVISION is
+    # the same as LIMIT_REVISION), this is a no-brainer.  If
+    # LIMIT_REVISION is older than PEG_REVISION, we can use Subversion's
+    # history tracing code to find the right location.  If, however,
+    # LIMIT_REVISION is younger than PEG_REVISION, we suffer from
+    # Subversion's lack of forward history searching.  Our workaround,
+    # ugly as it may be, involves a binary search through the revisions
+    # between PEG_REVISION and LIMIT_REVISION to find our last live
+    # revision.
+    peg_revision = self._getrev(peg_revision)
+    limit_revision = self._getrev(limit_revision)
+    try:
+      if peg_revision == limit_revision:
+        return peg_revision, path
+      elif peg_revision > limit_revision:
+        fsroot = self._getroot(peg_revision)
+        history = fs.node_history(fsroot, path)
+        while history:
+          path, peg_revision = fs.history_location(history)
+          if peg_revision <= limit_revision:
+            return max(peg_revision, limit_revision), _cleanup_path(path)
+          history = fs.history_prev(history, 1)
+        return peg_revision, _cleanup_path(path)
+      else:
+        orig_id = fs.node_id(self._getroot(peg_revision), path)
+        while peg_revision != limit_revision:
+          mid = (peg_revision + 1 + limit_revision) / 2
+          try:
+            mid_id = fs.node_id(self._getroot(mid), path)
+          except core.SubversionException, e:
+            if e.apr_err == core.SVN_ERR_FS_NOT_FOUND:
+              cmp = -1
+            else:
+              raise
+          else:
+            ### Not quite right.  Need a comparison function that only returns
+            ### true when the two nodes are the same copy, not just related.
+            cmp = fs.compare_ids(orig_id, mid_id)
+  
+          if cmp in (0, 1):
+            peg_revision = mid
+          else:
+            limit_revision = mid - 1
+  
+        return peg_revision, path
+    finally:
+      pass

Modified: branches/VIEWCVS_DIST/lib/viewvc.py
==============================================================================
--- branches/VIEWCVS_DIST/lib/viewvc.py	(original)
+++ branches/VIEWCVS_DIST/lib/viewvc.py	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 # -*-python-*-
 #
-# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC
@@ -14,7 +14,7 @@
 #
 # -----------------------------------------------------------------------
 
-__version__ = '1.1-dev'
+__version__ = '1.2-dev'
 
 # this comes from our library; measure the startup time
 import debug
@@ -24,27 +24,30 @@
 # standard modules that we know are in the path or builtin
 import sys
 import os
-import sapi
 import cgi
-import string
-import urllib
+import gzip
 import mimetypes
-import time
 import re
 import rfc822
 import stat
+import string
 import struct
-import types
 import tempfile
+import time
+import types
+import urllib
 
-# these modules come from our library (the stub has set up the path)
+# These modules come from our library (the stub has set up the path)
+import accept
 import compat
 import config
-import popen
 import ezt
-import accept
-import vclib
+import popen
+import sapi
 import vcauth
+import vclib
+import vclib.ccvs
+import vclib.svn
 
 try:
   import idiff
@@ -77,6 +80,10 @@
   'limit_changes',
   ]
 
+# number of extra pages of information on either side of the current
+# page to fetch (see use_pagesize configuration option)
+EXTRA_PAGES = 3
+
 # for reading/writing between a couple descriptors
 CHUNK_SIZE = 8192
 
@@ -96,40 +103,29 @@
     self.script_name = _normalize_path(server.getenv('SCRIPT_NAME', ''))
     self.browser = server.getenv('HTTP_USER_AGENT', 'unknown')
 
-    # in lynx, it it very annoying to have two links per file, so
-    # disable the link at the icon in this case:
-    self.no_file_links = string.find(self.browser, 'Lynx') != -1
-
-    # newer browsers accept gzip content encoding and state this in a
-    # header (netscape did always but didn't state it) It has been
-    # reported that these braindamaged MS-Internet Explorers claim
-    # that they accept gzip .. but don't in fact and display garbage
-    # then :-/
-    self.may_compress = (
-      ( string.find(server.getenv('HTTP_ACCEPT_ENCODING', ''), 'gzip') != -1
-        or string.find(self.browser, 'Mozilla/3') != -1)
-      and string.find(self.browser, 'MSIE') == -1
-      )
-
-    # process the Accept-Language: header
+    # process the Accept-Language: header, and load the key/value
+    # files, given the selected language
     hal = server.getenv('HTTP_ACCEPT_LANGUAGE','')
     self.lang_selector = accept.language(hal)
     self.language = self.lang_selector.select_from(cfg.general.languages)
+    self.kv = cfg.load_kv_files(self.language)
 
     # check for an authenticated username
     self.username = server.getenv('REMOTE_USER')
 
-    # load the key/value files, given the selected language
-    self.kv = cfg.load_kv_files(self.language)
+    # if we allow compressed output, see if the client does too
+    self.gzip_compress_level = 0
+    if cfg.options.allow_compress:
+      http_accept_encoding = os.environ.get("HTTP_ACCEPT_ENCODING", "")
+      if "gzip" in filter(None,
+                          map(lambda x: string.strip(x),
+                              string.split(http_accept_encoding, ","))):
+        self.gzip_compress_level = 9  # make this configurable?
 
   def run_viewvc(self):
 
     cfg = self.cfg
 
-    # global needed because "import vclib.svn" causes the
-    # interpreter to make vclib a local variable
-    global vclib
-
     # This function first parses the query string and sets the following
     # variables. Then it executes the request.
     self.view_func = None  # function to call to process the request
@@ -144,9 +140,6 @@
     self.pathrev = None    # current path revision or tag
     self.auth = None       # authorizer module in use
 
-    # setup the default authorizer (until we have a root)
-    self.auth = vcauth.ViewVCAuthorizer()
-    
     # redirect if we're loading from a valid but irregular URL
     # These redirects aren't neccessary to make ViewVC work, it functions
     # just fine without them, but they make it easier for server admins to
@@ -168,6 +161,15 @@
       # validate the parameter
       _validate_param(name, values[0])
 
+      # Only allow the magic ViewVC MIME types (the ones used for
+      # requesting the markup as as-text views) to be declared via CGI
+      # params.  Ignore disallowed values.
+      if (name == 'content-type') and \
+         (not values[0] in (viewcvs_mime_type,
+                            alt_mime_type,
+                            'text/plain')):
+        continue
+      
       # if we're here, then the parameter is okay
       self.query_dict[name] = values[0]
 
@@ -218,7 +220,7 @@
           self.rootname = path_parts.pop(0)
         else:
           self.rootname = ""
-      else:
+      elif self.view_func != view_roots:
         self.rootname = cfg.general.default_root
     elif cfg.options.root_as_url_component:
       needs_redirect = 1
@@ -227,59 +229,45 @@
     self.path_parts = path_parts
 
     if self.rootname:
-      # Create the repository object
-      if cfg.general.cvs_roots.has_key(self.rootname):
-        cfg.overlay_root_options(self.rootname)
-        self.rootpath = os.path.normpath(cfg.general.cvs_roots[self.rootname])
-        try:
-          if cfg.options.use_rcsparse:
-            import vclib.ccvs
-            self.repos = vclib.ccvs.CCVSRepository(self.rootname,
-                                                   self.rootpath,
-                                                   cfg.utilities)
-          else:
-            import vclib.bincvs
-            self.repos = vclib.bincvs.BinCVSRepository(self.rootname, 
-                                                       self.rootpath,
-                                                       cfg.utilities)
-        except vclib.ReposNotFound:
-          raise debug.ViewVCException(
-            'Unable to locate CVS root "%s".  Possible causes include '
-            'having an incorrectly configured path for this root, or the '
-            'server on which the repository lives being inaccessible.' \
-            % self.rootname)
-        # required so that spawned rcs programs correctly expand $CVSHeader$
-        os.environ['CVSROOT'] = self.rootpath
-      elif cfg.general.svn_roots.has_key(self.rootname):
+      roottype, rootpath = locate_root(cfg, self.rootname)
+      if roottype:
+        # Overlay root-specific options.
         cfg.overlay_root_options(self.rootname)
-        self.rootpath = cfg.general.svn_roots[self.rootname]
+        
+        # Setup an Authorizer for this rootname and username
+        self.auth = setup_authorizer(cfg, self.username, self.rootname)
+
+        # Create the repository object
         try:
-          if re.match(_re_rewrite_url, self.rootpath):
-            # If the rootpath is a URL, we'll use the svn_ra module, but
-            # lie about its name.
-            import vclib.svn_ra
-            vclib.svn = vclib.svn_ra
+          if roottype == 'cvs':
+            self.rootpath = vclib.ccvs.canonicalize_rootpath(rootpath)
+            self.repos = vclib.ccvs.CVSRepository(self.rootname,
+                                                  self.rootpath,
+                                                  self.auth,
+                                                  cfg.utilities,
+                                                  cfg.options.use_rcsparse)
+            # required so that spawned rcs programs correctly expand
+            # $CVSHeader$
+            os.environ['CVSROOT'] = self.rootpath
+          elif roottype == 'svn':
+            self.rootpath = vclib.svn.canonicalize_rootpath(rootpath)
+            self.repos = vclib.svn.SubversionRepository(self.rootname,
+                                                        self.rootpath,
+                                                        self.auth,
+                                                        cfg.utilities,
+                                                        cfg.options.svn_config_dir)
           else:
-            self.rootpath = os.path.normpath(self.rootpath)
-            import vclib.svn
-          self.repos = vclib.svn.SubversionRepository(self.rootname,
-                                                      self.rootpath,
-                                                      cfg.utilities)
+            raise vclib.ReposNotFound()
         except vclib.ReposNotFound:
-          raise debug.ViewVCException(
-            'Unable to locate Subversion root "%s".  Possible causes include '
-            'having an incorrectly configured path for this root, or the '
-            'server on which the repository lives being inaccessible.' \
-            % self.rootname)
-        except vclib.InvalidRevision, ex:
-          raise debug.ViewVCException(str(ex))
-      else:
+          pass
+      if self.repos is None:
         raise debug.ViewVCException(
           'The root "%s" is unknown. If you believe the value is '
           'correct, then please double-check your configuration.'
-          % self.rootname, "404 Repository not found")
+          % self.rootname, "404 Not Found")
 
     if self.repos:
+      self.repos.open()
       type = self.repos.roottype()
       if type == vclib.SVN:
         self.roottype = 'svn'
@@ -290,9 +278,6 @@
           'The root "%s" has an unknown type (%s).' % (self.rootname, type),
           "500 Internal Server Error")
       
-    if self.rootname and cfg.options.authorizer:
-      self.auth = setup_authorizer(cfg, self.username, self.repos)
-
     # If this is using an old-style 'rev' parameter, redirect to new hotness.
     # Subversion URLs will now use 'pathrev'; CVS ones use 'revision'.
     if self.repos and self.query_dict.has_key('rev'):
@@ -307,37 +292,43 @@
       needs_redirect = 1
 
     if self.repos and self.view_func is not redirect_pathrev:
+      # If this is an intended-to-be-hidden CVSROOT path, complain.
+      if cfg.options.hide_cvsroot \
+         and is_cvsroot_path(self.roottype, path_parts):
+        raise debug.ViewVCException("Unknown location: /%s" % self.where,
+                                    "404 Not Found")
+
       # Make sure path exists
       self.pathrev = pathrev = self.query_dict.get('pathrev')
       self.pathtype = _repos_pathtype(self.repos, path_parts, pathrev)
 
       if self.pathtype is None:
-        # path doesn't exist, see if it could be an old-style ViewVC URL
-        # with a fake suffix
-        result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE,      \
-                               self.repos, view_diff) or                      \
-                 _strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR,     \
-                               self.repos, download_tarball) or               \
-                 _strip_suffix('root.tar.gz', path_parts, pathrev, vclib.DIR, \
-                               self.repos, download_tarball) or               \
-                 _strip_suffix(self.rootname + '-root.tar.gz',                \
-                               path_parts, pathrev, vclib.DIR,                \
-                               self.repos, download_tarball) or               \
-                 _strip_suffix('root',                                        \
-                               path_parts, pathrev, vclib.DIR,                \
-                               self.repos, download_tarball) or               \
-                 _strip_suffix(self.rootname + '-root',                       \
-                               path_parts, pathrev, vclib.DIR,                \
+        # Path doesn't exist, see if it could be an old-style ViewVC URL
+        # with a fake suffix.
+        result = _strip_suffix('.diff', path_parts, pathrev, vclib.FILE,     \
+                               self.repos, view_diff) or                     \
+                 _strip_suffix('.tar.gz', path_parts, pathrev, vclib.DIR,    \
+                               self.repos, download_tarball) or              \
+                 _strip_suffix('root.tar.gz', path_parts, pathrev, vclib.DIR,\
+                               self.repos, download_tarball) or              \
+                 _strip_suffix(self.rootname + '-root.tar.gz',               \
+                               path_parts, pathrev, vclib.DIR,               \
+                               self.repos, download_tarball) or              \
+                 _strip_suffix('root',                                       \
+                               path_parts, pathrev, vclib.DIR,               \
+                               self.repos, download_tarball) or              \
+                 _strip_suffix(self.rootname + '-root',                      \
+                               path_parts, pathrev, vclib.DIR,               \
                                self.repos, download_tarball)
         if result:
           self.path_parts, self.pathtype, self.view_func = result
           self.where = _path_join(self.path_parts)
           needs_redirect = 1
         else:
-          raise debug.ViewVCException('%s: unknown location'
-                                       % self.where, '404 Not Found')
+          raise debug.ViewVCException("Unknown location: /%s" % self.where,
+                                      "404 Not Found")
 
-      # If we have an old ViewCVS Attic URL which is still valid, then redirect
+      # If we have an old ViewCVS Attic URL which is still valid, redirect
       if self.roottype == 'cvs':
         attic_parts = None
         if (self.pathtype == vclib.FILE and len(self.path_parts) > 1
@@ -351,13 +342,6 @@
           self.where = _path_join(attic_parts)
           needs_redirect = 1
 
-    # Check authorization for files and directories.
-    if self.path_parts:
-      if not self.auth.check_path_access(self.path_parts):
-        path = _path_join(self.path_parts)
-        raise debug.ViewVCNotAuthorizedException(self.username,
-                                                 'path "%s"' % (path))
-    
     if self.view_func is None:
       # view parameter is not set, try looking at pathtype and the 
       # other parameters
@@ -381,19 +365,26 @@
             self.view_func = view_cvsgraph_image
         elif self.query_dict.has_key('revision') \
                  or cfg.options.default_file_view != "log":
-          if self.query_dict.get('content-type', None) in (viewcvs_mime_type,
-                                                           alt_mime_type):
+          if cfg.options.default_file_view == "markup" \
+             or self.query_dict.get('content-type', None) \
+                 in (viewcvs_mime_type, alt_mime_type):
             self.view_func = view_markup
           else:
             self.view_func = view_checkout
         else:
           self.view_func = view_log
 
+    # If we've chosen the roots or revision view, our effective
+    # location is not really "inside" the repository, so we have no
+    # path and therefore no path parts or type, either.
+    if self.view_func is view_revision or self.view_func is view_roots:
+      self.where = ''
+      self.path_parts = []
+      self.pathtype = None
+      
     # if we have a directory and the request didn't end in "/", then redirect
     # so that it does.
     if (self.pathtype == vclib.DIR and path_info[-1:] != '/'
-        and self.view_func is not view_revision
-        and self.view_func is not view_roots
         and self.view_func is not download_tarball
         and self.view_func is not redirect_pathrev):
       needs_redirect = 1
@@ -402,14 +393,10 @@
     if needs_redirect:
       self.server.redirect(self.get_url())
 
-    # Finally done parsing query string, set mime type and call view_func
-    self.mime_type = None
-    if self.pathtype == vclib.FILE:
-      self.mime_type = guess_mime(self.where)
-
     # startup is done now.
     debug.t_end('startup')
     
+    # Call the function for the selected view.
     self.view_func(self)
 
   def get_url(self, escape=0, partial=0, prefix=0, **args):
@@ -438,13 +425,16 @@
 
   def get_form(self, **args):
     """Constructs a link to another ViewVC page just like the get_link
-    function except that it returns a base URL suitable for use as an HTML
-    form action and a string of HTML input type=hidden tags with the link
-    parameters."""
+    function except that it returns a base URL suitable for use as an
+    HTML form action, and an iterable object with .name and .value
+    attributes representing stuff that should be in <input
+    type=hidden> tags with the link parameters."""
 
     url, params = apply(self.get_link, (), args)
     action = self.server.escape(urllib.quote(url, _URL_SAFE_CHARS))
-    hidden_values = prepare_hidden_values(params)
+    hidden_values = []
+    for name, value in params.items():
+      hidden_values.append(_item(name=name, value=value))
     return action, hidden_values
 
   def get_link(self, view_func=None, where=None, pathtype=None, params=None):
@@ -526,15 +516,8 @@
     if where:
       url = url + '/' + where
 
-    # add suffix for tarball
-    if view_func is download_tarball:
-      if not where and not cfg.options.root_as_url_component:
-        url = url + '/' + rootname + '-root'
-        params['parent'] = '1'
-      url = url + '.tar.gz'
-
     # add trailing slash for a directory
-    elif pathtype == vclib.DIR:
+    if pathtype == vclib.DIR:
       url = url + '/'
 
     # normalize top level URLs for use in Location headers and A tags
@@ -563,13 +546,19 @@
       view_func = None
 
     # no need to explicitly specify checkout view when it's the default
-    # view, when checkout_magic is enabled, or when "revision" is present
+    # view or when checkout_magic is enabled
     if view_func is view_checkout:
-      if ((cfg.options.default_file_view != "log" and pathtype == vclib.FILE)
-          or cfg.options.checkout_magic
-          or params.get('revision') is not None):
+      if ((cfg.options.default_file_view == "co" and pathtype == vclib.FILE)
+          or cfg.options.checkout_magic):
         view_func = None
 
+    # no need to explicitly specify markup view when it's the default view
+    if view_func is view_markup:
+      if (cfg.options.default_file_view == "markup" \
+          and pathtype == vclib.FILE):
+        view_func = None
+
+    # set the view parameter
     view_code = _view_codes.get(view_func)
     if view_code and not (params.has_key('view') and params['view'] is None):
       params['view'] = view_code
@@ -662,7 +651,8 @@
 _re_validate_mimetype = re.compile('^[-_.a-zA-Z0-9/]+$')
 
 # date time values
-_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d(:\d\d)?)?)?$')
+_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d'
+                                   '(:\d\d)?)?)?$')
 
 # the legal query parameters and their validation functions
 _legal_params = {
@@ -681,17 +671,13 @@
   'pathrev'       : _re_validate_revnum,
   'dir_pagestart' : _re_validate_number,
   'log_pagestart' : _re_validate_number,
-  'hidecvsroot'   : _re_validate_number,
   'annotate'      : _re_validate_revnum,
   'graph'         : _re_validate_revnum,
   'makeimage'     : _re_validate_number,
-  'tarball'       : _re_validate_number,
-  'parent'        : _re_validate_number,
   'r1'            : _re_validate_revnum,
   'tr1'           : _re_validate_revnum,
   'r2'            : _re_validate_revnum,
   'tr2'           : _re_validate_revnum,
-  'rev'           : _re_validate_revnum,
   'revision'      : _re_validate_revnum,
   'content-type'  : _re_validate_mimetype,
 
@@ -718,6 +704,12 @@
   'orig_pathtype' : None,
   'orig_pathrev'  : None,
   'orig_view'     : None,
+
+  # deprecated
+  'parent'        : _re_validate_number,
+  'rev'           : _re_validate_revnum,
+  'tarball'       : _re_validate_number,
+  'hidecvsroot'   : _re_validate_number,
   }
 
 def _path_join(path_parts):
@@ -726,6 +718,8 @@
 def _strip_suffix(suffix, path_parts, rev, pathtype, repos, view_func):
   """strip the suffix from a repository path if the resulting path
   is of the specified type, otherwise return None"""
+  if not path_parts:
+    return None
   l = len(suffix)
   if path_parts[-1][-l:] == suffix:
     path_parts = path_parts[:]
@@ -739,7 +733,8 @@
   return None
 
 def _repos_pathtype(repos, path_parts, rev):
-  """return the type of a repository path, or None if the path doesn't exist"""
+  """Return the type of a repository path, or None if the path doesn't
+  exist"""
   try:
     return repos.itemtype(path_parts, rev)
   except vclib.ItemNotFound:
@@ -786,38 +781,42 @@
       rev = request.repos._getrev(rev)
     except vclib.InvalidRevision:
       raise debug.ViewVCException('Invalid revision', '404 Not Found')
-    return _path_parts(vclib.svn.get_location(request.repos, path, 
-                                              pathrev, rev)), rev
+    return _path_parts(request.repos.get_location(path, pathrev, rev)), rev
   return _path_parts(path), rev
 
-def setup_authorizer(cfg, username, root, params={}):
-  rootname = root.rootname()
+def setup_authorizer(cfg, username, rootname):
+  import imp
+  
+  # No configured authorizer?  No problem.
+  if not cfg.options.authorizer:
+    return None
 
   # First, try to load a module with the configured name.
+  fp = None
   try:
-    exec('import vcauth.%s' % (cfg.options.authorizer))
-  except ImportError:
-    raise debug.ViewVCException(
-      'Invalid authorizer (%s) specified for root "%s"' \
-      % (cfg.options.authorizer, rootname),
-      '500 Internal Server Error')
+    try:
+      fp, path, desc = imp.find_module("%s" % (cfg.options.authorizer),
+                                       vcauth.__path__)
+      my_auth = imp.load_module('viewvc', fp, path, desc)
+    except ImportError:
+      raise debug.ViewVCException(
+        'Invalid authorizer (%s) specified for root "%s"' \
+        % (cfg.options.authorizer, rootname),
+        '500 Internal Server Error')
+  finally:
+    if fp:
+      fp.close()
 
   # Now we'll get custom parameters for our particular root.
-  exec('my_auth = vcauth.%s' % (cfg.options.authorizer))
   params = cfg.get_authorizer_params(cfg.options.authorizer, rootname)
 
   # Finally, instantiate our Authorizer.
-  try:
-    return my_auth.ViewVCAuthorizer(username, root, params)
-  except vcauth.ViewVCRootAccessNotAuthorized:
-    raise debug.ViewVCNotAuthorizedException(username,
-                                             'root "%s"' % (rootname))
+  return my_auth.ViewVCAuthorizer(username, params)
 
 def check_freshness(request, mtime=None, etag=None, weak=0):
-  # See if we are supposed to disable etags (for debugging, usually)
-
   cfg = request.cfg
 
+  # See if we are supposed to disable etags (for debugging, usually)
   if not cfg.options.generate_etags:
     return 0
   
@@ -863,18 +862,18 @@
   return isfresh
 
 def get_view_template(cfg, view_name, language="en"):
-  # see if the configuration specifies a template for this view
-  tname = vars(cfg.templates).get(view_name)
+  # See if the configuration specifies a template for this view.  If
+  # not, use the default template path for this view.
+  tname = vars(cfg.templates).get(view_name) or view_name + ".ezt"
+
+  # Template paths are relative to the configurated template_dir (if
+  # any, "templates" otherwise), so build the template path as such.
+  tname = os.path.join(cfg.options.template_dir or "templates", tname)
 
-  # if there is no specific template definition for this view, look in
-  # the default location (relative to the configured template_dir)
-  if not tname:
-    tname = os.path.join(cfg.options.template_dir, view_name + ".ezt")
-
-  # allow per-language template selection
+  # Allow per-language template selection.
   tname = string.replace(tname, '%lang%', language)
 
-  # finally, construct the whole template path.
+  # Finally, construct the whole template path.
   tname = cfg.path(tname)
 
   debug.t_start('ezt-parse')
@@ -883,13 +882,28 @@
 
   return template
 
-def generate_page(request, view_name, data, content_type=None):
+def get_writeready_server_file(request, content_type=None):
+  """Return a file handle to a response body stream, after outputting
+  any queued special headers (on REQUEST.server) and (optionally) a
+  'Content-Type' header whose value is CONTENT_TYPE.  After this is
+  called, it is too late to add new headers to the response."""
+  if request.gzip_compress_level:
+    request.server.addheader('Content-Encoding', 'gzip')
   if content_type:
     request.server.header(content_type)
   else:
     request.server.header()
+  if request.gzip_compress_level:
+    fp = gzip.GzipFile('', 'wb', request.gzip_compress_level,
+                       request.server.file())
+  else:
+    fp = request.server.file()
+  return fp
+  
+def generate_page(request, view_name, data, content_type=None):
+  server_fp = get_writeready_server_file(request)
   template = get_view_template(request.cfg, view_name, request.language)
-  template.generate(request.server.file(), data)
+  template.generate(server_fp, data)
 
 def nav_path(request):
   """Return current path as list of items with "name" and "href" members
@@ -958,6 +972,9 @@
 def is_text(mime_type):
   return not mime_type or mime_type[:5] == 'text/'
 
+def is_cvsroot_path(roottype, path_parts):
+  return roottype == 'cvs' and path_parts and path_parts[0] == 'CVSROOT'
+
 def is_plain_text(mime_type):
   return not mime_type or mime_type == 'text/plain'
 
@@ -979,10 +996,15 @@
   """Return common hrefs and a viewability flag used for various views
   of FILENAME at revision REV whose MIME type is MIME_TYPE."""
   rev = rev and str(rev) or None
-  mime_type = mime_type or request.mime_type
+  mime_type = mime_type or guess_mime(where)
   if pathrev == -1: # cheesy default value, since we need to preserve None
     pathrev = request.pathrev
-  view_href = download_href = download_text_href = annotate_href = revision_href = None
+
+  view_href = None
+  download_href = None
+  download_text_href = None
+  annotate_href = None
+  revision_href = None
 
   if 'markup' in request.cfg.options.allowed_views:
     view_href = request.get_url(view_func=view_markup,
@@ -1032,29 +1054,43 @@
                              '(#([-a-zA-Z0-9%.~:_]+)?)?)')
 _re_rewrite_email = re.compile('([-a-zA-Z0-9_.\+]+)@'
                                '(([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
+
+def mangle_email_addresses(text, style=0):
+  # style=2:  truncation mangling
+  if style == 2: 
+    return re.sub(_re_rewrite_email, r'\1&#64;&hellip;', text)
+
+  # style=1:  entity-encoding and at-wrapping    
+  if style == 1: 
+    def _match_replace(matchobj):
+      return string.join(map(lambda x: '&#%d;' % (ord(x)),
+                             matchobj.group(1)), '') \
+             + ' {at} ' + \
+             string.join(map(lambda x: '&#%d;' % (ord(x)),
+                             matchobj.group(2)), '')
+    return re.sub(_re_rewrite_email, _match_replace, text)
+
+  # otherwise, no mangling
+  return text
+
 def htmlify(html, mangle_email_addrs=0):
   if not html:
     return html
   html = cgi.escape(html)
   html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
-  if mangle_email_addrs:
-    ### FIXME: I'm sure email address mangling comes in a hundred
-    ### different flavors.  As a mechanism for defeating spam
-    ### harvesters, I suspect that merely obscuring the address only
-    ### works for a season (until the obscurity algorithm is added to
-    ### the spammers' databases of such things).  We have to actually
-    ### *lose* information here for it really matter.
-    html = re.sub(_re_rewrite_email, r'\1&#64;&hellip;', html)
-  else:
-    html = re.sub(_re_rewrite_email,
-                  r'<a href="mailto:\1&#64;\2";>\1&#64;\2</a>', html)
+  html = mangle_email_addresses(html, mangle_email_addrs)
   return html
 
-def format_log(log, cfg):
+def format_log(log, cfg, htmlize=1):
   if not log:
     return log
-  s = htmlify(log[:cfg.options.short_log_len],
-              cfg.options.mangle_email_addresses)
+  if htmlize:
+    s = htmlify(log[:cfg.options.short_log_len],
+                cfg.options.mangle_email_addresses)
+  else:
+    s = cgi.escape(log[:cfg.options.short_log_len])
+    if cfg.options.mangle_email_addresses == 2:
+      s = re.sub(_re_rewrite_email, r'\1    ', s)
   if len(log) > cfg.options.short_log_len:
     s = s + '...'
   return s
@@ -1117,7 +1153,7 @@
       s = s + ', ' + ext
   return s
 
-def common_template_data(request):
+def common_template_data(request, revision=None, mime_type=None):
   cfg = request.cfg
   data = {
     'cfg' : cfg,
@@ -1126,14 +1162,17 @@
     'docroot' : cfg.options.docroot is None                        \
                 and request.script_name + '/' + docroot_magic_path \
                 or cfg.options.docroot,
+    'username' : request.username,
     'where' : request.server.escape(request.where),
     'roottype' : request.roottype,
-    'rootname' : request.server.escape(request.rootname),
+    'rootname' : request.rootname \
+                 and request.server.escape(request.rootname) or None,
     'rootpath' : request.rootpath,
     'pathtype' : None,
     'nav_path' : nav_path(request),
     'view'     : _view_codes[request.view_func],
     'rev'      : None,
+    'lockinfo' : None,
     'view_href' : None,
     'annotate_href' : None,
     'download_href' : None,
@@ -1146,10 +1185,13 @@
     'log_href_rev': None,
     'graph_href': None,
     'rss_href' : None,
+    'roots_href' : request.get_url(view_func=view_roots, escape=1, params={}),
     'prefer_markup' : ezt.boolean(0),
   }
 
-  rev = request.query_dict.get('annotate')
+  rev = revision
+  if not rev:
+    rev = request.query_dict.get('annotate')
   if not rev:
     rev = request.query_dict.get('revision')
   if not rev and request.roottype == 'svn':
@@ -1159,33 +1201,12 @@
                   and request.repos._getrev(rev) or rev
   except vclib.InvalidRevision:
     raise debug.ViewVCException('Invalid revision', '404 Not Found')
+
   if request.pathtype == vclib.DIR:
     data['pathtype'] = 'dir'
   elif request.pathtype == vclib.FILE:
     data['pathtype'] = 'file'
 
-  data['change_root_action'], data['change_root_hidden_values'] = \
-    request.get_form(view_func=view_directory, where='', pathtype=vclib.DIR,
-                     params={'root': None})
-
-  # add in the roots for the selection
-  roots = []
-  allroots = list_roots(cfg)
-  if len(allroots):
-    rootnames = allroots.keys()
-    rootnames.sort(icmp)
-    for rootname in rootnames:
-      href = request.get_url(view_func=view_directory,
-                             where='', pathtype=vclib.DIR,
-                             params={'root': rootname}, escape=1)
-
-      ### TODO: Check root authorization.
-      roots.append(_item(name=request.server.escape(rootname),
-                         type=allroots[rootname][1],
-                         path=allroots[rootname][0],
-                         href=href))
-  data['roots'] = roots
-
   if request.path_parts:
     dir = _path_join(request.path_parts[:-1])
     data['up_href'] = request.get_url(view_func=view_directory,
@@ -1195,13 +1216,21 @@
   if request.pathtype == vclib.FILE:
     data['view_href'], data['download_href'], data['download_text_href'], \
       data['annotate_href'], data['revision_href'], data['prefer_markup'] \
-        = get_file_view_info(request, request.where,
-                             data['rev'], request.mime_type)
+        = get_file_view_info(request, request.where, data['rev'], mime_type)
     data['log_href'] = request.get_url(view_func=view_log,
                                        params={}, escape=1)
     if request.roottype == 'cvs' and cfg.options.use_cvsgraph:
       data['graph_href'] = request.get_url(view_func=view_cvsgraph,
                                            params={}, escape=1)
+    file_data = request.repos.listdir(request.path_parts[:-1],
+                                      request.pathrev, {})
+    def _only_this_file(item):
+      return item.name == request.path_parts[-1]
+    entries = filter(_only_this_file, file_data)
+    if len(entries) == 1:
+      request.repos.dirlogs(request.path_parts[:-1], request.pathrev,
+                            entries, {})
+      data['lockinfo'] = entries[0].lockinfo
   elif request.pathtype == vclib.DIR:
     data['view_href'] = request.get_url(view_func=view_directory,
                                        params={}, escape=1)
@@ -1211,22 +1240,35 @@
                                              escape=1)
     if request.roottype == 'svn':
       data['revision_href'] = request.get_url(view_func=view_revision,
-                                              params={}, escape=1)
+                                              params={'revision': data['rev']},
+                                              escape=1)
 
       data['log_href'] = request.get_url(view_func=view_log,
                                          params={}, escape=1)
 
-  if is_query_supported(request):
-    params = {}
-    if request.roottype == 'cvs' and request.pathrev:
-      params['branch'] = request.pathrev
-    data['queryform_href'] = request.get_url(view_func=view_queryform,
-                                             params=params,
-                                             escape=1)
-    data['rss_href'] = request.get_url(view_func=view_query,
-                                       params={'date': 'month',
-                                               'format': 'rss'},
-                                       escape=1)
+  if is_querydb_nonempty_for_root(request):
+    if request.pathtype == vclib.DIR:
+      params = {}
+      if request.roottype == 'cvs' and request.pathrev:
+        params['branch'] = request.pathrev
+      data['queryform_href'] = request.get_url(view_func=view_queryform,
+                                               params=params,
+                                               escape=1)
+      data['rss_href'] = request.get_url(view_func=view_query,
+                                         params={'date': 'month',
+                                                 'format': 'rss'},
+                                         escape=1)
+    elif request.pathtype == vclib.FILE:
+      parts = _path_parts(request.where)
+      where = _path_join(parts[:-1])
+      data['rss_href'] = request.get_url(view_func=view_query,
+                                         where=where,
+                                         pathtype=request.pathtype,
+                                         params={'date': 'month',
+                                                 'format': 'rss',
+                                                 'file': parts[-1],
+                                                 'file_match': 'exact'},
+                                         escape=1)
   return data
 
 def retry_read(src, reqlen=CHUNK_SIZE):
@@ -1268,185 +1310,88 @@
     if self.posttext:
       ctx.fp.write(self.posttext)
 
-class MarkupShell:
-  """A EZT callback object slamming file contents through shell tools."""
-
-  def __init__(self, cfg, fp, cmds):
-    self.fp = fp
-    self.cmds = cmds
-    self.cfg = cfg
-
-  def __call__(self, ctx):
-    ctx.fp.flush()
-    try:
-      pipe = popen.pipe_cmds(self.cmds, ctx.fp)
-      try:
-        if self.fp:
-          copy_stream(self.fp, pipe, self.cfg)
-          self.fp.close()
-          self.fp = None
-      finally:
-        pipe.close()
-    except IOError:
-      raise debug.ViewVCException \
-        ('Error running external program. Command line was: "%s"'
-         % string.join(map(lambda args: string.join(args, ' '), self.cmds),
-                       ' | '))
-
-  def __del__(self):
-    self.close()
-
-  def close(self):
-    if self.fp:
-      self.fp.close()
-      self.fp = None
-
-class MarkupEnscript(MarkupShell):
-  def __init__(self, cfg, fp, filename):
-    
-    # I've tried to pass option '-C' to enscript to generate line numbers
-    # Unfortunately this option doesn't work with HTML output in enscript
-    # version 1.6.2.
-    enscript_cmd = [cfg.utilities.enscript or 'enscript',
-                    '--color', '--language=html', '--pretty-print',
-                    '-o', '-', '-']
-
-    ### I'd like to also strip the <PRE> and </PRE> tags, too, but
-    ### can't come up with a suitable sed expression.  Using
-    ### '1,/^<PRE>$/d;/<\\/PRE>/,$d;p' gets me most of the way, but
-    ### will drop the last line of a non-newline-terminated filed.
-    sed_cmd = [cfg.utilities.sed or 'sed', '-n', '/^<PRE>$/,/<\\/PRE>$/p']
-
-    MarkupShell.__init__(self, cfg, fp, [enscript_cmd, sed_cmd])
-    self.filename = filename
-    self.cfg = cfg
-
-  def __call__(self, ctx):
-    # create a temporary file with the same name as the file in
-    # the repository so enscript can detect file type correctly
-    dir = compat.mkdtemp("", "viewvc")
-    try:
-      file = os.path.join(dir, self.filename)
-      try:
-        copy_stream(self.fp, open(file, 'wb'), self.cfg)
-        self.fp.close()
-        self.fp = None
-        self.cmds[0][-1] = file
-        MarkupShell.__call__(self, ctx)
-      finally:
-        os.unlink(file)
-    finally:
-      os.rmdir(dir)
-
-class MarkupPHP(MarkupShell):
-  def __init__(self, cfg, fp):
-    php_cmd = [cfg.utilities.php or 'php', '-q', '-s', '-n']
-    MarkupShell.__init__(self, cfg, fp, [php_cmd])
-
-class MarkupHighlight(MarkupShell):
-  def __init__(self, cfg, fp, filename):
-    highlight_cmd = [cfg.utilities.highlight or 'highlight',
-                     '--force', '--anchors', '--fragment', '--xhtml']
-
-    if cfg.options.highlight_line_numbers:
-      highlight_cmd.extend(['--linenumbers'])
-
-    if cfg.options.highlight_convert_tabs:
-      highlight_cmd.extend(['--replace-tabs',
-                            str(cfg.options.highlight_convert_tabs)])
-
-    highlight_cmd.extend(['-'])
-    MarkupShell.__init__(self, cfg, fp, [highlight_cmd])
-    self.filename = filename
-    self.cfg = cfg
-
-  def __call__(self, ctx):
-    # create a temporary file with the same name as the file in
-    # the repository so highlight can detect file type correctly
-    dir = compat.mkdtemp("", "viewvc")
+def markup_stream_pygments(request, cfg, blame_data, fp, filename, mime_type):
+  # Determine if we should use Pygments to highlight our output.
+  # Reasons not to include a) being told not to by the configuration,
+  # b) not being able to import the Pygments modules, and c) Pygments
+  # not having a lexer for our file's format.
+  blame_source = []
+  if blame_data:
+    for i in blame_data:
+      i.text = cgi.escape(i.text)
+      i.diff_href = None
+      if i.prev_rev:
+        i.diff_href = request.get_url(view_func=view_diff,
+                                      params={'r1': i.prev_rev,
+                                              'r2': i.rev},
+                                      escape=1, partial=1)
+      blame_source.append(i)
+    blame_data = blame_source
+  lexer = None
+  use_pygments = cfg.options.enable_syntax_coloration
+  try:
+    from pygments import highlight
+    from pygments.formatters import HtmlFormatter
+    from pygments.lexers import ClassNotFound, \
+                                get_lexer_by_name, \
+                                get_lexer_for_mimetype, \
+                                get_lexer_for_filename
     try:
-      file = os.path.join(dir, self.filename)
+      lexer = get_lexer_for_mimetype(mime_type)
+    except ClassNotFound:
       try:
-        copy_stream(self.fp, open(file, 'wb'), self.cfg)
-        self.fp.close()
-        self.fp = None
-        self.cmds[0][-1] = file
-        MarkupShell.__call__(self, ctx)
-      finally:
-        os.unlink(file)
-    finally:
-      os.rmdir(dir)
-
-class MarkupSourceHighlight(MarkupShell):
-  def __init__(self, cfg, fp, filename):
-    basename, ext = os.path.splitext(filename)
-    if ext:
-      ext = ext[1:]
-
-    ### Ideally, we'd use '--output xhtml-css', which would let us supply
-    ### supply our own style definitions.  Unfortunately, this appears to
-    ### be broken in source-highlight 2.3, 2.4, and 2.5 (at least).  :-(
-    highlight_cmd = [cfg.utilities.source_highlight or 'source-highlight',
-                     '--out-format', 'xhtml', '--output', 'STDOUT',
-                     '-s', ext, '--failsafe']
-    if cfg.options.source_highlight_line_numbers:
-      highlight_cmd.extend(['--line-number-ref=l_'])
-
-    sed_cmd = [cfg.utilities.sed or 'sed',
-               '-n',
-               '/^<pre><tt>/,/<\\/tt><\\/pre>$/p']
-
-    MarkupShell.__init__(self, cfg, fp, [highlight_cmd, sed_cmd])
-
-def markup_stream_python(fp, cfg):
-  if not cfg.options.use_py2html:
-    return None
-  
-  ### Convert this code to use the recipe at:
-  ###     http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
-  ### Note that the cookbook states all the code is licensed according to
-  ### the Python license.
-  try:
-    # See if Marc-Andre Lemburg's py2html stuff is around.
-    # http://www.egenix.com/files/python/SoftwareDescriptions.html#py2html.py
-    ### maybe restrict the import to *only* this directory?
-    sys.path.insert(0, cfg.utilities.py2html_dir)
-    import py2html
-    import PyFontify
+        lexer = get_lexer_for_filename(filename)
+      except ClassNotFound:
+        use_pygments = 0
   except ImportError:
-    return None
+    use_pygments = 0
 
-  ### It doesn't escape stuff quite right, nor does it munge URLs and
-  ### mailtos as well as we do.
-  html = cgi.escape(fp.read())
-  pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
-  pp.set_mode_rawhtml_color()
-  html = pp.fontify(html)
-  html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
-  html = re.sub(_re_rewrite_email, r'<a href="mailto:\1";>\1</a>', html)
-  return html
-
-def markup_stream_php(fp, cfg):
-  if not cfg.options.use_php:
-    return None
-
-  # The following HACK may be be used to allow a PHP CGI executable to be
-  # invoked instead of a CLI executable, on systems that do not have PHP's
-  # CLI (command line interface) installed. Just uncomment the following lines:
-  #os.unsetenv("SERVER_SOFTWARE")
-  #os.unsetenv("SERVER_NAME")
-  #os.unsetenv("GATEWAY_INTERFACE")
-  #os.unsetenv("REQUEST_METHOD")
-  #os.unsetenv("SCRIPT_FILENAME")
-  #os.unsetenv("PATH_TRANSLATED")
-
-  return MarkupPHP(cfg, fp)
-
-markup_streamers = {
-  '.py' : markup_stream_python,
-  '.php' : markup_stream_php,
-  '.inc' : markup_stream_php,
-  }
+  # If we aren't going to be highlighting anything, just return the
+  # BLAME_SOURCE.  If there's no blame_source, we'll generate a fake
+  # one from the file contents we fetch with PATH and REV.
+  if not use_pygments:
+    if blame_source:
+      return blame_source
+    else:
+      lines = []
+      line_no = 0
+      while 1:
+        line = fp.readline()
+        if not line:
+          break
+        line_no = line_no + 1
+        item = vclib.Annotation(cgi.escape(line), line_no,
+                                None, None, None, None)
+        item.diff_href = None
+        lines.append(item)
+    return lines
+
+  # If we get here, we're highlighting something.
+  class PygmentsSink:
+    def __init__(self, blame_data):
+      if blame_data:
+        self.has_blame_data = 1
+        self.blame_data = blame_data
+      else:
+        self.has_blame_data = 0
+        self.blame_data = []
+      self.line_no = 0
+    def write(self, buf):
+      ### FIXME:  Don't bank on write() being called once per line
+      if self.has_blame_data:
+        self.blame_data[self.line_no].text = buf
+      else:
+        item = vclib.Annotation(buf, self.line_no + 1,
+                                None, None, None, None)
+        item.diff_href = None
+        self.blame_data.append(item)
+      self.line_no = self.line_no + 1
+  ps = PygmentsSink(blame_source)
+  highlight(fp.read(), lexer,
+            HtmlFormatter(nowrap=True,
+                          classprefix="pygments-",
+                          encoding='utf-8'), ps)
+  return ps.blame_data
 
 def make_time_string(date, cfg):
   """Returns formatted date string in either local time or UTC.
@@ -1472,24 +1417,88 @@
     return None
   return time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime(date)) + ' UTC'
 
-def view_markup(request):
-  if 'markup' not in request.cfg.options.allowed_views:
-    raise debug.ViewVCException('Markup view is disabled',
-                                 '403 Forbidden')
-    
+def get_itemprops(request, path_parts, rev):
+  itemprops = request.repos.itemprops(path_parts, rev)
+  propnames = itemprops.keys()
+  propnames.sort()
+  props = []
+  has_binary_props = 0
+  for name in propnames:
+    value = itemprops[name]
+    undisplayable = ezt.boolean(0)
+    # skip non-utf8 property names
+    try:
+      unicode(name, 'utf8')
+    except:
+      continue
+    # note non-utf8 property values
+    try:
+      unicode(value, 'utf8')
+    except:
+      value = None
+      undisplayable = ezt.boolean(1)
+    props.append(_item(name=name, value=value, undisplayable=undisplayable))
+  return props
+
+def calculate_mime_type(request, path_parts, rev):
+  mime_type = None
+  if not path_parts:
+    return None
+  if request.roottype == 'svn':
+    try:
+      itemprops = request.repos.itemprops(path_parts, rev)
+      mime_type = itemprops.get('svn:mime-type')
+      if mime_type:
+        return mime_type
+    except:
+      pass
+  return guess_mime(path_parts[-1])
+
+def markup_or_annotate(request, is_annotate):
   cfg = request.cfg
-  path, rev = _orig_path(request)
-  fp, revision = request.repos.openfile(path, rev)
+  path, rev = _orig_path(request, is_annotate and 'annotate' or 'revision')
+  lines = fp = image_src_href = None
+  annotation = None
+  revision = None
+  mime_type = calculate_mime_type(request, path, rev)
 
-  # Since the templates could be changed by the user, we can't provide
-  # a strong validator for this page, so we mark the etag as weak.
-  if check_freshness(request, None, revision, weak=1):
+  # Is this a viewable image type?
+  if is_viewable_image(mime_type) \
+     and 'co' in cfg.options.allowed_views:
+    fp, revision = request.repos.openfile(path, rev)
+    fp.close()
+    if check_freshness(request, None, revision, weak=1):
+      return
+    annotation = 'binary'
+    image_src_href = request.get_url(view_func=view_checkout,
+                                     params={'revision': rev}, escape=1)
+
+  # Not a viewable image.
+  else:
+    blame_source = None
+    if is_annotate:
+      # Try to annotate this file, but don't croak if we fail.
+      try:
+        blame_source, revision = request.repos.annotate(path, rev)
+        annotation = 'annotated'
+        if check_freshness(request, None, revision, weak=1):
+          return
+      except vclib.NonTextualFileContents:
+        annotation = 'binary'
+      except:
+        annotation = 'error'
+
+    fp, revision = request.repos.openfile(path, rev)
+    if check_freshness(request, None, revision, weak=1):
+      fp.close()
+      return
+    lines = markup_stream_pygments(request, cfg, blame_source, fp,
+                                   path[-1], mime_type)
     fp.close()
-    return
 
-  data = common_template_data(request)
+  data = common_template_data(request, revision)
   data.update({
-    'mime_type' : request.mime_type,
+    'mime_type' : mime_type,
     'log' : None,
     'date' : None,
     'ago' : None,
@@ -1504,11 +1513,16 @@
     'prev' : None,
     'orig_path' : None,
     'orig_href' : None,
+    'image_src_href' : image_src_href,
+    'lines' : lines,
+    'properties' : get_itemprops(request, path, rev),
+    'annotation' : annotation,
     })
 
   if cfg.options.show_log_in_markup:
-    options = {'svn_latest_log': 1}
-    revs = request.repos.itemlog(path, revision, options)
+    options = {'svn_latest_log': 1}  ### FIXME: No longer needed?
+    revs = request.repos.itemlog(path, revision, vclib.SORTBY_DEFAULT,
+                                 0, 1, options)
     entry = revs[-1]
     data.update({
         'date' : make_time_string(entry.date, cfg),
@@ -1542,50 +1556,26 @@
                                         pathtype=vclib.FILE,
                                         params={'pathrev': revision},
                                         escape=1)
-
-  markup_fp = None
-  if is_viewable_image(request.mime_type) \
-     and 'co' in cfg.options.allowed_views:
-    fp.close()
-    url = request.get_url(view_func=view_checkout, params={'revision': rev},
-                          escape=1)
-    markup_fp = '<img src="%s" alt="" /><br />' % url
-  else:
-    basename, ext = os.path.splitext(request.path_parts[-1])
-    streamer = markup_streamers.get(ext)
-    if streamer:
-      markup_fp = streamer(fp, cfg)
-
-    # If there wasn't a custom streamer, or the streamer wasn't enabled, we'll
-    # try to use one of the configured syntax highlighting programs.
-    if not markup_fp:
-      if cfg.options.use_enscript:
-        markup_fp = MarkupEnscript(cfg, fp, request.path_parts[-1])
-      elif cfg.options.use_highlight:
-        markup_fp = MarkupHighlight(cfg, fp, request.path_parts[-1])
-      elif cfg.options.use_source_highlight:
-        markup_fp = MarkupSourceHighlight(cfg, fp, request.path_parts[-1])
-      else:
-        # If no one has a suitable markup handler, we'll use the default.
-        markup_fp = MarkupPipeWrapper(cfg, fp)
     
-  data['markup'] = markup_fp
-  generate_page(request, "markup", data)
+  generate_page(request, "file", data)
+  
+def view_markup(request):
+  if 'markup' not in request.cfg.options.allowed_views:
+    raise debug.ViewVCException('Markup view is disabled',
+                                '403 Forbidden')
+  markup_or_annotate(request, 0)
+
+def view_annotate(request):
+  if 'annotate' not in request.cfg.options.allowed_views:
+    raise debug.ViewVCException('Annotation view is disabled',
+                                 '403 Forbidden')
+  markup_or_annotate(request, 1)
 
 def revcmp(rev1, rev2):
   rev1 = map(int, string.split(rev1, '.'))
   rev2 = map(int, string.split(rev2, '.'))
   return cmp(rev1, rev2)
 
-def prepare_hidden_values(params):
-  """returns variables from params encoded as a invisible HTML snippet.
-  """
-  hidden_values = []
-  for name, value in params.items():
-    hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
-                         (name, value))
-  return string.join(hidden_values, '')
-
 def sort_file_data(file_data, roottype, sortdir, sortby, group_dirs):
   # convert sortdir into a sign bit
   s = sortdir == "down" and -1 or 1
@@ -1638,7 +1628,28 @@
   return cmp(string.lower(x), string.lower(y))
 
 def view_roots(request):
+  if 'roots' not in request.cfg.options.allowed_views:
+    raise debug.ViewVCException('Root listing view is disabled',
+                                '403 Forbidden')
+  
+  # add in the roots for the selection
+  roots = []
+  expand_root_parents(request.cfg)
+  allroots = list_roots(request)
+  if len(allroots):
+    rootnames = allroots.keys()
+    rootnames.sort(icmp)
+    for rootname in rootnames:
+      href = request.get_url(view_func=view_directory,
+                             where='', pathtype=vclib.DIR,
+                             params={'root': rootname}, escape=1)
+      roots.append(_item(name=request.server.escape(rootname),
+                         type=allroots[rootname][1],
+                         path=allroots[rootname][0],
+                         href=href))
+
   data = common_template_data(request)
+  data['roots'] = roots
   generate_page(request, "roots", data)
 
 def view_directory(request):
@@ -1650,7 +1661,7 @@
       rev = request.repos._getrev(request.pathrev)
     except vclib.InvalidRevision:
       raise debug.ViewVCException('Invalid revision', '404 Not Found')
-    tree_rev = vclib.svn.created_rev(request.repos, request.where, rev)
+    tree_rev = request.repos.created_rev(request.where, rev)
     if check_freshness(request, None, str(tree_rev), weak=1):
       return
 
@@ -1662,25 +1673,9 @@
                                            cfg.options.hide_attic))
     options["cvs_subdirs"] = (cfg.options.show_subdir_lastmod and
                               cfg.options.show_logs)
-
   file_data = request.repos.listdir(request.path_parts, request.pathrev,
                                     options)
 
-  # Filter file list if a regex is specified
-  search_re = request.query_dict.get('search', '')
-  if cfg.options.use_re_search and search_re:
-    file_data = search_files(request.repos, request.path_parts,
-                             request.pathrev, file_data, search_re)
-
-  # Further filter the file list based on what the user is permitted
-  # to see.  We do this before called dirlogs because it'll save us
-  # some work there, but also so it won't harvest tag/branch names
-  # from unauthorized files.
-  def _auth_filter(item):
-    return request.auth.check_path_access(request.path_parts \
-                                          + [item.name])
-  file_data = filter(_auth_filter, file_data)
-
   # sort with directories first, and using the "sortby" criteria
   sortby = request.query_dict.get('sortby', cfg.options.sort_by) or 'file'
   sortdir = request.query_dict.get('sortdir', 'up')
@@ -1702,6 +1697,8 @@
       file.log = None
       file.author = None
       file.size = None
+      file.lockinfo = None
+      file.dead = None
     sort_file_data(file_data, request.roottype, sortdir, sortby,
                    cfg.options.sort_group_dirs)
     # request dirlogs only for the slice of files in "this page"
@@ -1714,6 +1711,12 @@
                    cfg.options.sort_group_dirs)
   debug.t_end("dirlogs")
 
+  # If a regex is specified, build a compiled form thereof for filtering
+  searchstr = None
+  search_re = request.query_dict.get('search', '')
+  if cfg.options.use_re_search and search_re:
+    searchstr = re.compile(search_re)
+
   # loop through entries creating rows and changing these values
   rows = [ ]
   num_displayed = 0
@@ -1729,7 +1732,10 @@
                 date=None, ago=None, view_href=None, log_href=None,
                 revision_href=None, annotate_href=None, download_href=None,
                 download_text_href=None, prefer_markup=ezt.boolean(0))
-
+    if request.roottype == 'cvs' and file.absent:
+      continue
+    if cfg.options.hide_errorful_entries and file.errors:
+      continue
     row.rev = file.rev
     row.author = file.author
     row.state = (request.roottype == 'cvs' and file.dead) and 'dead' or ''
@@ -1739,7 +1745,7 @@
     if cfg.options.show_logs:
       row.short_log = format_log(file.log, cfg)
       row.log = htmlify(file.log, cfg.options.mangle_email_addresses)
-
+    row.lockinfo = file.lockinfo
     row.anchor = request.server.escape(file.name)
     row.name = request.server.escape(file.name)
     row.pathtype = (file.kind == vclib.FILE and 'file') or \
@@ -1747,9 +1753,9 @@
     row.errors = file.errors
 
     if file.kind == vclib.DIR:
-
-      if (request.roottype == 'cvs' and cfg.options.hide_cvsroot
-          and where == '' and file.name == 'CVSROOT'):
+      if cfg.options.hide_cvsroot \
+         and is_cvsroot_path(request.roottype,
+                             request.path_parts + [file.name]):
         continue
     
       row.view_href = request.get_url(view_func=view_directory,
@@ -1777,19 +1783,25 @@
                                        escape=1)
       
     elif file.kind == vclib.FILE:
-      
+      if searchstr is not None:
+        if request.roottype == 'cvs' and (file.errors or file.dead):
+          continue
+        if not search_file(request.repos, request.path_parts + [file.name],
+                           request.pathrev, searchstr):
+          continue
       if request.roottype == 'cvs' and file.dead:
         num_dead = num_dead + 1
         if hideattic:
           continue
+        
       num_displayed = num_displayed + 1
 
       file_where = where_prefix + file.name
       if request.roottype == 'svn': 
         row.size = file.size
 
-      ### for Subversion, we should first try to get this from the properties
-      row.mime_type = guess_mime(file.name)
+      row.mime_type = calculate_mime_type(request, _path_parts(file_where),
+                                          file.rev)
       row.view_href, row.download_href, row.download_text_href, \
                      row.annotate_href, row.revision_href, \
                      row.prefer_markup \
@@ -1843,6 +1855,7 @@
     'hide_attic_href' : None,
     'branch_tags': None,
     'plain_tags': None,
+    'properties': get_itemprops(request, request.path_parts, request.pathrev),
   })
 
   # clicking on sort column reverses sort order
@@ -1879,7 +1892,7 @@
     data['tree_rev_href'] = request.get_url(view_func=view_revision,
                                             params={'revision': tree_rev},
                                             escape=1)
-    data['youngest_rev'] = vclib.svn.get_youngest_revision(request.repos)
+    data['youngest_rev'] = request.repos.get_youngest_revision()
     data['youngest_rev_href'] = request.get_url(view_func=view_revision,
                                                 params={},
                                                 escape=1)
@@ -1891,8 +1904,7 @@
   pathrev_form(request, data)
 
   ### one day, if EZT has "or" capability, we can lose this
-  data['search_re_form'] = ezt.boolean(cfg.options.use_re_search
-                                       and (num_displayed > 0 or search_re))
+  data['search_re_form'] = ezt.boolean(cfg.options.use_re_search)
   if data['search_re_form']:
     data['search_re_action'], data['search_re_hidden_values'] = \
       request.get_form(params={'search': None})
@@ -1909,7 +1921,7 @@
   # Create the picklist
   picklist = data['picklist'] = []
   for i in range(0, len(data[key]), pagesize):
-    pick = _item(start=None, end=None, count=None)
+    pick = _item(start=None, end=None, count=None, more=ezt.boolean(0))
     pick.start = getattr(data[key][i], local_name)
     pick.count = i
     pick.page = (i / pagesize) + 1
@@ -1932,6 +1944,38 @@
   # Slice
   return data[key][pagestart:pageend]
 
+def paging_sws(data, key, pagestart, local_name, pagesize, offset):
+  """Implement sliding window-style paging."""
+  # Create the picklist
+  last_requested = pagestart + (EXTRA_PAGES * pagesize)
+  picklist = data['picklist'] = []
+  has_more = ezt.boolean(0)
+  for i in range(0, len(data[key]), pagesize):
+    pick = _item(start=None, end=None, count=None, more=ezt.boolean(0))
+    pick.start = getattr(data[key][i], local_name)
+    pick.count = offset + i
+    pick.page = (pick.count / pagesize) + 1
+    try:
+      pick.end = getattr(data[key][i+pagesize-1], local_name)
+    except IndexError:
+      pick.end = getattr(data[key][-1], local_name)   
+    picklist.append(pick)
+    if pick.count >= last_requested:
+      pick.more = ezt.boolean(1)
+      break
+  data['picklist_len'] = len(picklist)
+  first = pagestart - offset
+  # FIXME: first can be greater than the length of data[key] if
+  # you select a tag or search while on a page other than the first.
+  # Should reset to the first page, but this test won't do that every
+  # time that it is needed.  Problem might go away if we don't hide
+  # non-matching files when selecting for tags or searching.
+  if first > len(data[key]):
+    pagestart = 0
+  pageend = first + pagesize
+  # Slice
+  return data[key][first:pageend]
+
 def pathrev_form(request, data):
   lastrev = None
 
@@ -1945,12 +1989,12 @@
                                'orig_view': _view_codes.get(request.view_func)})
 
     if request.pathrev:
-      youngest = vclib.svn.get_youngest_revision(request.repos)
-      lastrev = vclib.svn.last_rev(request.repos, request.where,
-                                   request.pathrev, youngest)[0]
+      youngest = request.repos.get_youngest_revision()
+      lastrev = request.repos.last_rev(request.where, request.pathrev,
+                                       youngest)[0]
 
       if lastrev == youngest:
-         lastrev = None
+        lastrev = None
 
   data['pathrev'] = request.pathrev
   data['lastrev'] = lastrev
@@ -1972,7 +2016,7 @@
   pathrev = request.query_dict.get('orig_pathrev') 
   view = _views.get(request.query_dict.get('orig_view'))
   
-  youngest = vclib.svn.get_youngest_revision(request.repos)
+  youngest = request.repos.get_youngest_revision()
 
   # go out of the way to allow revision numbers higher than youngest
   try:
@@ -1988,8 +2032,7 @@
   if _repos_pathtype(request.repos, _path_parts(path), new_pathrev):
     pathrev = new_pathrev
   else:
-    pathrev, path = vclib.svn.last_rev(request.repos, path, pathrev, 
-                                       new_pathrev)
+    pathrev, path = request.repos.last_rev(path, pathrev, new_pathrev)
     # allow clearing sticky revision by submitting empty string
     if new_pathrev is None and pathrev == youngest:
       pathrev = None
@@ -1999,37 +2042,43 @@
                                           pathtype=pathtype,
                                           params={'pathrev': pathrev}))
 
-def logsort_date_cmp(rev1, rev2):
-  # sort on date; secondary on revision number
-  return -cmp(rev1.date, rev2.date) or -cmp(rev1.number, rev2.number)
-
-def logsort_rev_cmp(rev1, rev2):
-  # sort highest revision first
-  return -cmp(rev1.number, rev2.number)
-
 def view_log(request):
   cfg = request.cfg
   diff_format = request.query_dict.get('diff_format', cfg.options.diff_format)
-  logsort = request.query_dict.get('logsort', cfg.options.log_sort)
   pathtype = request.pathtype
 
-  if pathtype is vclib.DIR and request.roottype == 'cvs':
-    raise debug.ViewVCException('Unsupported feature: log view on CVS '
-                                 'directory', '400 Bad Request')
+  if pathtype is vclib.DIR:
+    if request.roottype == 'cvs':
+      raise debug.ViewVCException('Unsupported feature: log view on CVS '
+                                  'directory', '400 Bad Request')
+    mime_type = None
+  else:
+    mime_type = calculate_mime_type(request, request.path_parts, request.pathrev)
 
   options = {}
   options['svn_show_all_dir_logs'] = 1 ### someday make this optional?
   options['svn_cross_copies'] = cfg.options.cross_copies
-    
+
+  logsort = request.query_dict.get('logsort', cfg.options.log_sort)
+  if request.roottype == "svn":
+    sortby = vclib.SORTBY_DEFAULT
+    logsort = None
+  else:
+    if logsort == 'date':
+      sortby = vclib.SORTBY_DATE
+    elif logsort == 'rev':
+      sortby = vclib.SORTBY_REV
+    else:
+      sortby = vclib.SORTBY_DEFAULT
+
+  first = last = 0
+  if cfg.options.use_pagesize:
+    log_pagestart = int(request.query_dict.get('log_pagestart', 0))
+    first = log_pagestart - min(log_pagestart,
+                                (EXTRA_PAGES * cfg.options.use_pagesize))
+    last = log_pagestart + ((EXTRA_PAGES + 1) * cfg.options.use_pagesize) + 1
   show_revs = request.repos.itemlog(request.path_parts, request.pathrev,
-                                    options)
-  if logsort == 'date':
-    show_revs.sort(logsort_date_cmp)
-  elif logsort == 'rev':
-    show_revs.sort(logsort_rev_cmp)
-  else:
-    # no sorting
-    pass
+                                    sortby, first, last - first, options)
 
   # selected revision
   selected_rev = request.query_dict.get('r1')
@@ -2049,6 +2098,7 @@
       entry.ago = html_time(request, rev.date, 1)
     entry.log = htmlify(rev.log or "", cfg.options.mangle_email_addresses)
     entry.size = rev.size
+    entry.lockinfo = rev.lockinfo
     entry.branch_point = None
     entry.next_main = None
     entry.orig_path = None
@@ -2124,8 +2174,7 @@
     if pathtype is vclib.FILE:
       entry.view_href, entry.download_href, entry.download_text_href, \
         entry.annotate_href, entry.revision_href, entry.prefer_markup \
-        = get_file_view_info(request, request.where, rev.string,
-                             request.mime_type)
+        = get_file_view_info(request, request.where, rev.string, mime_type)
     else:
       entry.revision_href = request.get_url(view_func=view_revision,
                                             params={'revision': rev.string},
@@ -2139,7 +2188,9 @@
     # calculate diff links
     if selected_rev != entry.rev:
       entry.sel_for_diff_href = \
-        request.get_url(view_func=view_log, params={'r1': entry.rev}, escape=1)
+        request.get_url(view_func=view_log,
+                        params={'r1': entry.rev},
+                        escape=1)
     if entry.prev is not None:
       entry.diff_to_prev_href = \
         request.get_url(view_func=view_diff,
@@ -2184,18 +2235,18 @@
   data = common_template_data(request)
   data.update({
     'default_branch' : None,
-    'mime_type' : request.mime_type,
+    'mime_type' : mime_type,
     'rev_selected' : selected_rev,
     'diff_format' : diff_format,
     'logsort' : logsort,
     'human_readable' : ezt.boolean(diff_format in ('h', 'l')),
     'log_pagestart' : None,
     'entries': entries,
-    'prefer_markup' : ezt.boolean(0),
-    'view_href' : None,
-    'download_href': None,
-    'download_text_href': None,
-    'annotate_href': None,
+    'head_prefer_markup' : ezt.boolean(0),
+    'head_view_href' : None,
+    'head_download_href': None,
+    'head_download_text_href': None,
+    'head_annotate_href': None,
     'tag_prefer_markup' : ezt.boolean(0),
     'tag_view_href' : None,
     'tag_download_href': None,
@@ -2205,10 +2256,6 @@
 
   lastrev = pathrev_form(request, data)
 
-  if cfg.options.use_pagesize:
-    data['log_paging_action'], data['log_paging_hidden_values'] = \
-      request.get_form(params={'log_pagestart': None})
-  
   data['diff_select_action'], data['diff_select_hidden_values'] = \
     request.get_form(view_func=view_diff,
                      params={'r1': None, 'r2': None, 'tr1': None,
@@ -2221,20 +2268,19 @@
     if not request.pathrev or lastrev is None:
       view_href, download_href, download_text_href, \
         annotate_href, revision_href, prefer_markup \
-        = get_file_view_info(request, request.where, None,
-                             request.mime_type, None)
+        = get_file_view_info(request, request.where, None, mime_type, None)
       data.update({
-        'view_href': view_href,
-        'download_href': download_href,
-        'download_text_href': download_text_href,
-        'annotate_href': annotate_href,
-        'prefer_markup': prefer_markup,
+        'head_view_href': view_href,
+        'head_download_href': download_href,
+        'head_download_text_href': download_text_href,
+        'head_annotate_href': annotate_href,
+        'head_prefer_markup': prefer_markup,
         })
 
     if request.pathrev and request.roottype == 'cvs':
       view_href, download_href, download_text_href, \
         annotate_href, revision_href, prefer_markup \
-        = get_file_view_info(request, request.where, None, request.mime_type)
+        = get_file_view_info(request, request.where, None, mime_type)
       data.update({
         'tag_view_href': view_href,
         'tag_download_href': download_href,
@@ -2243,8 +2289,8 @@
         'tag_prefer_markup': prefer_markup,
         })
   else:
-    data['view_href'] = request.get_url(view_func=view_directory, 
-                                        params={}, escape=1)
+    data['head_view_href'] = request.get_url(view_func=view_directory, 
+                                             params={}, escape=1)
 
   taginfo = options.get('cvs_tags', {})
   tagitems = taginfo.items()
@@ -2273,9 +2319,11 @@
       plain_tags.append(tag)
 
   if cfg.options.use_pagesize:
+    data['log_paging_action'], data['log_paging_hidden_values'] = \
+      request.get_form(params={'log_pagestart': None})
     data['log_pagestart'] = int(request.query_dict.get('log_pagestart',0))
-    data['entries'] = paging(data, 'entries', data['log_pagestart'],
-                             'rev', cfg.options.use_pagesize)
+    data['entries'] = paging_sws(data, 'entries', data['log_pagestart'],
+                                 'rev', cfg.options.use_pagesize, first)
 
   generate_page(request, "log", data)
 
@@ -2292,96 +2340,13 @@
 
   # The revision number acts as a strong validator.
   if not check_freshness(request, None, revision):
-    request.server.header(request.query_dict.get('content-type')
-                          or request.mime_type or 'text/plain')
-    copy_stream(fp, request.server.file(), cfg)
+    mime_type = request.query_dict.get('content-type') \
+                or calculate_mime_type(request, path, rev) \
+                or 'text/plain'
+    server_fp = get_writeready_server_file(request, mime_type)
+    copy_stream(fp, server_fp, cfg)
   fp.close()
 
-def view_annotate(request):
-  if 'annotate' not in request.cfg.options.allowed_views:
-    raise debug.ViewVCException('Annotation view is disabled',
-                                 '403 Forbidden')
-
-  cfg = request.cfg
-  path, rev = _orig_path(request, 'annotate')
-
-  ### be nice to hook this into the template...
-  import blame
-
-  diff_url = request.get_url(view_func=view_diff,
-                             params={'r1': None, 'r2': None},
-                             escape=1, partial=1)
-
-  include_url = request.get_url(view_func=view_log, where='/WHERE/',
-                                pathtype=vclib.FILE, params={}, escape=1)
-
-  try:
-    source, revision = blame.blame(request.repos, path,
-                                   diff_url, include_url, rev)
-  except vclib.NonTextualFileContents:
-    raise debug.ViewVCException('Unable to perform line-based annotation on '
-                                'non-textual file contents',
-                                '400 Bad Request')
-
-  data = common_template_data(request)
-  data.update({
-    'mime_type' : request.mime_type,
-    'log' : None,
-    'date' : None,
-    'ago' : None,
-    'author' : None,
-    'branches' : None,
-    'tags' : None,
-    'branch_points' : None,
-    'changed' : None,
-    'size' : None,
-    'state' : None,
-    'vendor_branch' : None,
-    'prev' : None,
-    'lines': source,
-    'orig_path': None,
-    'orig_href': None,
-    })
-
-  if cfg.options.show_log_in_markup:
-    options = {'svn_latest_log': 1}
-    revs = request.repos.itemlog(path, revision, options)
-    entry = revs[-1]
-    data.update({
-        'date' : make_time_string(entry.date, cfg),
-        'author' : entry.author,
-        'changed' : entry.changed,
-        'log' : htmlify(entry.log, cfg.options.mangle_email_addresses),
-        'size' : entry.size,
-        })
-
-    if entry.date is not None:
-      data['ago'] = html_time(request, entry.date, 1)
-      
-    if request.roottype == 'cvs':
-      branch = entry.branch_number
-      prev = entry.prev or entry.parent
-      data.update({
-        'state' : entry.dead and 'dead',
-        'prev' : prev and prev.string,
-        'vendor_branch' : ezt.boolean(branch and branch[2] % 2 == 1),
-        'branches' : string.join(map(lambda x: x.name, entry.branches), ', '),
-        'tags' : string.join(map(lambda x: x.name, entry.tags), ', '),
-        'branch_points': string.join(map(lambda x: x.name,
-                                         entry.branch_points), ', ')
-        })
-
-  if path != request.path_parts:
-    orig_path = _path_join(path)
-    data['orig_path'] = orig_path
-    data['orig_href'] = request.get_url(view_func=view_log,
-                                        where=orig_path,
-                                        pathtype=vclib.FILE,
-                                        params={'pathrev': revision},
-                                        escape=1)
-
-  generate_page(request, "annotate", data)
-
 def view_cvsgraph_image(request):
   "output the image rendered by cvsgraph"
   # this function is derived from cgi/cvsgraphmkimg.cgi
@@ -2394,14 +2359,14 @@
   # If cvsgraph can't find its supporting libraries, uncomment and set
   # accordingly.  Do the same in view_cvsgraph().
   #os.environ['LD_LIBRARY_PATH'] = '/usr/lib:/usr/local/lib:/path/to/cvsgraph'
-  
-  request.server.header('image/png')
+
   rcsfile = request.repos.rcsfile(request.path_parts)
   fp = popen.popen(cfg.utilities.cvsgraph or 'cvsgraph',
                    ("-c", cfg.path(cfg.options.cvsgraph_conf),
                     "-r", request.repos.rootpath,
                     rcsfile), 'rb', 0)
-  copy_stream(fp, request.server.file(), cfg)
+  
+  copy_stream(fp, get_writeready_server_file(request, 'image/png'), cfg)
   fp.close()
 
 def view_cvsgraph(request):
@@ -2419,8 +2384,8 @@
   #os.environ['LD_LIBRARY_PATH'] = '/usr/lib:/usr/local/lib:/path/to/cvsgraph'
 
   imagesrc = request.get_url(view_func=view_cvsgraph_image, escape=1)
-
-  view = default_view(request.mime_type, cfg)
+  mime_type = guess_mime(request.where)
+  view = default_view(mime_type, cfg)
   up_where = _path_join(request.path_parts[:-1])
 
   # Create an image map
@@ -2452,58 +2417,23 @@
 
   generate_page(request, "graph", data)
 
-def search_files(repos, path_parts, rev, files, search_re):
-  """ Search files in a directory for a regular expression.
-
-  Does a check-out of each file in the directory.  Only checks for
-  the first match.  
-  """
-
-  # Pass in search regular expression. We check out
-  # each file and look for the regular expression. We then return the data
-  # for all files that match the regex.
-
-  # Compile to make sure we do this as fast as possible.
-  searchstr = re.compile(search_re)
-
-  # Will become list of files that have at least one match.
-  # new_file_list also includes directories.
-  new_file_list = [ ]
-
-  # Loop on every file (and directory)
-  for file in files:
-    # Is this a directory?  If so, append name to new_file_list
-    # and move to next file.
-    if file.kind != vclib.FILE:
-      new_file_list.append(file)
-      continue
-
-    # Only files at this point
-    
-    # Shouldn't search binary files, or should we?
-    # Should allow all text mime types to pass.
-    if not is_text(guess_mime(file.name)):
-      continue
-
-    # Only text files at this point
-
-    # Assign contents of checked out file to fp.
-    fp = repos.openfile(path_parts + [file.name], rev)[0]
-
-    # Read in each line, use re.search to search line.
-    # If successful, add file to new_file_list and break.
-    while 1:
-      line = fp.readline()
-      if not line:
-        break
-      if searchstr.search(line):
-        new_file_list.append(file)
-        # close down the pipe (and wait for the child to terminate)
-        fp.close()
-        break
-
-  return new_file_list
-
+def search_file(repos, path_parts, rev, search_re):
+  """Return 1 iff the contents of the file at PATH_PARTS in REPOS as
+  of revision REV matches regular expression SEARCH_RE."""
+
+  # Read in each line of a checked-out file, and then use re.search to
+  # search line.
+  fp = repos.openfile(path_parts, rev)[0]
+  matches = 0
+  while 1:
+    line = fp.readline()
+    if not line:
+      break
+    if search_re.search(line):
+      matches = 1
+      fp.close()
+      break
+  return matches
 
 def view_doc(request):
   """Serve ViewVC static content locally.
@@ -2537,16 +2467,16 @@
 
   request.server.addheader('Content-Length', content_length)
   if document[-3:] == 'png':
-    request.server.header('image/png')
+    mime_type = 'image/png'
   elif document[-3:] == 'jpg':
-    request.server.header('image/jpeg')
+    mime_type = 'image/jpeg'
   elif document[-3:] == 'gif':
-    request.server.header('image/gif')
+    mime_type = 'image/gif'
   elif document[-3:] == 'css':
-    request.server.header('text/css')
+    mime_type = 'text/css'
   else: # assume HTML:
-    request.server.header()
-  copy_stream(fp, request.server.file(), cfg)
+    mime_type = None
+  copy_stream(fp, get_writeready_server_file(request, mime_type), cfg)
   fp.close()
 
 def rcsdiff_date_reformat(date_str, cfg):
@@ -2782,33 +2712,21 @@
 
 
 def _get_diff_path_parts(request, query_key, rev, base_rev):
+  repos = request.repos
   if request.query_dict.has_key(query_key):
-    path = request.query_dict[query_key]
-    parts = _path_parts(path)
-    if not request.auth.check_path_access(parts):
-      raise debug.ViewVCNotAuthorizedException(self.username,
-                                               'file "%s"' % (path))
+    parts = _path_parts(request.query_dict[query_key])
   elif request.roottype == 'svn':
     try:
-      repos = request.repos
-      path = vclib.svn.get_location(repos, request.where,
-                                    repos._getrev(base_rev),
-                                    repos._getrev(rev))
-      parts = _path_parts(path)      
-      if not request.auth.check_path_access(parts):
-        raise debug.ViewVCNotAuthorizedException(self.username,
-                                                 'file "%s"' % (path))
+      parts = _path_parts(repos.get_location(request.where,
+                                             repos._getrev(base_rev),
+                                             repos._getrev(rev)))
     except vclib.InvalidRevision:
       raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
                                    'to diff', '400 Bad Request')
     except vclib.ItemNotFound:
       raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
                                    'to diff', '400 Bad Request')
-    if not request.auth.check_path_access(parts):
-      raise debug.ViewVCException('Invalid path(s) or revision(s) passed '
-                                   'to diff', '400 Bad Request')
   else:
-    # NOTE: authorization already checked in run_viewvc()
     parts = request.path_parts
   return parts
 
@@ -2897,9 +2815,9 @@
   date1, date2, flag, headers = diff_parse_headers(fp, diff_type, rev1, rev2,
                                                    sym1, sym2)
 
-  request.server.header('text/plain')
-  request.server.file().write(headers)
-  copy_stream(fp, request.server.file(), cfg)
+  server_fp = get_writeready_server_file(request, 'text/plain')
+  server_fp.write(headers)
+  copy_stream(fp, server_fp, cfg)
   fp.close()
 
 
@@ -2974,7 +2892,8 @@
   path_left = _path_join(p1)
   path_right = _path_join(p2)
   if fp:
-    date1, date2, flag, headers = diff_parse_headers(fp, diff_type, rev1, rev2,
+    date1, date2, flag, headers = diff_parse_headers(fp, diff_type,
+                                                     rev1, rev2,
                                                      sym1, sym2)
   else:
     date1 = date2 = flag = headers = None
@@ -3049,7 +2968,8 @@
 
   # generate a GNU tar extension header for long names.
   if len(name) >= 100:
-    generate_tarball_header(out, '././@LongLink', len(name), 0644, 0, 0, 0, 'L')
+    generate_tarball_header(out, '././@LongLink', len(name),
+                            0644, 0, 0, 0, 'L')
     out.write(name)
     out.write('\0' * (511 - ((len(name) + 511) % 512)))
 
@@ -3112,7 +3032,7 @@
     for file in entries:
       if cvs and (file.kind != vclib.FILE or file.rev is None or file.dead):
         continue
-      if file.date > dir_mtime:
+      if (file.date is not None) and (file.date > dir_mtime):
         dir_mtime = file.date
 
   # Push current directory onto the stack.
@@ -3131,8 +3051,6 @@
       continue
     if cvs and (file.rev is None or file.dead):
       continue
-    if not request.auth.check_path_access(rep_path + [file.name]):
-      continue
 
     # If we get here, we've seen at least one valid file in the
     # current directory.  For CVS, we need to make sure there are
@@ -3142,9 +3060,11 @@
         generate_tarball_header(out, dir, mtime=dir_mtime)
       del stack[:]
 
-    if cvs:
-      info = os.stat(file.path)
-      mode = (info[stat.ST_MODE] & 0555) | 0200
+    # Calculate the mode for the file.  Sure, we could look directly
+    # at the ,v file in CVS, but that's a layering violation we'd like
+    # to avoid as much as possible.
+    if request.repos.isexecutable(rep_path + [file.name], request.pathrev):
+      mode = 0755
     else:
       mode = 0644
 
@@ -3155,7 +3075,8 @@
     fp.close()
 
     generate_tarball_header(out, tar_dir + file.name,
-                            len(contents), mode, file.date)
+                            len(contents), mode,
+                            file.date is not None and file.date or 0)
     out.write(contents)
     out.write('\0' * (511 - ((len(contents) + 511) % 512)))
 
@@ -3164,12 +3085,8 @@
   for file in entries:
     if file.errors or file.kind != vclib.DIR:
       continue
-    if (not rep_path) \
-       and cvs \
-       and request.cfg.options.hide_cvsroot \
-       and file.name == 'CVSROOT':
-        continue
-    if not request.auth.check_path_access(rep_path + [file.name]):
+    if request.cfg.options.hide_cvsroot \
+       and is_cvsroot_path(request.roottype, rep_path + [file.name]):
       continue
 
     mtime = request.roottype == 'svn' and file.date or None
@@ -3187,11 +3104,19 @@
 
   if debug.TARFILE_PATH:
     fp = open(debug.TARFILE_PATH, 'w')
-  else:
-    request.server.header('application/octet-stream')
+  else:    
+    tarfile = request.rootname
+    if request.path_parts:
+      tarfile = "%s-%s" % (tarfile, request.path_parts[-1])
+    request.server.addheader('Content-Disposition',
+                             'attachment; filename="%s.tar.gz"' % (tarfile))
+    server_fp = get_writeready_server_file(request, 'application/x-gzip')
     request.server.flush()
-    fp = popen.pipe_cmds([(cfg.utilities.gzip or 'gzip', '-c', '-n')])
-  
+    
+    # Try to use the Python gzip module, if available; otherwise,
+    # we'll use the configured 'gzip' binary.
+    fp = gzip.GzipFile('', 'wb', 9, server_fp)
+
   ### FIXME: For Subversion repositories, we can get the real mtime of the
   ### top-level directory here.
   generate_tarball(fp, request, [], [])
@@ -3221,20 +3146,17 @@
     rev = request.repos._getrev(query_dict.get('revision'))
   except vclib.InvalidRevision:
     raise debug.ViewVCException('Invalid revision', '404 Not Found')
-    
-  # The revision number acts as a weak validator.
-  if check_freshness(request, None, str(rev), weak=1):
+  youngest_rev = request.repos.get_youngest_revision()
+  
+  # The revision number acts as a weak validator (but we tell browsers
+  # not to cache the youngest revision).
+  if rev != youngest_rev and check_freshness(request, None, str(rev), weak=1):
     return
 
   # Fetch the revision information.
   date, author, msg, changes = request.repos.revinfo(rev)
   date_str = make_time_string(date, cfg)
 
-  # Filter the changes list based on what the user is permitted to see.
-  def _auth_filter(item):
-    return request.auth.check_path_access(item.path_parts)
-  changes = filter(_auth_filter, changes)
-
   # Sort the changes list by path.
   def changes_sort_by_path(a, b):
     return cmp(a.path_parts, b.path_parts)
@@ -3263,13 +3185,6 @@
   for change in changes:
     change.view_href = change.diff_href = change.type = change.log_href = None
 
-    # If this path was copied, and the user is permitted to see this
-    # path but not the path from which it was copied, then lie about
-    # this *not* being a copy.
-    if change.copied \
-       and not request.auth.check_path_access(change.base_path_parts):
-      change.copied = 0
-
     # If the path is newly added, don't claim text or property
     # modifications.
     if (change.action == vclib.ADDED or change.action == vclib.REPLACED) \
@@ -3277,7 +3192,7 @@
       change.text_changed = 0
       change.props_changed = 0
 
-    # Calculate the various view link URLs (for which we must have a pathtype).
+    # Calculate the view link URLs (for which we must have a pathtype).
     if change.pathtype:
       view_func = None
       if change.pathtype is vclib.FILE \
@@ -3341,7 +3256,7 @@
                                     pathtype=None,
                                     params={'revision': str(rev - 1)},
                                     escape=1)
-  if rev < request.repos.youngest:
+  if rev < request.repos.get_youngest_revision():
     next_rev_href = request.get_url(view_func=view_revision,
                                     where=None,
                                     pathtype=None,
@@ -3369,6 +3284,8 @@
   data['jump_rev_action'], data['jump_rev_hidden_values'] = \
     request.get_form(params={'revision': None})
 
+  if rev == youngest_rev:
+    request.server.addheader("Cache-control", "no-store")
   generate_page(request, "revision", data)
 
 def is_query_supported(request):
@@ -3377,6 +3294,22 @@
          and request.pathtype == vclib.DIR \
          and request.roottype in ['cvs', 'svn']
 
+def is_querydb_nonempty_for_root(request):
+  """Return 1 iff commits database integration is supported *and* the
+  current root is found in that database.  Only does this check if
+  check_database is set to 1."""
+  if request.cfg.cvsdb.enabled and request.roottype in ['cvs', 'svn']:
+    if request.cfg.cvsdb.check_database_for_root:
+      global cvsdb
+      import cvsdb
+      db = cvsdb.ConnectDatabaseReadOnly(request.cfg)
+      repos_root, repos_dir = cvsdb.FindRepository(db, request.rootpath)
+      if repos_root:
+        return 1
+    else:
+      return 1
+  return 0
+
 def view_queryform(request):
   if not is_query_supported(request):
     raise debug.ViewVCException('Can not query project root "%s" at "%s".'
@@ -3411,9 +3344,11 @@
 
   generate_page(request, "query_form", data)
 
-def parse_date(s):
-  '''Parse a date string from the query form.'''
-  match = re.match(r'^(\d\d\d\d)-(\d\d)-(\d\d)(?:\ +(\d\d):(\d\d)(?::(\d\d))?)?$', s)
+def parse_date(datestr):
+  """Parse a date string from the query form."""
+  
+  match = re.match(r'^(\d\d\d\d)-(\d\d)-(\d\d)(?:\ +'
+                   '(\d\d):(\d\d)(?::(\d\d))?)?$', datestr)
   if match:
     year = int(match.group(1))
     month = int(match.group(2))
@@ -3496,7 +3431,7 @@
   return string.join(ret, '')
 
 def prev_rev(rev):
-  '''Returns a string representing the previous revision of the argument.'''
+  """Returns a string representing the previous revision of the argument."""
   r = string.split(rev, '.')
   # decrement final revision component
   r[-1] = str(int(r[-1]) - 1)
@@ -3505,67 +3440,94 @@
     r = r[:-2]
   return string.join(r, '.')
 
-def build_commit(request, files, limited_files, dir_strip):
+def build_commit(request, files, max_files, dir_strip, format):
+  """Return a commit object build from the information in FILES, or
+  None if no allowed files are present in the set.  DIR_STRIP is the
+  path prefix to remove from the commit object's set of files.  If
+  MAX_FILES is non-zero, it is used to limit the number of files
+  returned in the commit object.  FORMAT is the requested output
+  format of the query request."""
+
   cfg = request.cfg
-  commit = _item(num_files=len(files), files=[])
-  commit.limited_files = ezt.boolean(limited_files)
+  author = files[0].GetAuthor()
+  date = files[0].GetTime()
   desc = files[0].GetDescription()
-  commit.log = htmlify(desc, cfg.options.mangle_email_addresses)
-  commit.short_log = format_log(desc, cfg)
-  commit.author = request.server.escape(files[0].GetAuthor())
-  commit.rss_date = make_rss_time_string(files[0].GetTime(), cfg)
-  if request.roottype == 'svn':
-    commit.rev = files[0].GetRevision()
-    commit.rss_url = request.get_url(view_func=view_revision,
-                                     params={'revision': commit.rev},
-                                     escape=1,
-                                     prefix=1)
-  else:
-    commit.rev = None
-    commit.rss_url = None
-
+  commit_rev = files[0].GetRevision()
   len_strip = len(dir_strip)
-
+  commit_files = []
+  num_allowed = 0
+  plus_count = 0
+  minus_count = 0
+  found_unreadable = 0
+  
   for f in files:
-    commit_time = f.GetTime()
-    if commit_time:
-      commit_time = make_time_string(commit_time, cfg)
-    change_type = f.GetTypeString()
-    rev = f.GetRevision()
-    rev_prev = prev_rev(rev)
-    
     dirname = f.GetDirectory()
     filename = f.GetFile()
     if dir_strip:
       assert dirname[:len_strip] == dir_strip
       assert len(dirname) == len_strip or dirname[len(dir_strip)] == '/'
       dirname = dirname[len_strip+1:]
-    filename = dirname and ("%s/%s" % (dirname, filename)) or filename
+    where = dirname and ("%s/%s" % (dirname, filename)) or filename
+    rev = f.GetRevision()
+    rev_prev = prev_rev(rev)
+    commit_time = f.GetTime()
+    if commit_time:
+      commit_time = make_time_string(commit_time, cfg)
+    change_type = f.GetTypeString()
 
     # In CVS, we can actually look at deleted revisions; in Subversion
     # we can't -- we'll look at the previous revision instead.
+    exam_rev = rev
+    if request.roottype == 'svn' and change_type == 'Remove':
+      exam_rev = rev_prev
+
+    # Check path access (since the commits database logic bypasses the
+    # vclib layer and, thus, the vcauth stuff that layer uses).
+    path_parts = _path_parts(where)
+    if path_parts:
+      # Skip files in CVSROOT if asked to hide such.
+      if cfg.options.hide_cvsroot \
+         and is_cvsroot_path(request.roottype, path_parts):
+        found_unreadable = 1
+        continue
+      
+      # We have to do a rare authz check here because this data comes
+      # from the CVSdb, not from the vclib providers.
+      #
+      # WARNING: The Subversion CVSdb integration logic is weak, weak,
+      # weak.  It has no ability to track copies, so complex
+      # situations like a copied directory with a deleted subfile (all
+      # in the same revision) are very ... difficult.  We've no choice
+      # but to omit as unauthorized paths the authorization logic
+      # can't find.
+      try:
+        readable = vclib.check_path_access(request.repos, path_parts,
+                                           None, exam_rev)
+      except vclib.ItemNotFound:
+        readable = 0
+      if not readable:
+        found_unreadable = 1
+        continue
+         
     if request.roottype == 'svn':
-      if change_type == 'Remove':
-        params = { 'pathrev': rev_prev }
-      else:
-        params = { 'pathrev': rev }
+      params = { 'pathrev': exam_rev }
     else:
-      params = { 'revision': rev, 'pathrev': f.GetBranch() or None }
-        
+      params = { 'revision': exam_rev, 'pathrev': f.GetBranch() or None }  
+    
     dir_href = request.get_url(view_func=view_directory,
                                where=dirname, pathtype=vclib.DIR,
                                params=params, escape=1)
     log_href = request.get_url(view_func=view_log,
-                               where=filename, pathtype=vclib.FILE,
+                               where=where, pathtype=vclib.FILE,
                                params=params, escape=1)
     diff_href = view_href = download_href = None
     if 'markup' in cfg.options.allowed_views:
       view_href = request.get_url(view_func=view_markup,
-                                  where=filename, pathtype=vclib.FILE,
+                                  where=where, pathtype=vclib.FILE,
                                   params=params, escape=1)
     if 'co' in cfg.options.allowed_views:
       download_href = request.get_url(view_func=view_checkout,
-                                      where=filename, pathtype=vclib.FILE,
+                                      where=where, pathtype=vclib.FILE,
                                       params=params, escape=1)
     if change_type == 'Change':
       diff_href_params = params.copy()
@@ -3575,27 +3537,29 @@
         'diff_format': None
         })
       diff_href = request.get_url(view_func=view_diff,
-                                  where=filename, pathtype=vclib.FILE,
+                                  where=where, pathtype=vclib.FILE,
                                   params=diff_href_params, escape=1)
-    prefer_markup = ezt.boolean(default_view(guess_mime(filename),
-                                             cfg) == view_markup)      
+    mime_type = calculate_mime_type(request, path_parts, exam_rev)
+    prefer_markup = ezt.boolean(default_view(mime_type, cfg) == view_markup)
 
-    # skip files in forbidden or hidden modules
-    dir_parts = filter(None, string.split(dirname, '/'))
-    if dir_parts \
-       and ((dir_parts[0] == 'CVSROOT'
-             and cfg.options.hide_cvsroot) \
-            or not request.auth.check_path_access(dir_parts)):
+    # Update plus/minus line change count.
+    plus = int(f.GetPlusCount())
+    minus = int(f.GetMinusCount())
+    plus_count = plus_count + plus
+    minus_count = minus_count + minus
+    
+    num_allowed = num_allowed + 1
+    if max_files and num_allowed > max_files:
       continue
 
-    commit.files.append(_item(date=commit_time,
+    commit_files.append(_item(date=commit_time,
                               dir=request.server.escape(dirname),
-                              file=request.server.escape(f.GetFile()),
+                              file=request.server.escape(filename),
                               author=request.server.escape(f.GetAuthor()),
                               rev=rev,
                               branch=f.GetBranch(),
-                              plus=int(f.GetPlusCount()),
-                              minus=int(f.GetMinusCount()),
+                              plus=plus,
+                              minus=minus,
                               type=change_type,
                               dir_href=dir_href,
                               log_href=log_href,
@@ -3603,6 +3567,42 @@
                               download_href=download_href,
                               prefer_markup=prefer_markup,
                               diff_href=diff_href))
+
+  # No files survived authz checks?  Let's just pretend this
+  # little commit didn't happen, shall we?
+  if not len(commit_files):
+    return None
+
+  commit = _item(num_files=len(commit_files), files=commit_files,
+                 plus=plus_count, minus=minus_count)
+  commit.limited_files = ezt.boolean(num_allowed > len(commit_files))
+
+  # We'll mask log messages in commits which contain unreadable paths,
+  # but even that is kinda iffy.  If a person searches for
+  # '/some/hidden/path' across log messages, then gets a response set
+  # that shows commits lacking log message, said person can reasonably
+  # assume that the log messages contained the hidden path, and that
+  # this is likely because they are referencing a real path in the
+  # repository -- a path the user isn't supposed to even know about.
+  if found_unreadable:
+    commit.log = None
+    commit.short_log = None
+  else:
+    commit.log = htmlify(desc)
+    commit.short_log = format_log(desc, cfg, format != 'rss')
+  commit.author = request.server.escape(author)
+  commit.rss_date = make_rss_time_string(date, request.cfg)
+  if request.roottype == 'svn':
+    commit.rev = commit_rev
+    commit.rss_url = '%s://%s%s' % \
+      (request.server.getenv("HTTPS") == "on" and "https" or "http",
+       request.server.getenv("HTTP_HOST"),
+       request.get_url(view_func=view_revision,
+                       params={'revision': commit.rev},
+                       escape=1))
+  else:
+    commit.rev = None
+    commit.rss_url = None
   return commit
 
 def query_backout(request, commits):
@@ -3743,47 +3743,49 @@
     current_desc = query.commit_list[0].GetDescriptionID()
     current_rev = query.commit_list[0].GetRevision()
     dir_strip = _path_join(repos_dir)
+
     for commit in query.commit_list:
-      # base modification time on the newest commit ...
+      commit_desc = commit.GetDescriptionID()
+      commit_rev = commit.GetRevision()
+
+      # base modification time on the newest commit
       if commit.GetTime() > mod_time:
         mod_time = commit.GetTime()
-      # form plus/minus totals
-      plus_count = plus_count + int(commit.GetPlusCount())
-      minus_count = minus_count + int(commit.GetMinusCount())
-      # group commits with the same commit message ...
-      desc = commit.GetDescriptionID()
+        
       # For CVS, group commits with the same commit message.
       # For Subversion, group them only if they have the same revision number
       if request.roottype == 'cvs':
-        if current_desc == desc:
-          if not limit_changes or len(files) < limit_changes:
-            files.append(commit)
-          else:
-            limited_files = 1
+        if current_desc == commit_desc:
+          files.append(commit)
           continue
       else:
-        if current_rev == commit.GetRevision():
-          if not limit_changes or len(files) < limit_changes:
-            files.append(commit)
-          else:
-            limited_files = 1
+        if current_rev == commit_rev:
+          files.append(commit)
           continue
 
-      # if our current group has any allowed files, append a commit
-      # with those files.
-      if len(files):
-        commits.append(build_commit(request, files, limited_files, dir_strip))
+      # append this grouping
+      commit_item = build_commit(request, files, limit_changes,
+                                 dir_strip, format)
+      if commit_item:
+        # update running plus/minus totals
+        plus_count = plus_count + commit_item.plus
+        minus_count = minus_count + commit_item.minus
+        commits.append(commit_item)
 
       files = [ commit ]
       limited_files = 0
-      current_desc = desc
-      current_rev = commit.GetRevision()
+      current_desc = commit_desc
+      current_rev = commit_rev
       
-    # we need to tack on our last commit grouping, but, again, only if
-    # it has allowed files.
-    if len(files):
-      commits.append(build_commit(request, files, limited_files, dir_strip))
-
+    # we need to tack on our last commit grouping, if any
+    commit_item = build_commit(request, files, limit_changes,
+                               dir_strip, format)
+    if commit_item:
+      # update running plus/minus totals
+      plus_count = plus_count + commit_item.plus
+      minus_count = minus_count + commit_item.minus
+      commits.append(commit_item)
+  
   # only show the branch column if we are querying all branches
   # or doing a non-exact branch match on a CVS repository.
   show_branch = ezt.boolean(request.roottype == 'cvs' and
@@ -3855,13 +3857,100 @@
 for code, view in _views.items():
   _view_codes[view] = code
 
-def list_roots(cfg):
+def list_roots(request):
+  cfg = request.cfg
   allroots = { }
+  
+  # Add the viewable Subversion roots
   for root in cfg.general.svn_roots.keys():
+    auth = setup_authorizer(cfg, request.username, root)
+    try:
+      vclib.svn.SubversionRepository(root, cfg.general.svn_roots[root], auth,
+                                     cfg.utilities, cfg.options.svn_config_dir)
+    except vclib.ReposNotFound:
+      continue
     allroots[root] = [cfg.general.svn_roots[root], 'svn']
+
+  # Add the viewable CVS roots
   for root in cfg.general.cvs_roots.keys():
+    auth = setup_authorizer(cfg, request.username, root)
+    try:
+      vclib.ccvs.CVSRepository(root, cfg.general.cvs_roots[root], auth,
+                               cfg.utilities, cfg.options.use_rcsparse)
+    except vclib.ReposNotFound:
+      continue
     allroots[root] = [cfg.general.cvs_roots[root], 'cvs']
+    
   return allroots
+
+def expand_root_parents(cfg):
+  """Expand the configured root parents into individual roots."""
+  
+  # Each item in root_parents is a "directory : repo_type" string.
+  for pp in cfg.general.root_parents:
+    pos = string.rfind(pp, ':')
+    if pos < 0:
+      raise debug.ViewVCException(
+        "The path '%s' in 'root_parents' does not include a "
+        "repository type." % (pp))
+
+    repo_type = string.strip(pp[pos+1:])
+    pp = os.path.normpath(string.strip(pp[:pos]))
+
+    if repo_type == 'cvs':
+      roots = vclib.ccvs.expand_root_parent(pp)
+      if cfg.options.hide_cvsroot and roots.has_key('CVSROOT'):
+        del roots['CVSROOT']
+      cfg.general.cvs_roots.update(roots)
+    elif repo_type == 'svn':
+      roots = vclib.svn.expand_root_parent(pp)
+      cfg.general.svn_roots.update(roots)
+    else:
+      raise debug.ViewVCException(
+        "The path '%s' in 'root_parents' has an unrecognized "
+        "repository type." % (pp))
+
+def find_root_in_parents(cfg, rootname, roottype):
+  """Return the rootpath for configured ROOTNAME of ROOTTYPE."""
+
+  # Easy out:  caller wants rootname "CVSROOT", and we're hiding those.
+  if rootname == 'CVSROOT' and cfg.options.hide_cvsroot:
+    return None
+  
+  for pp in cfg.general.root_parents:
+    pos = string.rfind(pp, ':')
+    if pos < 0:
+      continue
+    repo_type = string.strip(pp[pos+1:])
+    if repo_type != roottype:
+      continue
+    pp = os.path.normpath(string.strip(pp[:pos]))
+    
+    if roottype == 'cvs':
+      roots = vclib.ccvs.expand_root_parent(pp)
+    elif roottype == 'svn':
+      roots = vclib.svn.expand_root_parent(pp)
+    else:
+      roots = {}
+    if roots.has_key(rootname):
+      return roots[rootname]
+  return None
+
+def locate_root(cfg, rootname):
+  """Return a 2-tuple ROOTTYPE, ROOTPATH for configured ROOTNAME."""
+  if cfg.general.cvs_roots.has_key(rootname):
+    return 'cvs', cfg.general.cvs_roots[rootname]
+  path_in_parent = find_root_in_parents(cfg, rootname, 'cvs')
+  if path_in_parent:
+    cfg.general.cvs_roots[rootname] = path_in_parent
+    return 'cvs', path_in_parent
+  if cfg.general.svn_roots.has_key(rootname):
+    return 'svn', cfg.general.svn_roots[rootname]
+  path_in_parent = find_root_in_parents(cfg, rootname, 'svn')
+  if path_in_parent:
+    cfg.general.svn_roots[rootname] = path_in_parent
+    return 'svn', path_in_parent
+  return None, None
   
 def load_config(pathname=None, server=None):
   debug.t_start('load-config')
@@ -3879,50 +3968,8 @@
   # load mime types file
   if cfg.general.mime_types_file:
     mimetypes.init([cfg.general.mime_types_file])
-
-  # special handling for root_parents.  Each item in root_parents is
-  # a "directory : repo_type" string.  For each item in
-  # root_parents, we get a list of the subdirectories.
-  #
-  # If repo_type is "cvs", and the subdirectory contains a child
-  # "CVSROOT/config", then it is added to cvs_roots. Or, if the
-  # root directory itself contains a child "CVSROOT/config" file,
-  # then all its subdirectories are added to cvs_roots.
-  #
-  # If repo_type is "svn", and the subdirectory contains a child
-  # "format", then it is added to svn_roots.
-  for pp in cfg.general.root_parents:
-    pos = string.rfind(pp, ':')
-    if pos < 0:
-      raise debug.ViewVCException(
-        "The path '%s' in 'root_parents' does not include a "
-        "repository type." % pp)
-
-    repo_type = string.strip(pp[pos+1:])
-    pp = os.path.normpath(string.strip(pp[:pos]))
-
-    try:
-      subpaths = os.listdir(pp)
-    except OSError:
-      raise debug.ViewVCException(
-        "The path '%s' in 'root_parents' does not refer to "
-        "a valid directory." % pp)
-
-    cvsroot = os.path.exists(os.path.join(pp, "CVSROOT", "config"))
-
-    for subpath in subpaths:
-      if os.path.exists(os.path.join(pp, subpath)):
-        if (repo_type == 'cvs'
-            and (os.path.exists(os.path.join(pp, subpath, "CVSROOT", "config"))
-                 or (cvsroot and (subpath != 'CVSROOT'
-                                  or not cfg.options.hide_cvsroot)))):
-          cfg.general.cvs_roots[subpath] = os.path.join(pp, subpath)
-        elif repo_type == 'svn' and \
-             os.path.exists(os.path.join(pp, subpath, "format")):
-          cfg.general.svn_roots[subpath] = os.path.join(pp, subpath)
-
+  
   debug.t_end('load-config')
-
   return cfg
 
 

Added: branches/VIEWCVS_DIST/notes/logo/viewvc-logo.odg
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/notes/logo/viewvc-logo.pdf
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/notes/logo/viewvc-logo.svg
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/notes/logo/viewvc-logo.svg	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";><svg version="1.1" viewBox="0 0 23368 6350" preserveAspectRatio="xMidYMid" fill-rule="evenodd" xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";><g visibility="visible" id="Default"><desc>Master slide</desc></g><g visibility="visible" id="page1"><desc>Slide</desc><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(148,189,94)"><path d="M 3140,6026 L 2845,6011 2558,5967 2282,5896 2017,5799 1764,5678 1526,5533 1304,5367 1099,5181 913,4976 747,4754 602,4516 481,4263 384,3998 313,3722 269,3435 254,3140 258,2985 285,3234 336,3474 409,3706 502,3928 615,4139 746,4338 895,4523 1060,4693 1240,4848 1433,4985 1640,5105 1858,5206 2087,5286 2324,5345 2570,5381 2823,5393 3086,5380 3341,5341 3587,5277 3823,5191 4048,5083 4260,4954 4458,4806 4640,4640 4806,4458 4954,4260 5083,4048 5191,3823 5277,3587 5341,3341 5380,3086 5393,2823 5381,2570 5345,2324 5286,2087 52
 06,1858 5105,1640 4985,1433 4848,1240 4693,1060 4523,895 4338,746 4139,615 3928,502 3706,409 3474,336 3234,285 2985,258 3140,254 3435,269 3722,313 3998,384 4263,481 4516,602 4754,747 4976,913 5181,1099 5367,1304 5533,1526 5678,1764 5799,2017 5896,2282 5967,2558 6011,2845 6026,3140 6011,3435 5967,3722 5896,3998 5799,4263 5678,4516 5533,4754 5367,4976 5181,5181 4976,5367 4754,5533 4516,5678 4263,5799 3998,5896 3722,5967 3435,6011 3140,6026 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(148,189,94)"><path d="M 4334,3148 L 4332,3087 4328,3025 4320,2964 4309,2904 4295,2844 4278,2785 4258,2726 4236,2669 4210,2613 4181,2559 4150,2506 4116,2454 4080,2405 4041,2357 4000,2312 3956,2268 3911,2227 3863,2188 3814,2152 3762,2118 3709,2087 3655,2058 3599,2032 3542,2010 3483,1990 3424,1973 3364,1959 3304,1948 3243,1940 3181,1936 3120,1934 3120,1934 3059,1936 2997,1940 2936,1948 2876,1959 2816,1973 2757,1990 2698,2010 2641,2032 2585,2058 2531,2087 2478,2118 2426
 ,2152 2377,2188 2329,2227 2284,2268 2240,2312 2199,2357 2160,2405 2124,2454 2090,2506 2059,2559 2030,2613 2004,2669 1982,2726 1962,2785 1945,2844 1931,2904 1920,2964 1912,3025 1908,3087 1906,3148 1906,3148 1908,3209 1912,3271 1920,3332 1931,3392 1945,3452 1962,3511 1982,3570 2004,3627 2030,3683 2059,3737 2090,3790 2124,3842 2160,3891 2199,3939 2240,3984 2284,4028 2329,4069 2377,4108 2426,4144 2478,4178 2531,4209 2585,4238 2641,4264 2698,4286 2757,4306 2816,4323 2876,4337 2936,4348 2997,4356 3059,4360 3120,4362 3120,4362 3181,4360 3243,4356 3304,4348 3364,4337 3424,4323 3483,4306 3542,4286 3599,4264 3655,4238 3709,4209 3762,4178 3814,4144 3863,4108 3911,4069 3956,4028 4000,3984 4041,3939 4080,3891 4116,3842 4150,3790 4181,3737 4210,3683 4236,3627 4258,3570 4278,3511 4295,3452 4309,3392 4320,3332 4328,3271 4332,3209 4334,3148 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(255,255,255)"><path d="M 3857,1755 L 5494,1755 3991,4922 3889,4922 3891,4927
  2256,4927 753,1760 2390,1760 3122,3305 3857,1755 Z"/></g><g style="stroke:none;fill:rgb(115,156,62)"><path d="M 3857,1654 L 5494,1654 5494,1755 5494,1857 3857,1857 3857,1755 3857,1654 Z"/><path d="M 5494,1755 L 5494,1654 5512,1655 5529,1660 5545,1667 5559,1677 5572,1690 5582,1704 5589,1720 5594,1737 5596,1755 5594,1773 5589,1790 5586,1799 5494,1755 Z"/><path d="M 5586,1799 L 4083,4966 3991,4922 3899,4878 5402,1711 5494,1755 5586,1799 Z"/><path d="M 3991,4922 L 4083,4966 4074,4981 4062,4994 4049,5006 4033,5014 4017,5020 3999,5023 3991,5024 3991,4922 Z"/><path d="M 3991,5024 L 3889,5024 3889,4922 3889,4821 3991,4821 3991,4922 3991,5024 Z"/><path d="M 3889,4922 L 3795,4960 3790,4943 3788,4925 3789,4908 3793,4890 3800,4874 3809,4859 3821,4846 3836,4836 3851,4828 3868,4823 3886,4821 3889,4821 3889,4922 Z"/><path d="M 3983,4884 L 3985,4889 3891,4927 3797,4965 3795,4960 3889,4922 3983,4884 Z"/><path d="M 3891,4927 L 3985,4889 3990,4906 3992,4924 3991,4941 3987,4959 3980,4975 3971,
 4990 3959,5003 3944,5013 3929,5021 3912,5026 3894,5028 3891,5029 3891,4927 Z"/><path d="M 3891,5029 L 2256,5029 2256,4927 2256,4826 3891,4826 3891,4927 3891,5029 Z"/><path d="M 2256,4927 L 2256,5029 2238,5027 2221,5022 2205,5015 2191,5005 2178,4992 2168,4978 2164,4971 2256,4927 Z"/><path d="M 2164,4971 L 661,1804 753,1760 845,1716 2348,4883 2256,4927 2164,4971 Z"/><path d="M 753,1760 L 661,1804 655,1787 652,1770 652,1752 655,1734 661,1718 669,1702 681,1689 694,1677 709,1668 726,1662 743,1659 753,1659 753,1760 Z"/><path d="M 753,1659 L 2390,1659 2390,1760 2390,1862 753,1862 753,1760 753,1659 Z"/><path d="M 2390,1760 L 2390,1659 2408,1660 2425,1665 2441,1672 2455,1682 2468,1695 2478,1709 2482,1717 2390,1760 Z"/><path d="M 2482,1717 L 3214,3262 3122,3305 3030,3348 2298,1803 2390,1760 2482,1717 Z"/><path d="M 3122,3305 L 3214,3348 3205,3364 3193,3377 3180,3389 3164,3397 3148,3403 3130,3406 3113,3406 3095,3403 3079,3397 3063,3388 3050,3376 3038,3363 3030,3348 3122,3305 Z"/><path 
 d="M 3030,3262 L 3765,1712 3857,1755 3949,1798 3214,3348 3122,3305 3030,3262 Z"/><path d="M 3857,1755 L 3765,1712 3774,1696 3786,1683 3799,1671 3815,1663 3831,1657 3849,1654 3857,1654 3857,1755 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 7319,4538 L 6409,2458 7413,2458 7802,3712 8197,2458 9188,2458 8280,4538 7319,4538 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 9406,4538 L 9406,2458 10294,2458 10294,4538 9406,4538 Z M 9406,2286 L 9406,1759 10294,1759 10294,2286 9406,2286 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 11442,3269 L 12475,3269 12469,3227 12465,3207 12459,3187 12453,3168 12446,3150 12438,3133 12430,3116 12420,3099 12410,3083 12399,3068 12386,3054 12373,3040 12360,3026 12345,3013 12329,3001 12296,2979 12260,2960 12221,2944 12180,2931 12136,2920 12089,2913 12040,2908 11988,2907 11931,2908 11878,2913 11827,2920 117
 79,2930 11734,2943 11691,2959 11652,2977 11615,2999 11582,3023 11567,3037 11552,3051 11538,3065 11525,3080 11513,3096 11502,3113 11492,3130 11482,3148 11473,3167 11465,3186 11452,3226 11442,3269 Z M 13354,3904 L 13340,3946 13325,3987 13307,4027 13288,4066 13266,4103 13243,4140 13217,4174 13190,4208 13160,4240 13128,4271 13059,4329 12981,4381 12896,4429 12802,4471 12701,4507 12593,4538 12477,4564 12354,4583 12223,4597 12085,4606 11939,4609 11778,4604 11627,4591 11484,4568 11352,4536 11228,4495 11114,4445 11061,4417 11009,4386 10961,4353 10914,4318 10870,4281 10829,4242 10791,4201 10756,4158 10723,4113 10693,4067 10666,4018 10642,3968 10621,3916 10603,3862 10587,3806 10575,3748 10565,3689 10558,3627 10552,3498 10558,3369 10565,3307 10575,3247 10587,3189 10603,3133 10621,3079 10642,3027 10666,2976 10693,2928 10723,2881 10756,2837 10791,2794 10829,2753 10870,2714 10914,2677 10961,2642 11009,2609 11114,2550 11228,2500 11352,2459 11484,2427 11627,2404 11778,2391 11939,2386 12110,2
 391 12271,2407 12420,2432 12559,2468 12687,2514 12747,2541 12804,2571 12859,2603 12911,2637 12960,2674 13007,2714 13051,2756 13092,2801 13130,2847 13166,2897 13198,2949 13228,3003 13255,3059 13279,3118 13301,3180 13319,3244 13335,3310 13347,3378 13364,3523 13370,3677 13370,3713 11486,3713 11486,3734 11488,3754 11491,3773 11494,3792 11499,3811 11505,3828 11511,3846 11519,3862 11528,3878 11538,3894 11549,3909 11561,3923 11573,3937 11587,3950 11603,3962 11619,3974 11653,3995 11692,4014 11733,4030 11778,4043 11826,4053 11878,4060 11933,4065 11991,4066 12030,4065 12067,4063 12102,4060 12136,4056 12168,4050 12198,4043 12227,4034 12254,4024 12280,4013 12303,4001 12325,3987 12345,3973 12363,3957 12379,3941 12394,3923 12400,3913 12406,3904 13354,3904 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 13958,4538 L 13342,2458 14222,2458 14514,3795 14951,2458 15559,2458 15988,3740 16303,2458 17186,2458 16556,4538 15624,4538 15248,3404 14870,4
 538 13958,4538 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 18279,4538 L 17369,2458 18373,2458 18762,3712 19157,2458 20148,2458 19240,4538 18279,4538 Z"/></g><g/></g></g><g><desc>Drawing</desc><g><g style="stroke:none;fill:rgb(0,0,0)"><path d="M 22999,3624 L 22983,3743 22971,3800 22957,3854 22940,3907 22921,3958 22900,4007 22876,4054 22850,4099 22822,4143 22791,4184 22758,4223 22723,4261 22685,4296 22645,4330 22602,4362 22557,4392 22510,4420 22409,4470 22298,4512 22178,4547 22049,4574 21910,4593 21763,4605 21606,4609 21443,4604 21291,4591 21147,4568 21013,4536 20889,4495 20774,4445 20720,4417 20669,4386 20620,4353 20573,4318 20529,4281 20487,4242 20449,4201 20413,4158 20380,4114 20350,4067 20323,4019 20299,3969 20278,3916 20259,3862 20244,3807 20231,3749 20221,3689 20214,3628 20208,3499 20214,3371 20221,3309 20231,3250 20244,3192 20259,3136 20278,3082 20299,3030 20323,2980 20350,2931 20380,2885 20413,2840 20449,2797 20487,27
 56 20529,2716 20573,2679 20620,2643 20669,2610 20774,2551 20889,2501 21013,2460 21147,2428 21291,2405 21443,2392 21606,2387 21757,2391 21899,2401 22033,2419 22158,2444 22275,2476 22383,2515 22483,2561 22574,2614 22616,2643 22656,2674 22694,2706 22729,2741 22763,2777 22794,2814 22823,2854 22850,2895 22874,2938 22896,2983 22916,3029 22934,3077 22949,3127 22962,3178 22982,3286 22048,3286 22034,3252 22019,3219 22001,3189 21982,3161 21962,3135 21940,3112 21916,3090 21891,3071 21864,3054 21835,3040 21804,3028 21772,3018 21738,3010 21702,3004 21665,3001 21626,3000 21570,3002 21516,3008 21466,3018 21419,3033 21375,3051 21354,3062 21334,3074 21314,3087 21296,3101 21278,3116 21261,3132 21245,3148 21230,3166 21216,3184 21203,3204 21191,3223 21180,3244 21171,3266 21162,3288 21154,3311 21147,3335 21137,3385 21131,3438 21129,3495 21131,3549 21136,3601 21146,3651 21153,3674 21160,3697 21169,3719 21178,3740 21189,3760 21201,3780 21213,3799 21227,3818 21241,3835 21257,3852 21274,3868 21291,3
 883 21309,3897 21327,3910 21347,3922 21367,3933 21388,3942 21409,3951 21454,3966 21502,3976 21552,3983 21606,3985 21650,3983 21693,3979 21734,3971 21774,3960 21811,3946 21847,3930 21881,3910 21913,3887 21943,3862 21970,3834 21994,3805 22014,3773 22032,3739 22047,3703 22059,3664 22069,3624 22999,3624 Z"/></g><g/></g></g></g></svg>
\ No newline at end of file

Modified: branches/VIEWCVS_DIST/notes/releases.txt
==============================================================================
--- branches/VIEWCVS_DIST/notes/releases.txt	(original)
+++ branches/VIEWCVS_DIST/notes/releases.txt	Mon Nov  3 09:44:02 2008
@@ -65,12 +65,14 @@
     archive files into the root directory of the viewvc.org website
     (unversioned).
 
-12. Update the websites (both the viewvc.org/ and www/ ones) to refer
-    to the new release files.
+12. On trunk, update the websites (both the viewvc.org/ and www/ ones)
+    to refer to the new release files, and copy the CHANGES for the
+    new release into trunk's CHANGES file.
 
 13. Edit the file 'lib/viewvc.py' again, re-adding the "-dev" suffix
     and incrementing the patch number assigned to the __version__
-    variable, and commit:
+    variable, and add a new empty block in the branch's CHANGES file,
+    and commit:
 
        svn ci -m "Begin a new release cycle."
 

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/README
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/README	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,7 @@
+Template Set:  newvc
+Author(s):  C. Michael Pilato <cmpilato red-bean com>
+Compatibility:  ViewVC 1.1
+
+The "newvc" template set uses top navigation tabs to flip between
+various views of a file or directory, and aims for a clean-yet-modern
+look and feel.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/diff.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/diff.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,128 @@
+[# Setup page definitions]
+  [define page_title]Diff of:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+[include "include/header.ezt" "diff"]
+
+<form method="get" action="[diff_format_action]" style="display: inline;">
+  <div>
+    [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
+    <select name="diff_format" onchange="submit()">
+      <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
+      <option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
+      <option value="f" [is diff_format "f"]selected="selected"[end]>Full Colored Diff</option>
+      <option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
+      <option value="c" [is diff_format "c"]selected="selected"[end]>Context Diff</option>
+      <option value="s" [is diff_format "s"]selected="selected"[end]>Side by Side</option>
+    </select>
+    <input type="submit" value="Show" />
+    (<a href="[patch_href]">Generate patch</a>)
+  </div>
+</form>
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+[if-any raw_diff]
+<pre>[raw_diff]</pre>
+[else]
+
+[define change_right][end]
+[define last_change_type][end]
+
+[# these should live in stylesheets]
+
+<table cellpadding="0" cellspacing="0" style="width: 100%;">
+[for changes]
+ [is changes.type "change"][else]
+  [if-any change_right][change_right][define change_right][end][end]
+ [end]
+ [is changes.type "header"]
+  <tr>
+    <th class="vc_header" style="width:6%;"><strong>#</strong></th>
+    <th colspan="2" class="vc_header">
+      <strong>Line [changes.line_info_left]</strong> |
+      <strong>Line [changes.line_info_right]</strong> 
+    </th>
+  </tr>
+ [else]
+ [is changes.type "add"]
+  <tr>
+    <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+    <td class="vc_diff_plusminus"><strong style="color: green;">+</strong></td>
+    <td class="vc_diff_add">[changes.right]</td>
+  </tr>
+ [else]
+ [is changes.type "remove"]
+  <tr>
+    <td style="text-decoration: line-through">[changes.line_number]</td>
+    <td class="vc_diff_plusminus"><strong style="color: red;">&ndash;</strong></td>
+    <td class="vc_diff_remove">[changes.left]</td>
+  </tr>
+ [else]
+ [is changes.type "change"]
+  [if-any changes.have_left]
+  <tr>
+    <td style="text-decoration: line-through">[changes.line_number]</td>
+    <td class="vc_diff_plusminus"><strong style="color: yellow;">&lt;</strong></td>
+    <td class="vc_diff_changes1">[changes.left]</td>
+  </tr>
+  [end]
+  [define change_right][change_right]
+  [if-any changes.have_right]
+  <tr>
+    <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+    <td class="vc_diff_plusminus"><strong style="color: yellow;">&gt;</strong></td>
+    <td class="vc_diff_changes2">[changes.right]</td>
+  </tr>[end]
+  [end]
+ [else]
+ [is changes.type "no-changes"]
+  <tr><td colspan="3" style="vc_diff_nochange"><strong>- No changes -</strong></td></tr>
+ [else]
+ [is changes.type "binary-diff"]
+  <tr><td colspan="3" class="vc_diff_binary"><strong>- Binary file revisions differ -</strong></td></tr>
+ [else]
+ [is changes.type "error"]
+  <tr><td colspan="3" class="vc_diff_error"><strong>- ViewVC depends on rcsdiff and GNU diff
+      to create this page.  ViewVC cannot find GNU diff. Even if you
+      have GNU diff installed, the rcsdiff program must be configured
+      and compiled with the GNU diff location.  -</strong></td></tr>
+ [else][# a line of context]
+  <tr>
+    <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+    <td class="vc_diff_plusminus">&nbsp;</td>
+    <td style="font-family: monospace; white-space: pre;">[changes.right]</td>
+  </tr>
+ [end][end][end][end][end][end][end]
+ [define last_change_type][changes.type][end]
+[end]
+[if-any change_right][change_right][end]
+</table>
+
+<h3>Diff Legend</h3>
+<table class="auto" cellspacing="0">
+<tr>
+ <td class="vc_diff_plusminus"><strong style="color: red;">&ndash;</strong></td>
+ <td class="vc_diff_remove">Removed lines</td>
+</tr>
+<tr>
+ <td class="vc_diff_plusminus"><strong style="color: green;">+</strong></td>
+ <td class="vc_diff_add">Added lines</td>
+</tr>
+<tr>
+ <td class="vc_diff_plusminus"><strong style="color: yellow;">&lt;</strong></td>
+ <td class="vc_diff_changes1">Changed lines</td>
+</tr>
+<tr>
+ <td class="vc_diff_plusminus"><strong style="color: yellow;">&gt;</strong></td>
+ <td class="vc_diff_changes2">Changed lines</td>
+</tr>
+</table>
+
+[end]
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/directory.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/directory.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,139 @@
+[# setup page definitions]
+  [define page_title]Index of:[end]
+  [define help_href][docroot]/help_[if-any where]dir[else]root[end]view.html[end]
+[# end]
+[include "include/header.ezt" "directory"]
+
+[if-any where][else]
+  <!-- you may insert repository access instructions here -->
+[end]
+
+<table class="auto">
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]
+<tr>
+  <td>Jump to page:</td>
+  <td><form method="get" action="[dir_paging_action]">
+        [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
+        <select name="dir_pagestart"  onchange="submit()">
+          [for picklist]
+            <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
+          [end]
+        </select>
+        <input type="submit" value="Go" />
+      </form>
+  </td>
+</tr>
+[end][end]
+</table>
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+<div id="vc_togglables">
+[is roottype "svn"]
+[if-any rev]r<a href="[revision_href]">[rev]</a>[end]
+[else]
+[is num_dead "0"]
+[else]
+  [if-any attic_showing]
+    <a href="[hide_attic_href]">Hide
+  [else]
+    <a href="[show_attic_href]">Show
+  [end]
+  dead files</a>
+[end]
+[end]
+</div>
+
+<table cellspacing="2" class="fixed" id="dirlist">
+<thead>
+<tr>
+  <th style="width: 200px" class="vc_header[is sortby "file"]_sort[end]">
+    <a href="[sortby_file_href]#dirlist">File
+    [is sortby "file"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+  <th class="vc_header[is sortby "rev"]_sort[end]">
+    <a href="[sortby_rev_href]#dirlist">Last Change
+    [is sortby "rev"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+</tr>
+</thead>
+
+<tbody>
+[if-any up_href]
+  <tr class="vc_row_odd">
+    <td colspan="2">
+      <a href="[up_href]">
+      <img src="[docroot]/images/back_small.png" alt="" class="vc_icon"
+      />&nbsp;../</a>
+    </td>
+  </tr>
+ [end]
+[for entries]
+  [define click_href][is entries.pathtype "dir"][entries.view_href][else][if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end][end][end]
+
+  <tr class="vc_row_[if-index entries even]even[else]odd[end]">
+    <td style="width: 200px" onclick="jumpTo('[click_href]')">
+    <a name="[entries.anchor]" href="[click_href]" title="[is entries.pathtype "dir"]View Directory Contents[else][if-any entries.prefer_markup]View[else]Download[end] File Contents[end]">
+       <img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
+       [entries.name][is entries.pathtype "dir"]/[end]</a>
+       [is entries.state "dead"](dead)[end]
+    </td>
+
+    <td [if-any entries.log_href]onclick="jumpTo('[entries.log_href]')"[end]>
+      [if-any entries.rev]
+        <strong>[if-any entries.log_href]<a href="[entries.log_href]" title="Revision [entries.rev]">[entries.rev]</a>[else][entries.rev][end]</strong>
+        ([entries.ago] ago)
+        by <em>[entries.author]</em>:
+        [entries.log]
+        [is entries.pathtype "dir"][is roottype "cvs"]
+          <em>(from [entries.log_file]/[entries.log_rev])</em>
+        [end][end]
+      [end]
+    </td>
+  </tr>
+[end]
+</tbody>
+
+</table>
+
+<div id="vc_view_summary">
+[if-any search_re_form]
+<form class="inline" method="get" action="[search_re_action]">
+  <div class="inline">
+    [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+    <input type="text" name="search" value="[search_re]" />
+    <input type="submit" value="Search Files" />
+  </div>
+</form>
+[if-any search_re]
+<form class="inline" method="get" action="[search_re_action]">
+  <div class="inline">
+    [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+    <input type="submit" value="Show all files" />
+  </div>
+</form>
+[end]
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[end]
+[include "include/pathrev_form.ezt"]
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[files_shown] file[is files_shown "1"][else]s[end] shown
+</div>
+
+[include "include/props.ezt"]
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help.css
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help.css	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,8 @@
+/************************************/
+/***  ViewVC Help CSS Stylesheet ***/
+/************************************/
+body { margin: 0.5em; }
+img { border: none; }
+table { width: 100%; }
+td { vertical-align: top; }
+col.menu { width:12em; }

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_dirview.html
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_dirview.html	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,126 @@
+<!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>
+  <title>ViewVC Help: Directory View</title>
+  <link rel="stylesheet" href="help.css" type="text/css" />
+</head>
+<body>
+  <table>
+    <col class="menu" />
+    <col />
+    <tr>
+      <td colspan="2">
+	<h1>ViewVC Help: Directory View</h1>
+      </td>
+    </tr>
+    <tr><td>
+       <h3>Help</h3>
+       <a href="help_rootview.html">General</a><br />
+       <strong>Directory&nbsp;View</strong><br />
+       <a href="help_log.html">Log&nbsp;View</a><br />
+
+       <h3>Internet</h3>
+       <a href="http://viewvc.org/index.html";>Home</a><br />
+       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
+       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
+       <a href="http://viewvc.org/license-1.html";>License</a><br />
+    </td><td colspan="2">
+
+    <p>The directory listing view should be a familiar sight to any
+    computer user. It shows the path of the current directory being viewed
+    at the top of the page. Below that is a table summarizing the
+    directory contents, and then comes actual contents, a sortable list of
+    all files and subdirectories inside the current directory.</p>
+
+    <p><a name="summary"></a>The summary table is made up of some or all
+    of the following rows:</p>
+    <ul>
+      <li><a name="summary-files-shown"><strong>Files Shown</strong></a>
+      - Number of files shown in the directory listing. This might be less
+      than the actual number of files in the directory if a
+      <a href="#option-search">regular expression search</a> is in place,
+      hiding files which don't meet the search criteria. In CVS directory
+      listings, this row will also have a link to toggle display of
+      <a href="help_rootview.html#dead-files">dead files</a>, if any are
+      present.</li>
+
+      <li><a name="summary-revision"><strong>Directory
+      Revision</strong></a> - For Subversion directories only.
+      Shown as "# of #" where the first number is the most recent
+      repository revision where the directory (or a path underneath it)
+      was modified. The second number is just the latest repository
+      revision. Both numbers are links to
+      <a href="help_rootview.html#view-rev">revision views</a></li>
+
+     <li><a name="summary-sticky-revision-tag"><strong>Sticky
+     Revision/Tag</strong></a> - shows the current
+     <a href="help_rootview.html#sticky-revision-tag">sticky revision or
+     tag</a> and contains form fields to set or clear it.</li>
+
+     <li><a name="summary-search"><strong>Current Search</strong></a> -
+     If a <a href="#option-search">regular expression search</a> is in place,
+     shows the search string.</li>
+
+     <li><a name="summary-query"><strong>Query</strong></a> - Provides
+     a link to a <a href="help_rootview.html#view-query">query form</a>
+     for the directory</li>
+   </ul>
+
+  <p><a name="list"></a>The actual directory list is a table with
+  filenames and directory names in one column and information about the
+  most recent revisions where each file or directory was modified in the
+  other columns. Column headers can be clicked to sort the directory
+  entries in order by a column, and clicked again to reverse the sort
+  order.</p>
+
+  <p>
+  <!-- If using directory.ezt template -->
+  File names are links to <a href="help_log.html">log views</a>
+  showing a list of revisions where a file was modified. Revision
+  numbers are links to either
+  <a href="help_rootview.html#view-markup">view</a>
+  or <a href="help_rootview.html#view-checkout">download</a> a file
+  (depending on its file type). The links are reversed for directories.
+  Directory revision numbers are links to <a href="help_log.html">log
+  views</a>, while directory names are links showing the contents of those
+  directories.
+
+  <!-- If using dir_alt.ezt template -->
+  <!--
+  File and directory names are links to retrieve their contents.
+  File links may be either
+  <a href="help_rootview.html#view-markup">view</a>
+  or <a href="help_rootview.html#view-download">download</a> links
+  depending on the file type. Directory links go to directory
+  listings. Revision numbers are links to <a href="help_log.html">log
+  views</a> showing lists of revisions where a file or directory was
+  modified.
+  -->
+
+  Also, in CVS repositories with the <a
+  href="help_rootview.html#view-graph">graph view</a> enabled, there
+  will be small icons next to file names which are links to revision
+  graphs.</p>
+
+  <p>Depending on how ViewVC is configured, there may be more options
+  at the bottom of directory pages:</p>
+
+  <ul>
+    <li><a name="option-search"><strong>Regular expression
+    search</strong></a> - If enabled, will show a form field accepting
+    a search string (a
+    <a href="http://doc.python.org/lib/re-syntax.html";>python regular
+    expression</a>). Once submitted, only files that have at least
+    one occurance of the expression will show up in directory listings.
+    </li>
+    <li><a name="option-tarball"><strong>Tarball download</strong></a> -
+    If enabled, will show a link to download a gzipped tar archive of
+    the directory contents.</li>
+  </ul>
+
+  </td></tr></table>
+  <hr />
+  <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
+  </body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_log.html
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_log.html	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,71 @@
+<!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>
+  <title>ViewVC Help: Log View</title>
+  <link rel="stylesheet" href="help.css" type="text/css" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+</head>
+<body>
+  <table>
+    <col class="menu" />
+    <col />
+    <tr>
+      <td colspan="2">
+	<h1>ViewVC Help: Log View</h1>
+      </td>
+    </tr>
+    <tr><td>
+       <h3>Help</h3>
+       <a href="help_rootview.html">General</a><br />
+       <a href="help_dirview.html">Directory&nbsp;View</a><br />
+       <strong>Log&nbsp;View</strong><br />
+
+       <h3>Internet</h3>
+       <a href="http://viewvc.org/index.html";>Home</a><br />
+       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
+       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
+       <a href="http://viewvc.org/license-1.html";>License</a><br />
+    </td><td colspan="2">
+    <p>
+      The log view displays the revision history of the selected source
+      file or directory. For each revision the following information is
+      displayed:
+
+      <ul>
+        <li>The revision number. In Subversion repositories, this is a
+            link to the <a href="help_rootview.html#view-rev">revision
+            view</a></li>
+        <li>For files, links to
+        <a href="help_rootview.html#view-markup">view</a>,
+        <a href="help_rootview.html#view-checkout">download</a>, and
+        <a href="help_rootview.html#view-annotate">annotate</a> the
+          revision. For directories, a link to
+        <a href="help_dirview.html">list directory contents</a></li>
+        <li>A link to select the revision for diffs (see below)</li>
+        <li>The date and age of the change</li>
+        <li>The author of the modification</li>
+        <li>The CVS branch (usually <em>MAIN</em>, if not on a branch)</li>
+        <li>Possibly a list of CVS tags bound to the revision (if any)</li>
+        <li>The size of the change measured in added and removed lines of
+            code. (CVS only)</li>
+        <li>The size of the file in bytes at the time of the revision
+            (Subversion only)</li>
+        <li>Links to view diffs to the previous revision or possibly to
+            an arbitrary selected revision (if any, see above)</li>
+        <li>If the revision is the result of a copy, the path and revision
+            copied from</li>
+        <li>If the revision precedes a copy or rename, the path at the
+            time of the revision</li>
+        <li>And last but not least, the commit log message which should tell
+            about the reason for the change.</li>
+      </ul>
+    <p>
+      At the bottom of the page you will find a form which allows
+      to request diffs between arbitrary revisions.
+    </p>
+  </td></tr></table>
+  <hr />
+  <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
+  </body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_query.html
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_query.html	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,66 @@
+<!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>
+  <title>ViewVC Help: Query The Commit Database</title>
+  <link rel="stylesheet" href="help.css" type="text/css" />
+</head>
+<body>
+<table>
+  <col class="menu" />
+  <col />
+  <tr>
+    <td colspan="2">
+      <h1>ViewVC Help: Query The Commit Database</h1>
+    </td>
+  </tr>
+  <tr><td>
+     <h3>Other&nbsp;Help:</h3>
+     <a href="help_rootview.html">General</a><br />
+     <a href="help_dirview.html">Directory&nbsp;View</a><br />
+     <a href="help_log.html">Classic&nbsp;Log&nbsp;View</a><br />
+     <a href="help_logtable.html">Alternative&nbsp;Log&nbsp;View</a><br />
+     <strong>Query&nbsp;Database</strong>
+
+     <h3>Internet</h3>
+     <a href="http://viewvc.org/index.html";>Home</a><br />
+     <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
+     <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
+     <a href="http://viewvc.org/license-1.html";>License</a><br />
+  </td><td colspan="2">
+
+  <p> 
+    Select your parameters for querying the CVS commit database in the
+    form at the top of the page.  You
+    can search for multiple matches by typing a comma-seperated list
+    into the text fields.  Regular expressions, and wildcards are also
+    supported.  Blank text input fields are treated as wildcards.
+  </p>
+  <p>
+    Any of the text entry fields can take a comma-seperated list of
+    search arguments.  For example, to search for all commits from
+    authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
+    gstein</code> in the <em>Author</em> input box.  If you are searching
+    for items containing spaces or quotes, you will need to quote your
+    request.  For example, the same search above with quotes is:
+    <code>"jpaint", "gstein"</code>.
+  </p>
+  <p>                           
+    Wildcard and regular expression searches are entered in a similar
+    way to the quoted requests.  You must quote any wildcard or
+    regular expression request, and a command character preceeds the
+    first quote.  The command character <code>l</code>(lowercase L) is for wildcard
+    searches, and the wildcard character is a percent (<code>%</code>).  The
+    command character for regular expressions is <code>r</code>, and is
+    passed directly to MySQL, so you'll need to refer to the MySQL
+    manual for the exact regex syntax.  It is very similar to Perl.  A
+    wildard search for all files with a <em>.py</em> extention is:
+    <code>l"%.py"</code> in the <em>File</em> input box.  The same search done
+    with a regular expression is: <code>r".*\.py"</code>.
+  </p>
+  <p>                  
+    All search types can be mixed, as long as they are seperated by
+    commas.
+  </p>                                                    
+  </td></tr></table>
+</body></html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_rootview.html
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/help_rootview.html	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,166 @@
+<!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>
+  <title>ViewVC Help: General</title>
+  <link rel="stylesheet" href="help.css" type="text/css" />
+</head>
+<body>
+  <table>
+    <col class="menu" />
+    <col />
+    <tr>
+      <td colspan="2">
+	<h1>ViewVC Help: General</h1>
+      </td>
+    </tr>
+    <tr><td>
+       <h3>Help</h3>
+       <strong>General</strong><br />
+       <a href="help_dirview.html">Directory&nbsp;View</a><br />
+       <a href="help_log.html">Log&nbsp;View</a><br />
+
+       <h3>Internet</h3>
+       <a href="http://viewvc.org/index.html";>Home</a><br />
+       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
+       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
+       <a href="http://viewvc.org/license-1.html";>License</a><br />
+    </td><td colspan="2">
+
+  <p><em>ViewVC</em> is a WWW interface for CVS and Subversion
+  repositories. It allows you to browse the files and directories in a
+  repository while showing you metadata from the repository history: log
+  messages, modification dates, author names, revision numbers, copy
+  history, and so on. It provides several different views of repository
+  data to help you find the information you are looking for:</p>
+
+  <ul>
+    <li><a name="view-dir" href="help_dirview.html"><strong>Directory
+    View</strong></a> - Shows a list of files and subdirectories in a
+    directory of the repository, along with metadata like author names and
+    log entries.</li>
+
+    <li><a name="view-log" href="help_log.html"><strong>Log
+    View</strong></a> - Shows a revision by revision list of all the
+    changes that have made to a file or directory in the repository, with
+    metadata and links to views of each revision.</li>
+
+    <li><a name="view-markup"><strong>File Contents View (Markup
+    View)</strong></a> - Shows the contents of a file at a particular
+    revision, with revision information at the top of the page. File
+    revisions which are GIF, PNG, or JPEG images are displayed inline on
+    the page. Other file types are displayed as marked up text. The markup
+    may be limited to turning URLs and email addresses into links, or
+    configured to show colorized source code.</li>
+
+    <li><a name="view-checkout"><strong>File Download (Checkout
+    View)</strong></a> - Retrieves the unaltered contents of a file
+    revision. Browsers may try to display the file, or just save it to
+    disk.</li>
+
+    <li><a name="view-annotate"><strong>File Annotate View</strong></a> -
+    Shows the contents of a file revision and breaks it down line by line,
+    showing the revision number where each one was last modified, along
+    with links and other information. <em>This view is disabled in some
+    ViewVC configurations</em></li>
+
+    <li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
+    the changes made between two revisions of a file</li>
+
+    <li><a name="view-tarball"><strong>Directory Tarball View</strong> -
+    Retrieves a gzipped tar archive containing the contents of a
+    directory.<em>This view is disabled in the default ViewVC
+    configuration.</em></li>
+
+    <li><a name="view-query"><strong>Directory Query View</strong></a> -
+    Shows information about changes made to all subdirectories and files
+    under a parent directory, sorted and filtered by criteria you specify.
+    <em>This view is disabled in the default ViewVC configuration.</em>
+    </li>
+
+    <li><a name="view-rev"><strong>Revision View</strong> - Shows
+    information about a revision including log message, author, and a list
+    of changed paths. <em>For Subversion repositories only.</em></li>
+
+    <li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
+    graphical representation of a file's revisions and branches complete
+    with tag and author names and links to markup and diff pages.
+    <em>For CVS repositories only, and disabled in the default
+    configuration.</em></li>
+  </ul>
+
+  <h3><a name="multiple-repositories">Multiple Repositories</a></h3>
+
+  <p>A single installation of ViewVC is often used to provide access to
+  more than one repository. In these installations, ViewVC shows a
+  <em>Project Root</em> drop down box in the top right corner of every
+  generated page to allow for quick access to any repository.</p>
+
+  <h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
+
+  <p>By default, ViewVC will show the files and directories and revisions
+  that currently exist in the repository. But it's also possible to browse
+  the contents of a repository at a point in its past history by choosing
+  a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
+  forms at the top of directory and log pages. They're called sticky
+  because once they're chosen, they stick around when you navigate to
+  other pages, until you reset them. When they're set, directory and log
+  pages only show revisions preceding the specified point in history. In
+  CVS, when a tag refers to a branch or a revision on a branch, only
+  revisions from the branch history are shown, including branch points and
+  their preceding revisions.</p>
+
+  <h3><a name="dead-files">Dead Files</a></h3>
+
+  <p>In CVS directory listings, ViewVC can optionally display dead files.
+  Dead files are files which used to be in a directory but are currently
+  deleted, or files which just don't exist in the currently selected
+  <a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
+  shown in Subversion repositories. The only way to see a deleted file in
+  a Subversion directory is to navigate to a sticky revision where the
+  file previously existed.</p>
+
+  <h3><a name="artificial-tags">Artificial Tags</a></h3>
+
+  <p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
+  <em>MAIN</em> to tag listings and accepts them in place of revision
+  numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
+  tag pointing at the default branch, while <em>HEAD</em> acts like a
+  revision tag pointing to the latest revision on the default branch. The
+  default branch is usually just the trunk, but may be set to other
+  branches inside individual repository files. CVS will always check out
+  revisions from a file's default branch when no other branch is specified
+  on the command line.</p>
+
+  <h3><a name="more-information">More Information</a></h3>
+
+  <p>More information about <em>ViewVC</em> is available from
+  <a href="http://viewvc.org/";>viewvc.org</a>.
+  See the links below for guides to CVS and Subversion</p>
+
+  <h4>Documentation about CVS</h4>
+  <blockquote>
+    <p>
+      <a href="http://cvsbook.red-bean.com/";><em>Open Source
+      Development with CVS</em></a><br />
+      <a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html";>CVS
+      User's Guide</a><br />
+      <a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html";>Another CVS tutorial</a><br />
+      <a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/";>Yet another CVS tutorial (a little old, but nice)</a><br />
+      <a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt";>An old but very useful FAQ about CVS</a>
+    </p>
+  </blockquote>
+
+  <h4>Documentation about Subversion</h3>
+  <blockquote>
+    <p>
+      <a href="http://svnbook.red-bean.com/";><em>Version Control with
+      Subversion</em></a><br />
+    </p>
+  </blockquote>
+
+  </td></tr></table>
+  <hr />
+  <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
+  </body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/back.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/back_small.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/broken.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/cvs-logo.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/dir.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/down.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/feed-icon-16x16.jpg
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/forward.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/svn-logo.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/text.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/up.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/images/viewvc-logo.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/scripts.js
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/scripts.js	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,4 @@
+function jumpTo(url)
+{
+  window.location = url;
+}
\ No newline at end of file

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/styles.css
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/docroot/styles.css	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,332 @@
+/*******************************/
+/***  ViewVC CSS Stylesheet ***/
+/*******************************/
+
+/*** Standard Tags ***/
+html, body {
+  background-color: white;
+  color: black;
+  font-family: sans-serif;
+  font-size: 100%;
+  margin: 5px;
+}
+
+a { 
+  text-decoration: none; 
+  color: rgb(30%,30%,60%); 
+}
+img { border: none; }
+table {
+  width: 100%;
+  margin: 0; 
+  border: none;
+}
+td, th { 
+  vertical-align: top; 
+}
+th { white-space: nowrap; }
+table.auto {
+  width: auto;
+}
+table.fixed {
+  width: 100%;
+  table-layout: fixed;
+}
+table.fixed td {
+  overflow: hidden; 
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+form { margin: 0; }
+address { font-style: normal; display: inline; }
+.inline { display: inline; }
+
+/*** Icons ***/
+.vc_icon {
+  width: 16px;
+  height: 16px;
+  border: none;
+  padding: 0 1px;
+}
+
+#vc_header {
+  padding: 0 0 10px 0;
+  border-bottom: 10px solid #94bd5e;
+}
+
+#vc_footer {
+  text-align: right;
+  font-size: 85%;
+  padding: 10px 0 0 0;
+  border-top: 10px solid #94bd5e;
+}
+
+#vc_topmatter {
+  float: right;
+  text-align: right;
+  font-size: 85%;
+}
+
+#vc_current_path {
+  color: rgb(50%,50%,50%);
+  padding: 10px 0;
+  font-size: 140%;
+  font-weight: bold;
+}
+
+#vc_current_path a {
+  color: rgb(60%,60%,60%);
+}
+
+#vc_current_path a:hover {
+  background-color: rgb(90%,90%,90%);
+}
+
+#vc_current_path .thisitem {
+  color: #94bd5e;
+}
+
+#vc_current_path .pathdiv {
+  padding: 0 0.1em;
+}
+
+#vc_view_selection_group {
+  background: black;
+  color: white;
+  margin: 0 0 5px 0;
+  padding: 5px;
+  text-align: right;
+}
+
+#vc_view_selection_group a {
+  padding: 5px;
+  font-size: 100%;
+  color: white;
+  text-decoration: none; 
+}
+
+#vc_view_selection_group a.vc_view_link_this, #vc_view_selection_group a.vc_view_link:hover {
+  color: #94bd5e;
+}
+
+#vc_view_selection_group a:hover {
+  background-color: black;
+}
+
+#vc_view_main {
+  border-top: 1px solid black;
+  border-bottom: 1px solid black;
+}
+
+#vc_togglables {
+  text-align: right;
+  font-size: 85%;
+}
+
+#vc_main_body {
+  background: white;
+  padding: 5px 0 20px 0;
+}
+
+#vc_view_summary {
+  font-size: 85%;
+  text-align: right;
+  margin-top: 5px;
+}
+
+
+/*** Table Headers ***/
+.vc_header, .vc_header_sort {
+  text-align: left;
+  vertical-align: top;
+  border-bottom: 1px solid black;
+  background-color: rgb(80%,80%,80%);
+}
+.vc_header_sort {
+  background-color: rgb(85%,85%,85%);
+}
+
+
+/*** Table Rows ***/
+.vc_row_even {
+  background-color: rgb(95%,95%,95%);
+}
+.vc_row_odd {
+  background-color: rgb(90%,90%,90%);
+}
+
+
+/*** Directory View ***/
+#dirlist td, #dirlist th {
+  padding: 0.2em;
+  vertical-align: middle;
+}
+#dirlist tr:hover {
+  background-color: white;
+}
+
+
+/*** Log messages ***/
+.vc_log {
+  /* unfortunately, white-space: pre-wrap isn't widely supported ... */
+  white-space: -moz-pre-wrap; /* Mozilla based browsers */
+  white-space: -pre-wrap;     /* Opera 4 - 6 */
+  white-space: -o-pre-wrap;   /* Opera >= 7 */
+  white-space: pre-wrap;      /* CSS3 */
+  word-wrap: break-word;      /* IE 5.5+ */
+}
+
+
+/*** Properties Listing ***/
+.vc_properties {
+  margin: 1em 0;
+}
+.vc_properties h2 {
+  font-size: 115%;
+}
+.vc_properties td, .vc_properties th {
+  padding: 0.2em;
+}
+
+
+/*** File Content Markup Styles ***/
+.vc_summary {
+  background-color: #eeeeee;
+}
+#vc_file td {
+  border-right-style: solid;
+  border-right-color: #505050;
+  text-decoration: none;
+  font-weight: normal;
+  font-style: normal;
+  padding: 1px 5px;
+}
+.vc_file_line_number {
+  border-right-width: 1px;
+  background-color: #eeeeee;
+  color: #505050;
+  text-align: right;
+}
+.vc_file_line_author, .vc_file_line_rev {
+  border-right-width: 1px;
+  text-align: right;
+}
+.vc_file_line_text {
+  border-right-width: 0px;
+  background-color: white;
+  font-family: monospace;
+  text-align: left;
+  white-space: pre;
+  width: 100%;
+}
+.pygments-c { color: #408080; font-style: italic } /* Comment */
+.pygments-err { border: 1px solid #FF0000 } /* Error */
+.pygments-k { color: #008000; font-weight: bold } /* Keyword */
+.pygments-o { color: #666666 } /* Operator */
+.pygments-cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.pygments-cp { color: #BC7A00 } /* Comment.Preproc */
+.pygments-c1 { color: #408080; font-style: italic } /* Comment.Single */
+.pygments-cs { color: #408080; font-style: italic } /* Comment.Special */
+.pygments-gd { color: #A00000 } /* Generic.Deleted */
+.pygments-ge { font-style: italic } /* Generic.Emph */
+.pygments-gr { color: #FF0000 } /* Generic.Error */
+.pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.pygments-gi { color: #00A000 } /* Generic.Inserted */
+.pygments-go { color: #808080 } /* Generic.Output */
+.pygments-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.pygments-gs { font-weight: bold } /* Generic.Strong */
+.pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.pygments-gt { color: #0040D0 } /* Generic.Traceback */
+.pygments-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.pygments-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.pygments-kp { color: #008000 } /* Keyword.Pseudo */
+.pygments-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.pygments-kt { color: #B00040 } /* Keyword.Type */
+.pygments-m { color: #666666 } /* Literal.Number */
+.pygments-s { color: #BA2121 } /* Literal.String */
+.pygments-na { color: #7D9029 } /* Name.Attribute */
+.pygments-nb { color: #008000 } /* Name.Builtin */
+.pygments-nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.pygments-no { color: #880000 } /* Name.Constant */
+.pygments-nd { color: #AA22FF } /* Name.Decorator */
+.pygments-ni { color: #999999; font-weight: bold } /* Name.Entity */
+.pygments-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.pygments-nf { color: #0000FF } /* Name.Function */
+.pygments-nl { color: #A0A000 } /* Name.Label */
+.pygments-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.pygments-nt { color: #008000; font-weight: bold } /* Name.Tag */
+.pygments-nv { color: #19177C } /* Name.Variable */
+.pygments-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.pygments-w { color: #bbbbbb } /* Text.Whitespace */
+.pygments-mf { color: #666666 } /* Literal.Number.Float */
+.pygments-mh { color: #666666 } /* Literal.Number.Hex */
+.pygments-mi { color: #666666 } /* Literal.Number.Integer */
+.pygments-mo { color: #666666 } /* Literal.Number.Oct */
+.pygments-sb { color: #BA2121 } /* Literal.String.Backtick */
+.pygments-sc { color: #BA2121 } /* Literal.String.Char */
+.pygments-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.pygments-s2 { color: #BA2121 } /* Literal.String.Double */
+.pygments-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.pygments-sh { color: #BA2121 } /* Literal.String.Heredoc */
+.pygments-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.pygments-sx { color: #008000 } /* Literal.String.Other */
+.pygments-sr { color: #BB6688 } /* Literal.String.Regex */
+.pygments-s1 { color: #BA2121 } /* Literal.String.Single */
+.pygments-ss { color: #19177C } /* Literal.String.Symbol */
+.pygments-bp { color: #008000 } /* Name.Builtin.Pseudo */
+.pygments-vc { color: #19177C } /* Name.Variable.Class */
+.pygments-vg { color: #19177C } /* Name.Variable.Global */
+.pygments-vi { color: #19177C } /* Name.Variable.Instance */
+.pygments-il { color: #666666 } /* Literal.Number.Integer.Long */
+
+
+/*** Diff Styles ***/
+.vc_diff_plusminus { width: 1em; }
+.vc_diff_remove, .vc_diff_add, .vc_diff_changes1, .vc_diff_changes2 { 
+  font-family: monospace; 
+  white-space: pre; 
+}
+.vc_diff_remove { background: rgb(100%,60%,60%); }
+.vc_diff_add { background: rgb(60%,100%,60%); }
+.vc_diff_changes1 { background: rgb(100%,100%,70%); color: rgb(50%,50%,50%); text-decoration: line-through; }
+.vc_diff_changes2 { background: rgb(100%,100%,0%); }
+.vc_diff_nochange, .vc_diff_binary, .vc_diff_error {
+  font-family: sans-serif;
+  font-size: smaller;
+}
+
+/*** Intraline Diff Styles ***/
+.vc_idiff_add {
+  background-color: #aaffaa;
+}
+.vc_idiff_change {
+  background-color:#ffff77;
+}
+.vc_idiff_remove {
+  background-color:#ffaaaa;
+}
+.vc_idiff_empty {
+  background-color:#e0e0e0;
+}
+
+table.vc_idiff col.content { 
+  width: 50%;
+}
+table.vc_idiff tbody {
+  font-family: monospace; 
+  /* unfortunately, white-space: pre-wrap isn't widely supported ... */
+  white-space: -moz-pre-wrap; /* Mozilla based browsers */
+  white-space: -pre-wrap;     /* Opera 4 - 6 */
+  white-space: -o-pre-wrap;   /* Opera >= 7 */
+  white-space: pre-wrap;      /* CSS3 */
+  word-wrap: break-word;      /* IE 5.5+ */
+}
+table.vc_idiff tbody th {
+  background-color:#e0e0e0;
+  text-align:right;
+}
+
+
+/*** Query Form ***/
+.vc_query_form {
+}

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/error.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/error.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,51 @@
+<!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">
+<!-- ViewVC :: http://www.viewvc.org/ -->
+<head>
+<title>ViewVC Exception</title>
+</head>
+<body>
+<h3>An Exception Has Occurred</h3>
+
+[if-any msg]
+  <p>[msg]</p>
+[end]
+
+[if-any status]
+  <h4>HTTP Response Status</h4>
+  <p><pre>[status]</pre></p>
+  <hr />
+[end]
+
+[if-any msg][else]
+<h4>Python Traceback</h4>
+<p><pre>
+[stacktrace]
+</pre></p>
+[end]
+
+[# Here follows a bunch of space characters, present to ensure that
+   our error message is larger than 512 bytes so that IE's "Friendly
+   Error Message" won't show.  For more information, see
+   http://oreillynet.com/onjava/blog/2002/09/internet_explorer_subverts_err.html]
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+                                                            
+</body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/file.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/file.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,61 @@
+[# setup page definitions]
+  [define page_title]Annotation of:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+[include "include/header.ezt" "annotate"]
+[include "include/fileview.ezt"]
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+[define last_rev]0[end]
+[define rowclass]vc_row_odd[end]
+
+[if-any lines]
+<div id="vc_file">
+<table cellspacing="0" cellpadding="0">
+<tr>
+<th class="vc_header">Line</th>
+[is annotation "annotated"]
+<th class="vc_header">User</th>
+<th class="vc_header">Rev</th>
+[end]
+<th class="vc_header">File contents</th>
+</tr>
+[for lines]
+  [is lines.rev last_rev]
+  [else]
+    [is rowclass "vc_row_even"]
+      [define rowclass]vc_row_odd[end]
+    [else]
+      [define rowclass]vc_row_even[end]
+    [end]
+  [end]
+
+  <tr class="[rowclass]" id="l[lines.line_number]">
+    <td class="vc_file_line_number">[lines.line_number]</td>
+[is annotation "annotated"]
+    <td class="vc_file_line_author">[is lines.rev last_rev]&nbsp;[else][lines.author][end]</td>
+    <td class="vc_file_line_rev">[is lines.rev last_rev]&nbsp;[else][if-any lines.diff_href]<a href="[lines.diff_href]">[end][lines.rev][if-any lines.diff_href]</a>[end][end]</td>
+[end]
+    <td class="vc_file_line_text">[lines.text]</td>
+  </tr>
+  [define last_rev][lines.rev][end]
+[end]
+</table>
+</div>
+
+[else]
+[if-any image_src_href]
+<div id="vc_file_image">
+<img src="[image_src_href]" alt="" />
+</div>
+[end]
+[end]
+
+[include "include/props.ezt"]
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/graph.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/graph.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,15 @@
+[# setup page definitions]
+  [define page_title]Graph of:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "graph"]
+
+<div style="text-align:center;">
+[imagemap]
+<img usemap="#MyMapName"
+  src="[imagesrc]" 
+  alt="Revisions of [where]" />
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/diff_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/diff_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,70 @@
+
+<div style="border-bottom: solid 1px black;">
+<p id="diff">This form allows you to request diffs between any two
+  revisions of this file.
+  For each of the two "sides" of the diff,
+[if-any tags]
+  select a symbolic revision name using the selection box, or choose
+  'Use Text Field' and enter a numeric revision.
+[else]
+  enter a numeric revision.
+[end]
+</p>
+
+<form method="get" action="[diff_select_action]" id="diff_select">
+
+  <table cellpadding="2" cellspacing="0" class="auto">
+  <tr>
+  <td>&nbsp;</td>
+  <td>
+  [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
+  Diffs between
+[if-any tags]
+  <select name="r1">
+    <option value="text" selected="selected">Use Text Field</option>
+  [for tags]
+    <option value="[tags.rev]:[tags.name]">[tags.name]</option>
+  [end]
+  </select>
+  <input type="text" size="12" name="tr1" 
+         value="[if-any rev_selected][rev_selected][else][first_revision][end]"
+         onchange="document.getElementById('diff_select').r1.selectedIndex=0" />
+[else]
+  <input type="text" size="12" name="r1"
+         value="[if-any rev_selected][rev_selected][else][first_revision][end]" />
+[end]
+
+  and
+[if-any tags]
+  <select name="r2">
+    <option value="text" selected="selected">Use Text Field</option>
+  [for tags]
+    <option value="[tags.rev]:[tags.name]">[tags.name]</option>
+  [end]
+  </select>
+  <input type="text" size="12" name="tr2" 
+         value="[last_revision]"
+         onchange="document.getElementById('diff_select').r2.selectedIndex=0" />
+[else]
+  <input type="text" size="12" name="r2" value="[last_revision]" />
+[end]
+  </td>
+  </tr>
+  <tr>
+  <td>&nbsp;</td>
+  <td>
+  Type of Diff should be a
+  <select name="diff_format" onchange="submit()">
+    <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
+    <option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>
+    <option value="f" [is diff_format "f"]selected="selected"[end]>Full Colored Diff</option>
+    <option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
+    <option value="c" [is diff_format "c"]selected="selected"[end]>Context Diff</option>
+    <option value="s" [is diff_format "s"]selected="selected"[end]>Side by Side</option>
+  </select>
+  <input type="submit" value="  Get Diffs  " />
+  </td>
+  </tr>
+  </table>
+  </form>
+</div>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/fileview.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/fileview.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,74 @@
+<table class="auto">
+<tr>
+<td>Revision:</td>
+<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong> [if-any vendor_branch] <em>(vendor branch)</em>[end]</td> 
+</tr>
+<tr>
+<tr>
+<td>Committed:</td>
+<td>[if-any date]<em>[date]</em> [end][if-any ago]([ago] ago) [end][if-any author]by <em>[author]</em>[end]</td>
+</tr>
+[if-any orig_path]
+<tr>
+<td>Original Path:</td>
+<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
+</tr>
+[end]
+[if-any branches]
+<tr>
+<td>Branch:</td>
+<td><strong>[branches]</strong></td>
+</tr>
+[end]
+[if-any tags]
+<tr>
+<td>CVS Tags:</td>
+<td><strong>[tags]</strong></td>
+</tr>
+[end]
+[if-any branch_points]
+<tr>
+<td>Branch point for:</td>
+<td><strong>[branch_points]</strong></td>
+</tr>
+[end]
+[is roottype "cvs"][if-any changed]
+<tr>
+<td>Changes since <strong>[prev]</strong>:</td>
+<td><strong>[changed] lines</strong></td>
+</tr>
+[end][end]
+[is roottype "svn"][if-any size]
+<td>File size:</td>
+<td>[size] byte(s)</td>
+</tr>
+[end][end]
+[if-any lockinfo]
+<td>Lock status:</td>
+<td>[lockinfo]</td>
+[end]
+[is state "dead"]
+<tr>
+<td>State:</td>
+<td><strong><em>FILE REMOVED</em></strong></td>
+</tr>
+[end]
+[if-any annotation]
+[is annotation "binary"]
+<tr>
+<td colspan="2"><strong>Unable to calculate annotation data on binary file contents.</strong></td>
+</tr>
+[end]
+[is annotation "error"]
+<tr>
+<td colspan="2"><strong>Error occurred while calculating annotation data.</strong></td>
+</tr>
+[end]
+[end]
+[if-any log]
+<tr>
+<td>Log Message:</td>
+<td><pre class="vc_log">[log]</span></td>
+</tr>
+[end]
+</table>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/footer.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/footer.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,10 @@
+</div> <!-- vc_view_main -->
+
+<div id="vc_footer">
+[if-any cfg.general.address]Administered by <address><a href="mailto:[cfg.general.address]";>[cfg.general.address]</a></address><br/>[end]
+Powered by <a href="http://viewvc.tigris.org/";>ViewVC [vsn]</a>
+[if-any rss_href]<br/><a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg" class="vc_icon" alt="RSS 2.0 feed" /></a>[else]&nbsp;[end]
+</div>
+
+</body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/header.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/header.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,63 @@
+<!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">
+
+<!-- ViewVC :: http://www.viewvc.org/ -->
+
+<head>
+  <title>[[]ViewVC] [page_title] [if-any rootname][rootname][if-any where]/[where][end][end]</title>
+  <meta name="generator" content="ViewVC [vsn]" />
+  <link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
+  <script src="[docroot]/scripts.js"></script>
+  [if-any rss_href]
+  <link rel="alternate" type="application/rss+xml" href="[rss_href]" title="ViewVC RSS: [if-any rootname][rootname][if-any where]/[where][end][end]">
+  [end]
+</head>
+
+<body>
+
+<div id="vc_header">
+
+<div id="vc_topmatter">
+[if-any username]Logged in as: <strong>[username]</strong> |[end]
+<a href="[help_href]">ViewVC Help</a>
+</div>
+
+<div id="vc_logo">
+<a href="http://www.viewvc.org/";><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a>
+</div>
+
+<div id="vc_view_selection_group">
+[is pathtype "dir"]
+  <a class="vc_view_link[is view "dir"]_this[end]" href="[view_href]">View Directory</a>
+  [if-any log_href]
+  | <a class="vc_view_link[is view "log"]_this[end]" href="[log_href]">Revision Log</a>
+  [end]
+  [if-any queryform_href]
+  | <a class="vc_view_link[is view "queryform"]_this[end]" href="[queryform_href]">Commit Query</a>
+  [end]
+  [if-any tarball_href]
+  | <a class="vc_view_link" href="[tarball_href]">Download Tarball</a>
+  [end]
+[end]
+[is pathtype "file"]
+  <a class="vc_view_link[is view "markup"]_this[end]" href="[view_href]">View File</a>
+  | <a class="vc_view_link[is view "log"]_this[end]" href="[log_href]">Revision Log</a>
+  | <a class="vc_view_link[is view "annotate"]_this[end]" href="[annotate_href]">Show Annotations</a>
+  [if-any graph_href]
+  | <a class="vc_view_link[is view "graph"]_this[end]" href="[graph_href]">Revision Graph</a>
+  [end]
+  | <a class="vc_view_link" href="[download_href]">Download File</a>
+[end]
+[if-any revision_href]
+  | <a class="vc_view_link[is view "revision"]_this[end]" href="[revision_href]">View Changeset</a>
+[end]
+  | <a class="vc_view_link[is view "roots"]_this[end]" href="[roots_href]">Root Listing</a>
+</div>
+
+<div id="vc_current_path">
+[if-any roots_href]<a href="[roots_href]">root</a>[end][if-any nav_path]<span class="pathdiv">/</span>[for nav_path][if-any nav_path.href]<a href="[nav_path.href]">[end][if-index nav_path last]<span class="thisitem">[end][nav_path.name][if-index nav_path last]</span>[end][if-any nav_path.href]</a>[end][if-index nav_path last][else]<span class="pathdiv">/</span>[end][end][end]
+</div>
+
+</div> <!-- vc_header -->
+
+<div id="vc_view_main">

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/pathrev_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/pathrev_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,53 @@
+<form method="get" action="[pathrev_action]" style="display: inline">
+<div style="display: inline">
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
+[is roottype "cvs"]
+  [define pathrev_selected][pathrev][end]
+  <select name="pathrev" onchange="submit()">
+  <option value=""></option>
+  [if-any branch_tags]
+    <optgroup label="Branches">
+    [for branch_tags]
+      [is branch_tags pathrev]
+        <option selected>[branch_tags]</option>
+        [define pathrev_selected][end]
+      [else]
+        <option>[branch_tags]</option>
+      [end]
+    [end]
+    </optgroup>
+  [end]
+  <optgroup label="Non-branch tags">
+  [for plain_tags]
+    [is plain_tags pathrev]
+      <option selected>[plain_tags]</option>
+      [define pathrev_selected][end]
+    [else]
+      <option>[plain_tags]</option>
+    [end]
+  [end]
+  </optgroup>
+  [if-any pathrev_selected]
+    <option selected>[pathrev_selected]</option>
+  [end]
+  </select>
+[else]
+  <input type="text" name="pathrev" value="[pathrev]" size="6"/>
+[end]
+<input type="submit" value="Set Sticky [is roottype "cvs"]Tag[else]Revision[end]" />
+</div>
+</form>
+
+[if-any pathrev]
+<form method="get" action="[pathrev_clear_action]" style="display: inline">
+<div style="display: inline">
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
+[if-any lastrev]
+  [is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
+  (<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)
+[else]
+  <input type="submit" value="Clear" />
+[end]
+</div>
+</form>
+[end]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/props.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/include/props.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,26 @@
+[if-any properties]
+<hr/>
+<div class="vc_properties">
+<h2>Properties</h2>
+<table cellspacing="2" class="fixed">
+<thead>
+  <tr>
+    <th class="vc_header_sort" style="width: 200px;">Name</th>
+    <th class="vc_header">Value</th>
+  </tr>
+</thead>
+<tbody>
+[for properties]
+  <tr class="vc_row_[if-index properties even]even[else]odd[end]">
+    <td><strong>[properties.name]</strong></td>
+    [if-any properties.undisplayable]
+    <td><em>Property value is undisplayable.</em></td>
+    [else]
+    <td style="white-space: pre;">[properties.value]</td>
+    [end]
+  </tr>
+[end]
+</tbody>
+</table>
+</div>
+[end]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/log.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/log.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,247 @@
+[# setup page definitions]
+  [define page_title]Log of:[end]
+  [define help_href][docroot]/help_log.html[end]
+[# end]
+[include "include/header.ezt" "log"]
+
+<table class="auto">
+
+[if-any default_branch]
+<tr>
+  <td>Default branch:</td>
+  <td>[for default_branch]<a href="[default_branch.href]">[default_branch.name]</a>[if-index default_branch last][else], [end]
+[end]</td>
+</tr>
+[end]
+
+[is pathtype "file"]
+[if-any view_href]
+<tr>
+  <td>Links to HEAD:</td>
+  <td>
+    (<a href="[view_href]">view</a>)
+    [if-any download_href](<a href="[download_href]">download</a>)[end]
+    [if-any download_text_href](<a href="[download_text_href]">as text</a>)[end]
+    [if-any annotate_href](<a href="[annotate_href]">annotate</a>)[end]
+  </td>
+</tr>
+[end]
+
+[if-any tag_view_href]
+<tr>
+  <td>Links to [pathrev]:</td>
+  <td>
+    (<a href="[tag_view_href]">view</a>)
+    [if-any tag_download_href](<a href="[tag_download_href]">download</a>)[end]
+    [if-any tag_download_text_href](<a href="[tag_download_text_href]">as text</a>)[end]
+    [if-any tag_annotate_href](<a href="[tag_annotate_href]">annotate</a>)[end]
+  </td>
+</tr>
+[end]
+[end]
+
+<tr>
+  <td>Sticky [is roottype "cvs"]Tag[else]Revision[end]:</td>
+  <td>[include "include/pathrev_form.ezt"]</td>
+</tr>
+
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]    
+<tr>
+  <td>Jump to page:</td>
+  <td><form method="get" action="[log_paging_action]">
+        [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
+        <select name="log_pagestart"  onchange="submit()">
+          [for picklist]
+           [if-any picklist.more]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+           [else]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+           [end]
+          [end]
+        </select>
+        <input type="submit" value="Go" />
+      </form>
+  </td>
+</tr>
+[end][end]
+
+<tr>
+  <td>Sort logs by:</td>
+  <td><form method="get" action="[logsort_action]">
+      <div>
+        <a name="logsort"></a>
+          [for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
+          <select name="logsort" onchange="submit()">
+            <option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
+            <option value="date" [is logsort "date"]selected="selected"[end]>Commit date</option>
+            <option value="rev" [is logsort "rev"]selected="selected"[end]>Revision</option>
+          </select>
+          <input type="submit" value="  Sort  " />
+      </div>
+    </form>
+  </td>
+</tr>
+
+</table>
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+[define first_revision][end]
+[define last_revision][end]
+
+[for entries]
+
+[if-index entries first][define first_revision][entries.rev][end][end]
+[if-index entries last]
+[define last_revision][entries.rev][end]
+<div>
+[else]
+<div style="border-bottom: 1px dotted black">
+[end]
+
+  [is entries.state "dead"]
+    Revision <strong>[entries.rev]</strong>
+  [else]
+    <a name="rev[entries.rev]"></a>
+    [for entries.tag_names]<a name="[entries.tag_names]"></a>
+    [end]
+    [for entries.branch_names]<a name="[entries.branch_names]"></a>
+    [end]
+
+    Revision [is roottype "svn"]<a href="[entries.revision_href]"><strong>[entries.rev]</strong></a>[else]<strong>[entries.rev]</strong>[end] -
+    [if-any entries.view_href]
+      [is pathtype "file"]
+        (<a href="[entries.view_href]">view</a>)
+      [else]
+        <a href="[entries.view_href]">Directory Listing</a>
+      [end]
+    [end]
+    [if-any entries.download_href](<a href="[entries.download_href]">download</a>)[end]
+    [if-any entries.download_text_href](<a href="[entries.download_text_href]">as text</a>)[end]
+    [if-any entries.annotate_href](<a href="[entries.annotate_href]">annotate</a>)[end]
+
+    [is pathtype "file"]
+      [# if you don't want to allow select for diffs then remove this section]
+      [is entries.rev rev_selected]
+        - <strong>[[]selected]</strong>
+      [else]
+        - <a href="[entries.sel_for_diff_href]">[[]select for diffs]</a>
+      [end]
+    [end]
+  [end]
+
+  [if-any entries.vendor_branch]
+    <em>(vendor branch)</em>
+  [end]
+
+  <br />
+
+  [is roottype "svn"]
+    [if-index entries last]Added[else]Modified[end]
+  [end]
+
+  <em>[if-any entries.date][entries.date][else](unknown date)[end]</em>
+  [if-any entries.ago]([entries.ago] ago)[end] 
+  by <em>[if-any entries.author][entries.author][else](unknown author)[end]</em>
+
+  [if-any entries.orig_path]
+    <br />Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a>
+  [end]
+
+  [if-any entries.branches]
+    <br />Branch:
+    [for entries.branches]
+      <a href="[entries.branches.href]"><strong>[entries.branches.name]</strong></a>[if-index entries.branches last][else],[end]
+    [end]
+  [end]
+
+  [if-any entries.tags]
+    <br />CVS Tags:
+    [for entries.tags]
+      <a href="[entries.tags.href]"><strong>[entries.tags.name]</strong></a>[if-index entries.tags last][else],[end]
+    [end]
+  [end]
+
+  [if-any entries.branch_points]
+    <br />Branch point for:
+    [for entries.branch_points]
+      <a href="[entries.branch_points.href]"><strong>[entries.branch_points.name]</strong></a>[if-index entries.branch_points last][else],[end]
+    [end]
+  [end]
+
+  [if-any entries.prev]
+    [if-any entries.changed]
+      [is roottype "cvs"]
+      <br />Changes since <strong>[entries.prev]: [entries.changed] lines</strong>
+      [end]
+    [end]
+  [end]
+
+  [if-any entries.lockinfo]
+    <br />Lock status: [entries.lockinfo]
+  [end]
+
+  [is roottype "svn"]
+    [if-any entries.size]
+    <br />File length: [entries.size] byte(s)
+    [end]
+
+    [if-any entries.copy_path]
+    <br />Copied from: <a href="[entries.copy_href]"><em>[entries.copy_path]</em></a> revision [entries.copy_rev]
+    [end]
+  [end]
+
+  [is entries.state "dead"]
+    <br /><strong><em>FILE REMOVED</em></strong>
+  [else]
+   [is pathtype "file"]
+    [if-any entries.prev]
+      <br />Diff to <a href="[entries.diff_to_prev_href]">previous [entries.prev]</a>
+      [if-any human_readable]
+      [else]
+        (<a href="[entries.diff_to_prev_href]&amp;diff_format=h">colored</a>)
+      [end]
+    [end]
+
+    [is roottype "cvs"]
+      [if-any entries.branch_point]
+        , to <a href="[entries.diff_to_branch_href]">branch point [entries.branch_point]</a>
+        [if-any human_readable]
+        [else]
+           (<a href="[entries.diff_to_branch_href]&amp;diff_format=h">colored</a>)
+        [end]
+      [end]
+  
+      [if-any entries.next_main]
+        , to <a href="[entries.diff_to_main_href]">next main [entries.next_main]</a>
+        [if-any human_readable]
+        [else]
+           (<a href="[entries.diff_to_main_href]&amp;diff_format=h">colored</a>)
+        [end]
+      [end]
+    [end]
+
+    [if-any entries.diff_to_sel_href]
+      [if-any entries.prev], [else]<br />Diff[end]
+        to <a href="[entries.diff_to_sel_href]">selected [rev_selected]</a>
+      [if-any human_readable]
+      [else]
+        (<a href="[entries.diff_to_sel_href]&amp;diff_format=h">colored</a>)
+      [end]
+    [end]
+   [end]
+  [end]
+
+<pre class="vc_log">[entries.log]</pre>
+</div>
+[end]
+
+<!-- ************************************************************** -->
+</div>
+
+[is pathtype "file"]
+  [include "include/diff_form.ezt"]
+[end]
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/markup.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/markup.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,18 @@
+[# setup page definitions]
+  [define page_title]View of:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+[include "include/header.ezt" "markup"]
+[include "include/fileview.ezt"]
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+<div id="vc_markup"><pre>[markup]</pre></div>
+
+[include "include/props.ezt"]
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,241 @@
+<!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">
+<!-- ViewVC :: http://www.viewvc.org/ -->
+<head>
+  <title>Checkin Database Query</title>
+  <link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
+</head>
+
+<body>
+
+[# setup page definitions]
+  [define help_href][docroot]/help_query.html[end]
+[# end]
+
+  <p> 
+    Select your parameters for querying the CVS commit database.  You
+    can search for multiple matches by typing a comma-seperated list
+    into the text fields.  Regular expressions, and wildcards are also
+    supported.  Blank text input fields are treated as wildcards.
+  </p>
+  <p>
+    Any of the text entry fields can take a comma-seperated list of
+    search arguments.  For example, to search for all commits from
+    authors <em>jpaint</em> and <em>gstein</em>, just type: <strong>jpaint,
+    gstein</strong> in the <em>Author</em> input box.  If you are searching
+    for items containing spaces or quotes, you will need to quote your
+    request.  For example, the same search above with quotes is:
+    <strong>"jpaint", "gstein"</strong>.
+  </p>
+  <p>                           
+
+    Wildcard and regular expression searches are entered in a similar
+    way to the quoted requests.  You must quote any wildcard or
+    regular expression request, and a command charactor preceeds the
+    first quote.  The command charactor <strong>l</strong> is for wildcard
+    searches, and the wildcard charactor is a percent (<strong>%</strong>).  The
+    command charactor for regular expressions is <strong>r</strong>, and is
+    passed directly to MySQL, so you'll need to refer to the MySQL
+    manual for the exact regex syntax.  It is very similar to Perl.  A
+    wildard search for all files with a <em>.py</em> extention is:
+    <strong>l"%.py"</strong> in the <em>File</em> input box.  The same search done
+    with a regular expression is: <strong>r".*\.py"</strong>.
+  </p>
+  <p>                  
+    All search types can be mixed, as long as they are seperated by
+    commas.
+  </p>                                                    
+
+<form method="get" action="">
+
+<div class="vc_query_form">
+<table cellspacing="0" cellpadding="2" class="auto">
+ <tr>
+  <td>
+   <table>
+    <tr>
+     <td style="vertical-align:top;">
+
+      <table>
+       <tr>
+        <td align="right">CVS Repository:</td>
+        <td>
+         <input type="text" name="repository" size="40" value="[repository]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">CVS Branch:</td>
+        <td>
+         <input type="text" name="branch" size="40" value="[branch]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">Directory:</td>
+        <td>
+         <input type="text" name="directory" size="40" value="[directory]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">File:</td>
+        <td>
+         <input type="text" name="file" size="40" value="[file]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">Author:</td>
+        <td>
+         <input type="text" name="who" size="40" value="[who]" />
+        </td>
+       </tr>
+      </table>
+
+     </td>
+     <td style="vertical-align:top;">
+
+      <table>
+       <tr>
+        <td align="left">Sort By:</td>
+        <td>
+         <select name="sortby">
+          <option value="date" [is sortby "date"]selected="selected"[end]>Date</option>
+          <option value="author" [is sortby "author"]selected="selected"[end]>Author</option>
+          <option value="file" [is sortby "file"]selected="selected"[end]>File</option>
+         </select>
+        </td>
+       </tr>
+       <tr>
+        <td colspan="2">
+         <table cellspacing="0" cellpadding="0">
+          <tr>
+           <td>Date:</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="hours"
+		  [is date "hours"]checked="checked"[end] /></td>
+           <td>In the last
+             <input type="text" name="hours" value="[hours]" size="4" />hours
+           </td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="day"
+		  [is date "day"]checked="checked"[end] /></td>
+           <td>In the last day</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="week"
+		  [is date "week"]checked="checked"[end] /></td>
+           <td>In the last week</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="month"
+		  [is date "month"]checked="checked"[end] /></td>
+           <td>In the last month</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="all"
+		  [is date "all"]checked="checked"[end] /></td>
+           <td>Since the beginning of time</td>
+          </tr>
+         </table>
+        </td>
+       </tr>
+      </table>
+
+     </td>
+    </tr>
+   </table>
+  </td>
+  <td>
+   <input type="submit" value="Search" />
+  </td>
+ </tr>
+</table>
+</div>
+
+</form>
+
+[is query "skipped"]
+[else]
+<p><strong>[num_commits]</strong> matches found.</p>
+
+[if-any commits]
+<table cellspacing="0" cellpadding="2">
+ <thead>
+ <tr class="vc_header">
+  <th>Revision</th>
+  <th>File</th>
+  <th>Branch</th>
+  <th>+/-</th>
+  <th>Date</th>
+  <th>Author</th>
+[# uncommment, if you want a separate Description column: (also see below)
+<th>Description</th>
+]
+ </tr>
+ </thead>
+[for commits]
+ <tbody>
+  [for commits.files]
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td style="vertical-align:top;">
+	[if-any commits.files.rev][commits.files.rev][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">[commits.files.link]</td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.branch][commits.files.branch][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">
+        [is commits.files.type "Add"]<ins>[end]
+        [is commits.files.type "Change"]<a href="[commits.files.difflink]">[end]
+        [is commits.files.type "Remove"]<del>[end]
+          [commits.files.plus]/[commits.files.minus]
+        [is commits.files.type "Add"]</ins>[end]
+        [is commits.files.type "Change"]</a>[end]
+        [is commits.files.type "Remove"]</del>[end]
+      </td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.date][commits.files.date][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.author][commits.files.author][else]&nbsp;[end]
+      </td>
+
+[# uncommment, if you want a separate Description column:
+      {if-index commits.files first{
+        <td style="vertical-align:top;" rowspan="{commits.num_files}">
+          {commits.log}
+        </td>
+      {end}
+
+   (substitute brackets for the braces)
+]
+    </tr>
+[# and also take the following out in the "Description column"-case:]
+      [if-index commits.files last]
+	<tr class="vc_row_[if-index commits even]even[else]odd[end]">
+	  <td>&nbsp;</td>
+	  <td colspan="5"><strong>Log:</strong><br />
+	    <pre class="vc_log">[commits.log]</pre></td>
+	</tr>
+      [end]
+[# ---]
+  [end]
+ </tbody>
+[end]
+
+ <tr class="vc_header">
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+[# uncommment, if you want a separate Description column:
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+]
+ </tr>
+</table>
+[end]
+[end]
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,201 @@
+[# setup page definitions]
+  [define page_title]Query on:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+[include "include/header.ezt" "query"]
+
+<form action="[query_action]" method="get">
+
+<div class="vc_query_form">
+  [for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
+<table cellspacing="0" cellpadding="5" class="auto">
+  [is roottype "cvs"]
+  [# For subversion, the branch field is not used ]
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Branch:</th>
+    <td>
+      <input type="text" name="branch" value="[branch]" />
+      <label for="branch_match_exact">
+        <input type="radio" name="branch_match" id="branch_match_exact"
+           value="exact" [is branch_match "exact"]checked="checked"[end] />
+        exact
+      </label>
+      <label for="branch_match_glob">
+        <input type="radio" name="branch_match" id="branch_match_glob"
+           value="glob" [is branch_match "glob"]checked="checked"[end] />
+        glob pattern
+      </label>
+      <label for="branch_match_regex">
+        <input type="radio" name="branch_match" id="branch_match_regex"
+           value="regex" [is branch_match "regex"]checked="checked"[end] />
+        regex
+      </label>
+      <label for="branch_match_notregex">
+        <input type="radio" name="branch_match" id="branch_match_notregex"
+           value="notregex" [is branch_match "notregex"]checked="checked"[end] />
+        <em>not</em> regex
+      </label>
+    </td>
+  </tr>
+  [end]
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Subdirectory:</th>
+    <td>
+      <input type="text" name="dir" value="[dir]" />
+      <em>(You can list multiple directories separated by commas.)</em>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">File:</th>
+    <td>
+      <input type="text" name="file" value="[file]" />
+      <label for="file_match_exact">
+        <input type="radio" name="file_match" id="file_match_exact"
+           value="exact" [is file_match "exact"]checked="checked"[end] />
+        exact
+      </label>
+      <label for="file_match_glob">
+        <input type="radio" name="file_match" id="file_match_glob"
+           value="glob" [is file_match "glob"]checked="checked"[end] />
+        glob pattern
+      </label>
+      <label for="file_match_regex">
+        <input type="radio" name="file_match" id="file_match_regex"
+           value="regex" [is file_match "regex"]checked="checked"[end] />
+        regex
+      </label>
+      <label for="file_match_notregex">
+        <input type="radio" name="file_match" id="file_match_notregex"
+           value="notregex" [is file_match "notregex"]checked="checked"[end] />
+        <em>not</em> regex
+      </label>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Who:</th>
+    <td>
+      <input type="text" name="who" value="[who]" />
+      <label for="who_match_exact">
+        <input type="radio" name="who_match" id="who_match_exact"
+           value="exact" [is who_match "exact"]checked="checked"[end] />
+        exact
+      </label>
+      <label for="who_match_glob">
+        <input type="radio" name="who_match" id="who_match_glob"
+           value="glob" [is who_match "glob"]checked="checked"[end] />
+        glob pattern
+      </label>
+      <label for="who_match_regex">
+        <input type="radio" name="who_match" id="who_match_regex"
+           value="regex" [is who_match "regex"]checked="checked"[end] />
+        regex
+      </label>
+      <label for="who_match_notregex">
+        <input type="radio" name="who_match" id="who_match_notregex"
+           value="notregex" [is who_match "notregex"]checked="checked"[end] />
+        <em>not</em> regex
+      </label>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Comment:</th>
+    <td>
+      <input type="text" name="comment" value="[comment]" />
+      <label for="comment_match_exact">
+        <input type="radio" name="comment_match" id="comment_match_exact"
+           value="exact" [is comment_match "exact"]checked=""[end] />
+        exact
+      </label>
+      <label for="comment_match_glob">
+        <input type="radio" name="comment_match" id="comment_match_glob"
+           value="glob" [is comment_match "glob"]checked=""[end] />
+        glob pattern
+      </label>
+      <label for="comment_match_regex">
+        <input type="radio" name="comment_match" id="comment_match_regex"
+           value="regex" [is comment_match "regex"]checked=""[end] />
+        regex
+      </label>
+      <label for="comment_match_notregex">
+        <input type="radio" name="comment_match" id="comment_match_notregex"
+           value="notregex" [is comment_match "notregex"]checked=""[end] />
+        <em>not</em> regex
+      </label>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Sort By:</th>
+    <td>
+      <select name="querysort">
+        <option value="date" [is querysort "date"]selected="selected"[end]>Date</option>
+        <option value="author" [is querysort "author"]selected="selected"[end]>Author</option>
+        <option value="file" [is querysort "file"]selected="selected"[end]>File</option>
+      </select>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Date:</th>
+    <td>
+      <table cellspacing="0" cellpadding="0">
+        <tr>
+          <td><input type="radio" name="date" id="date_hours"
+                 value="hours" [is date "hours"]checked="checked"[end] /></td>
+          <td>
+            <label for="date_hours">In the last</label>
+            <input type="text" name="hours" value="[hours]" size="4" />
+            hours
+          </td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_day"
+                 value="day" [is date "day"]checked="checked"[end] /></td>
+          <td><label for="date_day">In the last day</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_week"
+                 value="week" [is date "week"]checked="checked"[end] /></td>
+          <td><label for="date_week">In the last week</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_month"
+                 value="month" [is date "month"]checked="checked"[end] /></td>
+          <td><label for="date_month">In the last month</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_all"
+                 value="all" [is date "all"]checked="checked"[end] /></td>
+          <td><label for="date_all">Since the beginning of time</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_explicit"
+                 value="explicit" [is date "explicit"]checked="checked"[end] /></td>
+          <td>
+            <label for="date_explicit">Between</label>
+            <input type="text" name="mindate" value="[mindate]" size="20" />
+            and
+            <input type="text" name="maxdate" value="[maxdate]" size="20" />
+            <br />
+            (use the form <strong>yyyy-mm-dd hh:mm:ss</strong>)
+          </td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Limit:</th>
+    <td>
+      Show at most
+      <input type="text" name="limit_changes" value="[limit_changes]" size="5" />
+      changed files per commit.  <em>(Use 0 to show all files.)</em>
+    </td>
+  </tr>
+  <tr>
+    <td></td>
+    <td><input type="submit" value="Search" /></td>
+  </tr>
+</table>
+</div>
+
+</form>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_results.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/query_results.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,86 @@
+[# setup page definitions]
+  [define page_title]Query results in:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt"]
+
+<p><strong>[english_query]</strong></p>
+[# <!-- {sql} --> ]
+<p><a href="[queryform_href]">Modify query</a></p>
+<p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p>
+
+<p><strong>+[plus_count]/-[minus_count]</strong> lines changed.</p>
+
+[if-any commits]
+<table cellspacing="1" cellpadding="2">
+ <thead>
+  <tr>
+   <th class="vc_header">Revision</th>
+   <th class="vc_header[is querysort "file"]_sort[end]">File</th>
+[if-any show_branch]
+   <th class="vc_header">Branch</th>
+[end]
+   <th class="vc_header">+/-</th>
+   <th class="vc_header[is querysort "date"]_sort[end]">Date</th>
+   <th class="vc_header[is querysort "author"]_sort[end]">Author</th>
+[# uncommment, if you want a separate Description column: (also see below)
+   <th class="vc_header">Description</th>
+]
+  </tr>
+ </thead>
+[for commits]
+  [for commits.files]
+    <tbody>
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td style="vertical-align: top;">
+        [define rev_href][if-any commits.files.prefer_markup][commits.files.view_href][else][if-any commits.files.download_href][commits.files.download_href][end][end][end]
+	[if-any commits.files.rev][if-any rev_href]<a href="[rev_href]">[end][commits.files.rev][if-any rev_href]</a>[end][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align: top;">
+        <a href="[commits.files.dir_href]">[commits.files.dir]/</a>
+        <a href="[commits.files.log_href]">[commits.files.file]</a>
+      </td>
+[if-any show_branch]
+      <td style="vertical-align: top;">
+	[if-any commits.files.branch][commits.files.branch][else]&nbsp;[end]
+      </td>
+[end]
+      <td style="vertical-align: top;">
+        [# only show a diff link for changes ]
+        [is commits.files.type "Add"]<ins>[end]
+        [is commits.files.type "Change"]<a href="[commits.files.diff_href]">[end]
+        [is commits.files.type "Remove"]<del>[end]
+          [commits.files.plus]/[commits.files.minus]
+        [is commits.files.type "Add"]</ins>[end]
+        [is commits.files.type "Change"]</a>[end]
+        [is commits.files.type "Remove"]</del>[end]
+      </td>
+      <td style="vertical-align: top;">
+	[if-any commits.files.date][commits.files.date][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align: top;">
+	[if-any commits.files.author][commits.files.author][else]&nbsp;[end]
+      </td>
+    </tr>
+  [end]
+  [if-any commits.limited_files]
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td>&nbsp;</td>
+      <td colspan="5">
+        <strong><em><small>Only first [commits.num_files] files shown.
+        <a href="[limit_changes_href]">Show all files</a> or
+        <a href="[queryform_href]">adjust limit</a>.</small></em></strong>
+    </tr>
+  [end]
+  <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+    <td>&nbsp;</td>
+    <td colspan="5"><strong>Log:</strong><br />
+      <pre class="vc_log">[commits.log]</pre></td>
+  </tr>
+  </tbody>
+[end]
+</table>
+[end]
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/revision.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/revision.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,83 @@
+[# setup page definitions]
+  [define page_title]Revision [rev] of:[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+[include "include/header.ezt" "revision"]
+
+<form method="get" action="[jump_rev_action]">
+<table cellspacing="1" cellpadding="2" style="width: auto;">
+  <tr align="left">
+    <th>Jump to revision:</th>
+    <td>
+      [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
+      <input type="text" name="revision" value="[rev]" />
+      <input type="submit" value="Go" />
+      [if-any prev_href]
+        <a href="[prev_href]" title="Previous Revision"><img src="[docroot]/images/back.png" alt="Previous" width="20" height="22" /></a>[end]
+      [if-any next_href] <a href="[next_href]" title="Next Revision"><img src="[docroot]/images/forward.png" width="20" height="22" alt="Next" /></a>[end]
+    </td>
+  </tr>
+  <tr align="left">
+    <th>Author:</th>
+    <td>[if-any author][author][else]<em>(unknown author)</em>[end]</td>
+  </tr>
+  <tr align="left">
+    <th>Date:</th>
+    <td>[if-any date][date][else]<em>(unknown date)</em>[end]
+        [if-any ago]<em>([ago] ago)</em>[end]</td>
+  </tr>
+  <tr align="left">
+    <th>Log Message:</th>
+    <td><pre class="vc_log">[log]</pre></td>
+  </tr>
+</table>
+</form>
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+<p><strong>Changed paths:</strong></p>
+
+[if-any more_changes]
+  <div>
+    Only [limit_changes] changes shown,
+    <a href="[more_changes_href]">display [more_changes] more changes...</a>
+  </div>
+[end]
+
+[if-any first_changes]
+  <div><a href="[first_changes_href]">Show only first [first_changes] changes...</div>
+[end]
+
+<table cellspacing="1" cellpadding="2">
+  <thead>
+  <tr align="left">
+    <th class="vc_header_sort">Path</th>
+    <th class="vc_header">Details</th>
+  </tr>
+  </thead>
+  <tbody>
+  [if-any changes]
+   [for changes]
+    <tr class="vc_row_[if-index changes even]even[else]odd[end]">
+      <td>[if-any changes.view_href]<a href="[changes.view_href]" title="View [is changes.pathtype "dir"]Directory[else]File[end] Contents">[end]<img src="[docroot]/images/[is changes.pathtype "dir"]dir[else]text[end].png" class="vc_icon" alt="Directory" />[changes.path][is changes.pathtype "dir"]/[end][if-any changes.view_href]</a>[end]
+      [if-any changes.is_copy]<br /><em>(Copied from [changes.copy_path], r[changes.copy_rev])</em>[end]
+      </td>
+      <td>[if-any changes.log_href]<a href="[changes.log_href]" title="View Log">[end][changes.action][if-any changes.log_href]</a>[end]
+          [if-any changes.text_mods], [if-any changes.diff_href]<a href="[changes.diff_href]" title="View Diff">[end]text changed[if-any changes.diff_href]</a>[end][end]
+          [if-any changes.prop_mods], props changed[end]
+      </td>
+    </tr>
+   [end]
+  [else]
+    <tr>
+    <td colspan="5">No changed paths.</td>
+    </tr>
+  [end]
+  </tbody>
+</table>
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/roots.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/roots.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,33 @@
+[# setup page definitions]
+  [define page_title]Repository Listing[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "directory"]
+
+<div id="vc_main_body">
+<!-- ************************************************************** -->
+
+<table cellspacing="1" id="dirlist">
+<thead>
+<tr>
+  <th class="vc_header_sort">Name</th>
+</tr>
+</thead>
+
+<tbody>
+[if-any roots]
+[for roots]
+  <tr class="vc_row_[if-index roots even]even[else]odd[end]">
+    <td onclick="jumpTo('[roots.href]')"><a href="[roots.href]"><img src="[docroot]/images/[roots.type]-logo.png" alt="" class="vc_icon" />[roots.name]</a></td>
+  </tr>
+[end]
+[end]
+</tbody>
+
+</table>
+
+<!-- ************************************************************** -->
+</div>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/newvc/templates/rss.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/newvc/templates/rss.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+<channel>
+    <link>[rss_link_href]</link>
+    <title>[rootname] checkins[if-any where] (in [where])[end]</title>
+
+    <description>[is roottype "svn"]Subversion[else]CVS[end] commits to the[if-any where] [where] directory of the[end] [rootname] repository</description>
+
+	[for commits]<item>
+        <title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
+		[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
+		<author>[commits.author]</author>
+		<pubDate>[if-any commits.rss_date][commits.rss_date][else](unknown date)[end]</pubDate>
+		<description>&lt;pre&gt;[format "xml"][commits.log][end]&lt;/pre&gt;</description>
+    </item>[end]
+</channel>	
+</rss>

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/annotate.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/annotate.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/annotate.ezt	Mon Nov  3 09:44:02 2008
@@ -3,19 +3,7 @@
   [define help_href][docroot]/help_rootview.html[end]
 [# end]
 [include "include/header.ezt" "annotate"]
-
-<table class="auto">
-<tr>
-<td>Revision:</td>
-<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong></td>
-</tr>
-[if-any orig_path]
-<tr>
-<td>Original Path:</td>
-<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
-</tr>
-[end]
-</table>
+[include "include/fileview.ezt"]
 
 <div id="vc_main_body">
 <!-- ************************************************************** -->
@@ -50,6 +38,8 @@
 [end]
 </table>
 
+[include "include/props.ezt"]
+
 <!-- ************************************************************** -->
 </div>
 

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/diff.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/diff.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/diff.ezt	Mon Nov  3 09:44:02 2008
@@ -6,7 +6,7 @@
 
 <form method="get" action="[diff_format_action]" style="display: inline;">
   <div>
-    [diff_format_hidden_values]
+    [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
     <select name="diff_format" onchange="submit()">
       <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
       <option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/directory.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/directory.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/directory.ezt	Mon Nov  3 09:44:02 2008
@@ -128,4 +128,5 @@
 
 </table>
 
+[include "include/props.ezt"]
 [include "include/dir_footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/images/lock.png
==============================================================================
Binary file. No diff available.

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/styles.css
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/styles.css	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/docroot/styles.css	Mon Nov  3 09:44:02 2008
@@ -19,6 +19,7 @@
   border: none;
 }
 tr, td, th { vertical-align: top; }
+th { white-space: nowrap; }
 table.auto {
     width: auto;
 }
@@ -131,6 +132,15 @@
 }
 
 
+/*** Properties Listing ***/
+.vc_properties {
+  margin: 1em 0;
+}
+.vc_properties h2 {
+  font-size: 115%;
+}
+
+
 /*** Markup Summary Header ***/
 .vc_summary {
   background-color: #eeeeee;

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/diff_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/diff_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/diff_form.ezt	Mon Nov  3 09:44:02 2008
@@ -17,7 +17,7 @@
   <tr>
   <td>&nbsp;</td>
   <td>
-  [diff_select_hidden_values]
+  [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
   Diffs between
 [if-any tags]
   <select name="r1">

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_footer.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_footer.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_footer.ezt	Mon Nov  3 09:44:02 2008
@@ -9,7 +9,7 @@
           <td>
             <form method="get" action="[search_re_action]">
               <div>
-                [search_re_hidden_values]
+                [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
                 <input type="text" name="search" value="[search_re]" />
                 <input type="submit" value="Show" />
               </div>
@@ -22,7 +22,7 @@
           <td>
             <form method="get" action="[search_tag_action]">
               <div>
-                [search_tag_hidden_values]
+                [for search_tag_hidden_values]<input type="hidden" name="[search_tag_hidden_values.name]" value="[search_tag_hidden_values.value]"/>[end]
                 <input type="submit" value="Show all files" />
               </div>
             </form>

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/dir_header.ezt	Mon Nov  3 09:44:02 2008
@@ -40,22 +40,24 @@
   <td><a href="[queryform_href]">Query revision history</a></td>
 </tr>
 [end]
-</table>
-  [is cfg.options.use_pagesize "0"]
-  [else]
-    [is picklist_len "1"]
-    [else]
-      <form method="get" action="[dir_paging_action]">
-        [dir_paging_hidden_values]
-        <input type="submit" value="Go to:" />
+
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]
+<tr>
+  <td>Jump to page:</td>
+  <td><form method="get" action="[dir_paging_action]">
+        [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
         <select name="dir_pagestart"  onchange="submit()">
           [for picklist]
             <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
           [end]
         </select>
+        <input type="submit" value="Go" />
       </form>
-    [end]
-  [end]
+  </td>
+</tr>
+[end][end]
+
+</table>
 
 <div id="vc_main_body">
 <!-- ************************************************************** -->

Added: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/fileview.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/fileview.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,62 @@
+<table class="auto">
+<tr>
+<td>Revision:</td>
+<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong> [if-any vendor_branch] <em>(vendor branch)</em>[end]</td> 
+</tr>
+<tr>
+<tr>
+<td>Committed:</td>
+<td>[if-any date]<em>[date]</em> [end][if-any ago]([ago] ago) [end][if-any author]by <em>[author]</em>[end]</td>
+</tr>
+[if-any orig_path]
+<tr>
+<td>Original Path:</td>
+<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
+</tr>
+[end]
+[if-any branches]
+<tr>
+<td>Branch:</td>
+<td><strong>[branches]</strong></td>
+</tr>
+[end]
+[if-any tags]
+<tr>
+<td>CVS Tags:</td>
+<td><strong>[tags]</strong></td>
+</tr>
+[end]
+[if-any branch_points]
+<tr>
+<td>Branch point for:</td>
+<td><strong>[branch_points]</strong></td>
+</tr>
+[end]
+[is roottype "cvs"][if-any changed]
+<tr>
+<td>Changes since <strong>[prev]</strong>:</td>
+<td><strong>[changed] lines</strong></td>
+</tr>
+[end][end]
+[is roottype "svn"][if-any size]
+<td>File size:</td>
+<td>[size] byte(s)</td>
+</tr>
+[end][end]
+[if-any lockinfo]
+<td>Lock status:</td>
+<td><img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]</td>
+[end]
+[is state "dead"]
+<tr>
+<td>State:</td>
+<td><strong><em>FILE REMOVED</em></strong></td>
+</tr>
+[end]
+[if-any log]
+<tr>
+<td>Log Message:</td>
+<td><pre class="vc_log">[log]</span></td>
+</tr>
+[end]
+</table>

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/header.ezt	Mon Nov  3 09:44:02 2008
@@ -22,43 +22,10 @@
      width="150" height="60" /></a>
 </div>
 
-[if-any roots]
-  <form method="get" style="display: inline" action="[change_root_action]">
-    [change_root_hidden_values]
-      <strong>Repository:</strong>
-      <select name="root" onchange="submit()">
-        [define cvs_root_options][end]
-        [define svn_root_options][end]
-        <option value="*viewroots*"[is view "roots"] selected="selected"[else][end]>Repository Listing</option>
-        [for roots]
-          [define root_option][end]
-          [is roots.name rootname]
-            [define root_option]<option selected="selected">[roots.name]</option>[end]
-          [else]
-            [define root_option]<option>[roots.name]</option>[end]
-          [end]
-          [is roots.type "cvs"]
-            [define cvs_root_options][cvs_root_options][root_option][end]
-          [else]
-            [is roots.type "svn"]
-              [define svn_root_options][svn_root_options][root_option][end]
-            [end]
-          [end]
-        [end]
-        [is cvs_root_options ""][else]
-          <optgroup label="CVS Repositories">[cvs_root_options]</optgroup>
-        [end]
-        [is svn_root_options ""][else]
-          <optgroup label="Subversion Repositories">[svn_root_options]</optgroup>
-        [end]
-      </select>
-      <input type="submit" value="Go" />
-  </form>
-[end]
-
 <div id="vc_current_path">
 <strong>[page_title]</strong>
 [if-any nav_path]
+  [if-any roots_href]<a href="[roots_href]">/</a>[else]/[end]
   [for nav_path]
     [if-any nav_path.href]<a href="[nav_path.href]">[end]
       [nav_path.name][if-any nav_path.href]</a>[end]

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_footer.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_footer.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_footer.ezt	Mon Nov  3 09:44:02 2008
@@ -1,13 +1,9 @@
 <!-- ************************************************************** -->
 </div>
 
-[include "paging.ezt"]
-
 [is pathtype "file"]
   [include "diff_form.ezt"]
 [end]
 
-[include "sort.ezt"]
-
 [include "footer.ezt"]
 

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/log_header.ezt	Mon Nov  3 09:44:02 2008
@@ -45,7 +45,42 @@
   <td>[include "pathrev_form.ezt"]</td>
 </tr>
 
-[include "paging.ezt"]
+[is cfg.options.use_pagesize "0"][else][is picklist_len "1"][else]    
+<tr>
+  <td>Jump to page:</td>
+  <td><form method="get" action="[log_paging_action]">
+        [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
+        <select name="log_pagestart"  onchange="submit()">
+          [for picklist]
+           [if-any picklist.more]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+           [else]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+           [end]
+          [end]
+        </select>
+        <input type="submit" value="Go" />
+      </form>
+  </td>
+</tr>
+[end][end]
+
+<tr>
+  <td>Sort logs by:</td>
+  <td><form method="get" action="[logsort_action]">
+      <div>
+        <a name="logsort"></a>
+          [for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
+          <select name="logsort" onchange="submit()">
+            <option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
+            <option value="date" [is logsort "date"]selected="selected"[end]>Commit date</option>
+            <option value="rev" [is logsort "rev"]selected="selected"[end]>Revision</option>
+          </select>
+          <input type="submit" value="  Sort  " />
+      </div>
+    </form>
+  </td>
+</tr>
 
 </table>
 

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/pathrev_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/pathrev_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/pathrev_form.ezt	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 <form method="get" action="[pathrev_action]" style="display: inline">
 <div style="display: inline">
-[pathrev_hidden_values]
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
 [is roottype "cvs"]
   [define pathrev_selected][pathrev][end]
   <select name="pathrev" onchange="submit()">
@@ -41,7 +41,7 @@
 [if-any pathrev]
 <form method="get" action="[pathrev_clear_action]" style="display: inline">
 <div style="display: inline">
-[pathrev_clear_hidden_values]
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
 [if-any lastrev]
   [is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
   (<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)

Added: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/props.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/include/props.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,26 @@
+[if-any properties]
+<hr/>
+<div class="vc_properties">
+<h2>Properties</h2>
+<table cellspacing="1" cellpadding="2" class="fixed">
+<thead>
+  <tr>
+    <th class="vc_header_sort" style="width: 20%;">Name</th>
+    <th class="vc_header">Value</th>
+  </tr>
+</thead>
+<tbody>
+[for properties]
+  <tr class="vc_row_[if-index properties even]even[else]odd[end]">
+    <td><strong>[properties.name]</strong></td>
+    [if-any properties.undisplayable]
+    <td><em>Property value is undisplayable.</em></td>
+    [else]
+    <td style="white-space: pre;">[properties.value]</td>
+    [end]
+  </tr>
+[end]
+</tbody>
+</table>
+</div>
+[end]

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/log.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/log.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/log.ezt	Mon Nov  3 09:44:02 2008
@@ -91,6 +91,10 @@
     [end]
   [end]
 
+  [if-any entries.lockinfo]
+    <br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
+  [end]
+
   [is roottype "svn"]
     [if-any entries.size]
     <br />File length: [entries.size] byte(s)

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/markup.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/markup.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/markup.ezt	Mon Nov  3 09:44:02 2008
@@ -3,71 +3,15 @@
   [define help_href][docroot]/help_rootview.html[end]
 [# end]
 [include "include/header.ezt" "markup"]
-
-<table class="auto">
-<tr>
-<td>Revision:</td>
-<td><strong>[if-any revision_href]<a href="[revision_href]">[rev]</a>[else][rev][end]</strong> [if-any vendor_branch] <em>(vendor branch)</em>[end]</td> 
-</tr>
-<tr>
-<tr>
-<td>Committed:</td>
-<td>[if-any date]<em>[date]</em> [end][if-any ago]([ago] ago) [end][if-any author]by <em>[author]</em>[end]</td>
-</tr>
-[if-any orig_path]
-<tr>
-<td>Original Path:</td>
-<td><strong><a href="[orig_href]"><em>[orig_path]</em></a></strong></td>
-</tr>
-[end]
-[if-any branches]
-<tr>
-<td>Branch:</td>
-<td><strong>[branches]</strong></td>
-</tr>
-[end]
-[if-any tags]
-<tr>
-<td>CVS Tags:</td>
-<td><strong>[tags]</strong></td>
-</tr>
-[end]
-[if-any branch_points]
-<tr>
-<td>Branch point for:</td>
-<td><strong>[branch_points]</strong></td>
-</tr>
-[end]
-[is roottype "cvs"][if-any changed]
-<tr>
-<td>Changes since <strong>[prev]</strong>:</td>
-<td><strong>[changed] lines</strong></td>
-</tr>
-[end][end]
-[is roottype "svn"][if-any size]
-<td>File size:</td>
-<td>[size] byte(s)</td>
-</tr>
-[end][end]
-[is state "dead"]
-<tr>
-<td>State:</td>
-<td><strong><em>FILE REMOVED</em></strong></td>
-</tr>
-[end]
-[if-any log]
-<tr>
-<td>Log Message:</td>
-<td><pre class="vc_log">[log]</span></td>
-</tr>
-[end]
-</table>
+[include "include/fileview.ezt"]
 
 <div id="vc_main_body">
 <!-- ************************************************************** -->
 
 <div id="vc_markup"><pre>[markup]</pre></div>
 
+[include "include/props.ezt"]
+
 <!-- ************************************************************** -->
 </div>
 

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_form.ezt	Mon Nov  3 09:44:02 2008
@@ -7,7 +7,7 @@
 <form action="[query_action]" method="get">
 
 <div class="vc_query_form">
-  [query_hidden_values]
+  [for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
 <table cellspacing="0" cellpadding="5" class="auto">
   [is roottype "cvs"]
   [# For subversion, the branch field is not used ]

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_results.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_results.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/query_results.ezt	Mon Nov  3 09:44:02 2008
@@ -1,5 +1,5 @@
 [# setup page definitions]
-  [define page_title]Query results on /[where][end]
+  [define page_title]Query results in:[end]
   [define help_href][docroot]/help_rootview.html[end]
 [# end]
 

Modified: branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/revision.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/revision.ezt	(original)
+++ branches/VIEWCVS_DIST/templates-contrib/tabbed/templates/revision.ezt	Mon Nov  3 09:44:02 2008
@@ -9,7 +9,7 @@
   <tr align="left">
     <th>Jump to revision:</th>
     <td>
-      [jump_rev_hidden_values]
+      [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
       <input type="text" name="revision" value="[rev]" />
       <input type="submit" value="Go" />
       [if-any prev_href]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/INSTALL
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/INSTALL	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,132 @@
+I.   BASIC INSTALLATION
+
+
+Let ViewVC use the viewsvn templates folder as templates. You can either delete the original
+templates folder in the ViewVC installation directory and copy the one from this archive to
+the ViewVC installation directory or copy the templates folder from this archive with a different 
+name to the ViewVC installation directory and change the template_dir option in viewvc.conf
+
+template_dir = templates-viewsvn
+
+Leave the section [templates] as is, thus do not override any templates. 
+
+
+
+ 
+II.  TWEAKS
+
+
+1. Set your own favicon
+
+Modify include/header.ezt, line 9, to include your favicon.
+
+
+2. Let your own logo appear in the upper right area and link to your homepage. 
+
+Modify include/header.ezt, line 78, to include your link and logo.
+
+
+3. Enable TortoiseSVN checkout links.
+
+If you are certain that most of your guest use TortoiseSVN you can give them the ability
+to use TortoiseSVN checkout links 
+(see http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-repository-links.html). This wil
+only work if all your repositories share the same base location, e.g. http://svn.server/svn/.
+This is mostly the case if you are using the mod_dav_svn SVNParentPath directive.
+ 
+Modify include/dir_footer.ezt, line 44. Enable this section and configure your subversion location. 
+
+
+
+
+III. EXTRAS
+
+
+1.   fix-blame-output.diff
+
+If you are running ViewVC 1.0 and you are suffering from a broken blame/annotate output because of
+long author names you can apply this patch. Note that Subversion 1.3.1 or higher is required.
+
+
+2.   svnindex.xsl & svnindex.css
+
+If you are using mod_dav_svn to host your repository you can teach it to use a stylesheet if you are 
+browsing the repository directly. Take a look at the SVNIndexXSLT directive for more information.
+You can use the .xsl and .css from the extras folder to get a look & feel that is similiar to this
+ViewVC template. Note that these stylesheets knows nothing about ViewVC. You have to teach
+svnindex.xsl where the [docroot] folder exists. If it is /docroot you have to change nothing, 
+otherwise edit line 68, 82 and 97.
+
+
+
+
+IV.  EXAMPLE VIEWVC.CONF
+
+
+The following viewvc.conf setting were used to create the templates, do not copy these blindly,
+just check them if something seems wrong:
+
+[general]
+root_parents = [REPOSPATH] : svn
+use_rcsparse = 0
+mime_types_file = [PATHTO]\mime.types
+address = <a href="mailto:[ADRESS]";>Admin</a>
+forbidden =
+kv_files =
+languages = en-us
+[options]
+root_as_url_component = 0
+default_file_view = log
+checkout_magic = 0
+http_expiration_time = 600
+generate_etags = 1
+sort_by = file
+sort_group_dirs = 1
+hide_attic = 1
+log_sort = date
+diff_format = h
+hide_cvsroot = 1
+hr_breakable = 1
+hr_funout = 0
+hr_ignore_white = 1
+hr_ignore_keyword_subst = 1
+hr_intraline = 0
+allow_annotate = 1
+allow_markup = 1
+allow_compress = 1
+template_dir = templates-viewsvn
+docroot = [PATHTO]/docroot
+show_subdir_lastmod = 0
+show_logs = 1
+show_log_in_markup = 1
+cross_copies = 0
+use_localtime = 1
+py2html_path = .
+short_log_len = 80
+use_enscript = 0
+enscript_path =
+use_highlight = 1
+highlight_path = [PATH]
+highlight_line_numbers = 1
+highlight_convert_tabs = 2
+use_php = 0
+php_exe_path = php
+allow_tar = 0
+use_cvsgraph = 0
+cvsgraph_path =
+cvsgraph_conf = cvsgraph.conf
+use_re_search = 0
+use_pagesize = 200
+limit_changes = 100
+[templates]
+[cvsdb]
+enabled = 1
+host = localhost
+port = 3306
+database_name = ViewVC
+user = [UID]
+passwd = [PWD]
+readonly_user = [UID] 
+readonly_passwd = [PWD] 
+#row_limit = 1000
+[vhosts]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/README
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/README	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,52 @@
+I.   INTRODUCTION
+
+
+ViewVC is a Subversion and CVS webbased repository viewer. Templates-viewsvn is
+a set of templates for a different look & feel.
+
+Warning:
+Do not use this template set if you plan to view cvs repositories through ViewVC! 
+This template-set is heavily trimmed for Subversion needs. Special CVS features are 
+untested, possibly disabled or broken.
+
+Please report enhancemants back to the ViewVC project or to me.
+jpeters7677 gmx de
+
+
+
+
+II.  COMPATABILITY
+
+
+This template is compatible with ViewVC 1.0.x
+
+
+
+
+III. CREDITS
+
+
+Stylesheet color codes:
+Subversion Mailing List Archive
+http://svn.haxx.se/ 
+
+Images:
+All images in templates/docroot/images/tortoisesvn are licensed under the
+ToirtoiseSVN Icon license. See license.txt in this folder for more details.
+
+
+
+
+IV.  LINKS
+
+
+ViewVC:
+http://www.viewvc.org/
+
+Subversion:
+http://subversion.tigris.org/
+
+TortoiseSVN:
+http://tortoisesvn.net/
+
+

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.css
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.css	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,76 @@
+
+html, body {
+  color: #000000;
+  background-color: #ffffff;
+  font-family: arial,helvetica,sans-serif;
+  font-size: 12px;
+}
+
+body{
+  margin: 0;
+  padding: 0;
+}
+
+a         { text-decoration:none;}
+a:hover   { text-decoration:underline;}
+a:link    { color: #0000ff; }
+a:visited { color: #880088; }
+a:active  { color: #0000ff; }
+
+.img a:hover { text-decoration:none;}
+
+img { 
+  border: none; 
+}
+
+.footer {
+  margin-top: 8em;
+  padding: 0.5em 1em 0.5em;
+  clear: both;
+  font-size: smaller;
+  font-style: italic;
+}
+
+.svn {
+  margin: 3em;
+}
+
+.rev {
+  margin-right: 3px;
+  margin-bottom: 15px;
+  padding-left: 3px;
+  
+  text-align: left;
+  font-size: 24px;
+  font-weight: bold;
+  color: #000066
+}
+
+.path {
+  margin: 3px;
+  padding: 3px;
+  background: #e0e0ff;
+font-weight: bold;
+}
+
+.updir {
+  margin: 3px;
+  padding: 3px;
+  margin-left: 3em;
+  background: #eeeeee;
+}
+
+.file {
+  margin: 3px;
+  padding: 3px;
+  margin-left: 3em;
+  background: #eeeeee;
+}
+
+.dir {
+  margin: 3px;
+  padding: 3px;
+  margin-left: 3em;
+  background: #eeeeee;
+}
+

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.xsl
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/extras/svnindex.xsl	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,107 @@
+<?xml version="1.0"?>
+
+<!-- A sample XML transformation style sheet for displaying the Subversion
+  directory listing that is generated by mod_dav_svn when the "SVNIndexXSLT"
+  directive is used. -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
+
+  <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" />
+
+  <xsl:template match="*"/>
+
+  <xsl:template match="svn">
+    <html xmlns="http://www.w3.org/1999/xhtml"; xml:lang="en" lang="en">
+      <head>
+        <title>
+          <xsl:if test="string-length(index/@name) != 0">
+            <xsl:value-of select="index/@name"/>
+            <xsl:text>: </xsl:text>
+          </xsl:if>
+          <xsl:value-of select="index/@path"/>
+        </title>
+        <link rel="shortcut icon" href="/favicon.ico" />
+        <link rel="stylesheet" type="text/css" href="/svnindex.css"/>
+      </head>
+      <body>
+        <div class="svn">
+          <xsl:apply-templates/>
+        </div>
+        <div class="footer">
+          <xsl:element name="a">
+            <xsl:attribute name="href">
+              <xsl:value-of select="@href"/>
+            </xsl:attribute>
+            <xsl:text>Subversion</xsl:text>
+          </xsl:element>
+          <xsl:text> </xsl:text>
+          <xsl:value-of select="@version"/>
+        </div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="index">
+    <div class="rev">
+      <xsl:if test="string-length(@name) != 0">
+        <xsl:value-of select="@name"/>
+        <xsl:if test="string-length(@rev) != 0">
+          <xsl:text> &#8212; </xsl:text>
+        </xsl:if>
+      </xsl:if>
+      <xsl:if test="string-length(@rev) != 0">
+        <xsl:text>Revision </xsl:text>
+        <xsl:value-of select="@rev"/>
+      </xsl:if>
+    </div>
+    <div class="path">
+      <xsl:value-of select="@path"/>
+    </div>
+    <xsl:apply-templates select="updir"/>
+    <xsl:apply-templates select="dir"/>
+    <xsl:apply-templates select="file"/>
+  </xsl:template>
+
+  <xsl:template match="updir">
+    <div class="updir">
+      <a href=".." class="img" title="Parent Directory"><img src="/docroot/images/tortoisesvn/back.png" alt="Parent Directory" width="16" height="16"/></a>
+      <xsl:text> </xsl:text>
+      <xsl:text>[</xsl:text>
+      <xsl:element name="a">
+        <xsl:attribute name="href">..</xsl:attribute>
+        <xsl:text>Parent Directory</xsl:text>
+      </xsl:element>
+      <xsl:text>]</xsl:text>
+    </div>
+    <!-- xsl:apply-templates/ -->
+  </xsl:template>
+
+  <xsl:template match="dir">
+    <div class="dir">
+      <a href="{ href}" class="img" title="{ name}"><img src="/docroot/images/dir.png" alt="{ name}" width="16" height="16"/></a>
+      <xsl:text> </xsl:text>
+      <xsl:element name="a">
+        <xsl:attribute name="href">
+          <xsl:value-of select="@href"/>
+        </xsl:attribute>
+        <xsl:value-of select="@name"/>
+        <xsl:text>/</xsl:text>
+      </xsl:element>
+    </div>
+    <!-- <xsl:apply-templates/ -->
+  </xsl:template>
+
+  <xsl:template match="file">
+    <div class="file">
+      <a href="{ href}" class="img" title="{ name}"><img src="/docroot/images/text.png" alt="{ name}" width="16" height="16"/></a>
+      <xsl:text> </xsl:text>
+      <xsl:element name="a">
+        <xsl:attribute name="href">
+          <xsl:value-of select="@href"/>
+        </xsl:attribute>
+        <xsl:value-of select="@name"/>
+      </xsl:element>
+    </div>
+    <!-- xsl:apply-templates/ -->
+  </xsl:template>
+
+</xsl:stylesheet>

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/diff.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/dir.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/log.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/screenshots/markup.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/diff.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/diff.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,234 @@
+[# setup page definitions]
+  [define page_title]Diff of /[where][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "diff"]
+[include "include/file_header.ezt"]
+
+<h3 style="text-align:center;"></h3>
+
+[if-any raw_diff]
+  <pre class="vc_raw_diff">[raw_diff]</pre>
+[end]
+
+[define left_view_href][if-any left.prefer_markup][left.view_href][else][if-any left.download_href][left.download_href][end][end][end]
+[define right_view_href][if-any right.prefer_markup][right.view_href][else][if-any right.download_href][right.download_href][end][end][end]
+
+[if-any changes]
+<table cellspacing="0" cellpadding="0">
+  <tr class="vc_diff_header">
+    <th style="width:6%;"></th>
+    <th style="width:47%; vertical-align:top;">
+      [is left.path right.path][else][left.path][end]
+      revision [if-any left_view_href]<a href="[left_view_href]">[end][left.rev][if-any left_view_href]</a>[end],
+      [left.date]
+    </th>
+    <th style="width:47%; vertical-align:top;">
+      [is left.path right.path][else][right.path][end]
+      revision [if-any right_view_href]<a href="[right_view_href]">[end][right.rev][if-any right_view_href]</a>[end],
+      [right.date]
+    </th>
+  </tr>
+
+  [for changes]
+    [is changes.type "header"]
+      <tr class="vc_diff_chunk_header" id="h[changes.line_info_right]">
+        <td style="width:6%;"><strong>#</strong></td>
+        <td style="width:47%;">
+          <strong>Line [changes.line_info_left]</strong>&nbsp;
+          <span class="vc_diff_chunk_extra">[changes.line_info_extra]</span>
+        </td>
+        <td style="width:47%;">
+          <strong>Line [changes.line_info_right]</strong>&nbsp;
+          <span class="vc_diff_chunk_extra">[changes.line_info_extra]</span>
+        </td>
+      </tr>
+    [else]
+      [is changes.type "add"]
+        <tr>
+          <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+          <td class="vc_diff_empty">&nbsp;</td>
+          <td class="vc_diff_add">&nbsp;[changes.right]</td>
+        </tr>
+      [else]
+        [is changes.type "remove"]
+          <tr>
+            <td></td>
+            <td class="vc_diff_remove">&nbsp;[changes.left]</td>
+            <td class="vc_diff_empty">&nbsp;</td>
+          </tr>
+        [else]
+          [is changes.type "change"]
+            <tr>
+              [if-any changes.have_right]
+                <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+              [else]
+                <td></td>
+              [end]
+              [if-any changes.have_left]
+                <td class="vc_diff_change">&nbsp;[changes.left]</td>
+              [else]
+                <td class="vc_diff_change_empty">&nbsp;</td>
+              [end]
+              [if-any changes.have_right]
+                <td class="vc_diff_change">&nbsp;[changes.right]</td>
+              [else]
+                <td class="vc_diff_change_empty">&nbsp;</td>
+              [end]
+            </tr>
+          [else]
+            [is changes.type "no-changes"]
+              <tr>
+                <td colspan="3">&nbsp;</td>
+              </tr>
+              <tr class="vc_diff_empty">
+                <td colspan="3" style="text-align:center;"><br />
+                <strong>- No changes -</strong><br />&nbsp; </td>
+              </tr>
+            [else]
+              [is changes.type "binary-diff"]
+                <tr>
+                  <td colspan="3">&nbsp;</td>
+                </tr>
+                <tr class="vc_diff_empty">
+                  <td colspan="3" style="text-align:center;"><br />
+                  <strong>- Binary file revisions differ -</strong><br />&nbsp; </td>
+                </tr>
+              [else]
+                [is changes.type "error"]
+                  <tr>
+                    <td colspan="3">&nbsp;</td>
+                  </tr>
+                  <tr class="vc_diff_empty">
+                    <td colspan="3" style="text-align:center;"> <br />
+                    <strong>- ViewVC depends on rcsdiff and GNU diff to create 
+                    this page.  ViewVC cannot find GNU diff. Even if you 
+                    have GNU diff installed, the rcsdiff program must be 
+                    configured and compiled with the GNU diff location.
+                    -</strong> <br />&nbsp; </td>
+                  </tr>
+                [else]
+                  <tr>
+                    <td id="l[changes.line_number]">[if-any right.annotate_href]<a href="[right.annotate_href]#l[changes.line_number]">[changes.line_number]</a>[else][changes.line_number][end]</td>
+                    <td class="vc_diff_nochange">&nbsp;[changes.left]</td>
+                    <td class="vc_diff_nochange">&nbsp;[changes.right]</td>
+                  </tr>
+                [end]
+              [end]
+            [end]
+          [end]
+        [end]
+      [end]
+    [end]
+  [end]
+</table>
+[end]
+
+[if-any sidebyside]
+  <table class="vc_idiff">
+    <colgroup><col /><col class="content" /></colgroup>
+    <colgroup><col /><col class="content" /></colgroup>
+    <thead>
+      <tr>
+        <th colspan="2">    
+          [is left.path right.path][else][left.path][end]
+          Revision [left.rev]
+        </th>
+        <th colspan="2">
+          [is left.path right.path][else][right.path][end]
+          Revision [right.rev]
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      [for sidebyside]
+        [if-any sidebyside.gap]
+          <tr>
+            <th>&hellip;</th><th></th>
+            <th>&hellip;</th><th></th>
+          </tr>
+        [end]
+        <tr>
+          [for sidebyside.columns]
+            <th>[sidebyside.columns.line_number]</th><td[if-any sidebyside.columns.line_number][else] class="vc_idiff_empty"[end]>[for sidebyside.columns.segments][if-any sidebyside.columns.segments.type]<span class="vc_idiff_[sidebyside.columns.segments.type]">[sidebyside.columns.segments.text]</span>[else][sidebyside.columns.segments.text][end][end]</td>
+          [end]
+        </tr>
+      [end]
+    </tbody>
+  </table>
+[end]
+
+[if-any unified]
+  <table class="vc_idiff">
+    <thead>
+      <tr>
+        <th>r[left.rev]</th>
+        <th>r[right.rev]</th>
+        <th></th>
+      </tr>
+    </thead>
+    <tbody>
+      [for unified]
+        [if-any unified.gap]
+          <tr>
+            <th>&hellip;</th>
+            <th>&hellip;</th>
+            <th></th>
+          </tr>
+        [end]
+        <tr>
+          <th>[unified.left_number]</th>
+          <th>[unified.right_number]</th>
+          <td[if-any unified.type] class="vc_idiff_[unified.type]"[end]>[for unified.segments][if-any unified.segments.type]<span class="vc_idiff_[unified.segments.type]">[unified.segments.text]</span>[else][unified.segments.text][end][end]</td>
+        </tr>
+      [end]
+    </tbody>
+  </table>
+[end]
+
+<hr style="margin-top:1em;" />
+
+<table cellpadding="10" class="auto">
+  <tr>
+    <td>
+      <form method="get" action="[diff_format_action]">
+        <div>
+          [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
+          <select name="diff_format" onchange="submit()">
+            <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
+            <option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
+          </select>
+          <input type="submit" value="Show" />
+          </div>
+      </form>
+    </td>
+    <td>
+[if-any raw_diff]
+      &nbsp;
+[else]
+      <table style="border:solid gray 1px;" class="auto">
+        <tr>
+          <td>Legend:<br />
+            <table cellspacing="0" cellpadding="1">
+              <tr>
+                <td style="text-align:center;" class="vc_diff_remove">Removed from v.[left.rev]</td>
+                <td class="vc_diff_empty">&nbsp;</td>
+              </tr>
+              <tr>
+                <td style="text-align:center;" colspan="2" class="vc_diff_change">changed lines</td>
+              </tr>
+              <tr>
+                <td class="vc_diff_empty">&nbsp;</td>
+                <td style="text-align:center;" class="vc_diff_add">Added in v.[right.rev]</td>
+              </tr>
+            </table>
+          </td>
+        </tr>
+      </table>
+[end]
+    </td>
+  </tr>
+</table>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/directory.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/directory.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,136 @@
+[include "include/dir_header.ezt"]
+
+<table cellspacing="1" cellpadding="2">
+<thead>
+<tr>
+  <th class="vc_header[is sortby "file"]_sort[end]">
+    <a href="[sortby_file_href]#dirlist">Name</a>
+    <a href="[sortby_file_href]#dirlist" class="img">
+    [is sortby "file"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+  <th class="vc_header[is sortby "rev"]_sort[end]" width="[is cfg.options.show_logs "1"]5[else]10[end]%">
+    <a href="[sortby_rev_href]#dirlist">Rev.</a>
+    <a href="[sortby_rev_href]#dirlist" class="img">
+    [is sortby "rev"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+  <th class="vc_header[is sortby "date"]_sort[end]" width="[is cfg.options.show_logs "1"]10[else]20[end]%">
+    <a href="[sortby_date_href]#dirlist">Age</a>
+    <a href="[sortby_date_href]#dirlist" class="img">
+    [is sortby "date"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+  <th class="vc_header[is sortby "author"]_sort[end]" width="[is cfg.options.show_logs "1"]10[else]20[end]%">
+    <a href="[sortby_author_href]#dirlist">Author</a>
+    <a href="[sortby_author_href]#dirlist" class="img">
+    [is sortby "author"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+[is cfg.options.show_logs "1"]
+  <th class="vc_header[is sortby "log"]_sort[end]" width="50%">
+    <a href="[sortby_log_href]#dirlist">Last log entry</a>
+    <a href="[sortby_log_href]#dirlist" class="img">
+    [is sortby "log"]
+      <img class="vc_sortarrow" alt="[is sortdir "down"](rev)[end]"
+        width="13" height="13"
+        src="[docroot]/images/[is sortdir "up"]up[else]down[end].png" />
+    [end]
+    </a>
+  </th>
+[end]
+</tr>
+</thead>
+
+<tbody>
+[if-any up_href]
+  <tr class="vc_row_odd">
+    <td>
+      <table cellspacing=0 cellpadding=0>
+        <tr>
+          <td width="18px"><a href="[up_href]" class="img"><img src="[docroot]/images/tortoisesvn/back_small.png" alt="" width="16" height="16"/></a></td>
+          <td><a href="[up_href]">Parent&nbsp;Directory</a></td>
+        </tr>
+      </table>    
+    </td>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+    <td>&nbsp;</td>
+    [is cfg.options.show_logs "1"]
+      <td>&nbsp;</td>
+    [end]
+  </tr>
+ [end]
+ [for entries]
+   <tr class="vc_row_[if-index entries even]even[else]odd[end]">
+     <td>
+
+       <table cellspacing=0 cellpadding=0>
+         <tr>
+           <td width="18px">      
+             [is entries.pathtype "dir"]
+               <a href="[entries.view_href]" title="View directory contents" class="img">
+                 <img src="[docroot]/images/dir.png" alt="View directory contents" width="16" height="16" />
+               </a>
+             [else]
+               [if-any entries.view_href]<a href="[entries.view_href]" title="View file contents" class="img">[end]
+               <img src="[docroot]/images/text.png" alt="View file contents" width="16" height="16" />
+               [if-any entries.view_href]</a>[end]
+             [end]
+           </td>
+           <td>
+             [is entries.pathtype "dir"]
+               <a href="[entries.view_href]" title="View directory contents">[entries.name]</a>
+             [else]
+               [if-any entries.view_href]<a href="[entries.view_href]" title="View file contents">[end]
+               [entries.name]
+               [if-any entries.view_href]</a>[end]
+             [end]
+           </td>
+         </tr>
+       </table>
+
+     </td>
+     [if-any entries.errors]
+       <td colspan=[is cfg.options.show_logs "1"]4[else]3[end]>
+         [for entries.errors]<em>[entries.errors]</em>[end]
+       </td>
+     [else]
+       [is entries.pathtype "dir"]
+         <td>&nbsp;[if-any entries.rev]<a href="[entries.log_href]" title="View directory revision log"><strong>[entries.rev]</strong></a>[end]</td>
+       [else]
+         <td>&nbsp;[if-any entries.rev]<a name="[entries.anchor]" href="[entries.log_href]" title="View file revision log"><strong>[entries.rev]</strong></a>[end]</td>
+       [end]
+       <td>&nbsp;[entries.ago]</td>
+       <td>&nbsp;[entries.author]</td>
+       [is cfg.options.show_logs "1"]
+         [if-any entries.log]
+           <td>&nbsp;[entries.log]</td>
+         [else]
+           <td>&nbsp;</td>
+         [end]
+      [end]
+    [end]
+  </tr>
+[end]
+</tbody>
+
+</table>
+
+[include "include/dir_footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/broken.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/dir.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/down.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/download.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/favicon-svn.ico
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/feed-icon-16x16.jpg
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/logo-svn.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/logo-viewvc.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/svn.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/text.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/back.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/back_small.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/blame.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/checkout.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/diff.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/forward.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/license.txt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/license.txt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,39 @@
+The icons in these folders are available either under the terms
+of the GNU Public License, or under the terms of the TortoiseSVN
+Icon License below, unless the folder contains an alternative
+license file.
+
+====================================================================
+Copyright (c) 2006 The TortoiseSVN Project.  All rights reserved.
+
+Redistribution and use of these icons, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of these icons as part of a source or binary
+   distribution must retain the above copyright notice and this
+   list of conditions.
+
+2. The icons may only be used for a Subversion client application,
+   or for an application with Subversion support (e.g. an IDE).
+   You may not use these icons for to represent actions which are
+   not directly related to Subversion. If the application supports
+   other version control systems besides Subversion, the icons may
+   be used for those other version control systems too.
+
+3. Software using these icons must provide an acknowledgement
+   that the icons were derived from the TortoiseSVN project,
+   with a link to the project website (tortoisesvn.tigris.org)
+   in one or more of the following places:
+   a) an "about" box.
+   b) the product user manual.
+   c) a textfile in the installation folder of the application.
+   d) a contributors page on the product web page.
+
+4. The name "TortoiseSVN" must not be used to endorse or
+   promote products using these icons without prior written
+   permission. For written permission, please contact
+   dev tortoisesvn tigris org 
+
+5. If you provide additional icon sets for Subversion actions or
+   status besides those you use from us, you must give us 
+   permission to use your icon sets too. 

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/log.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/patch.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/repos.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/tortoisesvn/tsvn.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/up.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/images/viewvc.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/styles.css
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/docroot/styles.css	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,263 @@
+/*******************************/
+/***  ViewVC CSS Stylesheet ***/
+/*******************************/
+
+/*** Standard Tags ***/
+html, body {
+  color: #000000;
+  background-color: #ffffff;
+  font-family: arial,helvetica,sans-serif;
+  font-size: 12px;
+}
+
+a         { text-decoration:none;}
+a:hover   { text-decoration:underline;}
+a:link    { color: #0000ff; }
+a:visited { color: #880088; }
+a:active  { color: #0000ff; }
+.img a:hover   { text-decoration:none;}
+
+img { border: none; }
+
+table {
+  width: 100%;
+  margin: 0; 
+  border: none;
+}
+table.props {
+  width: 50%;
+}
+table.auto {
+  width: auto;
+}
+tr, td, th { vertical-align: top; }
+form { margin: 0; }
+
+hr{
+  color: #eeeeee;
+  background-color: #eeeeee;
+  height: 1px;
+  border: none;
+}
+
+h1{
+  font-size: 24px;
+  color: #000066
+}
+h2{
+  font-size: 18px;
+  color: #000066
+}
+
+/** Navigation Headers ***/
+.vc_navheader {
+  background-color: #e0e0ff;
+  font-size: 13px;
+  vertical-align:middle;
+}
+.vc_navheader td{
+  vertical-align:middle;
+}
+
+/*** Table Headers ***/
+.vc_header {
+  text-align: left;
+  vertical-align: top;
+  background-color: #e0e0ff;
+}
+.vc_header_sort {
+  text-align: left;
+  background-color: #e0e0ff;
+}
+
+
+/*** Table Rows ***/
+.vc_row_even {
+  background-color: #ffffff;
+}
+.vc_row_odd {
+  background-color: #eeeeee;
+}
+
+
+/*** Log messages ***/
+.vc_log {
+  white-space: pre-wrap;
+  background-color: #eeeeee;
+}
+
+/*** Properties Listing ***/
+.vc_properties {
+  margin: 1em 0;
+}
+.vc_properties h2 {
+  font-size: 115%;
+}
+
+/*** File Content Markup Styles ***/
+.vc_summary {
+  background-color: #eeeeee;
+}
+#vc_file td {
+  border-right-style: solid;
+  border-right-color: #505050;
+  text-decoration: none;
+  font-weight: normal;
+  font-style: normal;
+  padding: 1px 5px;
+}
+.vc_file_line_number {
+  border-right-width: 1px;
+  background-color: #eeeeee;
+  color: #505050;
+  text-align: right;
+}
+.vc_file_line_author, .vc_file_line_rev {
+  border-right-width: 1px;
+  text-align: right;
+}
+.vc_file_line_text {
+  border-right-width: 0px;
+  background-color: white;
+  font-family: monospace;
+  text-align: left;
+  white-space: pre;
+  width: 100%;
+}
+.pygments-c { color: #408080; font-style: italic } /* Comment */
+.pygments-err { border: 1px solid #FF0000 } /* Error */
+.pygments-k { color: #008000; font-weight: bold } /* Keyword */
+.pygments-o { color: #666666 } /* Operator */
+.pygments-cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.pygments-cp { color: #BC7A00 } /* Comment.Preproc */
+.pygments-c1 { color: #408080; font-style: italic } /* Comment.Single */
+.pygments-cs { color: #408080; font-style: italic } /* Comment.Special */
+.pygments-gd { color: #A00000 } /* Generic.Deleted */
+.pygments-ge { font-style: italic } /* Generic.Emph */
+.pygments-gr { color: #FF0000 } /* Generic.Error */
+.pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.pygments-gi { color: #00A000 } /* Generic.Inserted */
+.pygments-go { color: #808080 } /* Generic.Output */
+.pygments-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.pygments-gs { font-weight: bold } /* Generic.Strong */
+.pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.pygments-gt { color: #0040D0 } /* Generic.Traceback */
+.pygments-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.pygments-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.pygments-kp { color: #008000 } /* Keyword.Pseudo */
+.pygments-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.pygments-kt { color: #B00040 } /* Keyword.Type */
+.pygments-m { color: #666666 } /* Literal.Number */
+.pygments-s { color: #BA2121 } /* Literal.String */
+.pygments-na { color: #7D9029 } /* Name.Attribute */
+.pygments-nb { color: #008000 } /* Name.Builtin */
+.pygments-nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.pygments-no { color: #880000 } /* Name.Constant */
+.pygments-nd { color: #AA22FF } /* Name.Decorator */
+.pygments-ni { color: #999999; font-weight: bold } /* Name.Entity */
+.pygments-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.pygments-nf { color: #0000FF } /* Name.Function */
+.pygments-nl { color: #A0A000 } /* Name.Label */
+.pygments-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.pygments-nt { color: #008000; font-weight: bold } /* Name.Tag */
+.pygments-nv { color: #19177C } /* Name.Variable */
+.pygments-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.pygments-w { color: #bbbbbb } /* Text.Whitespace */
+.pygments-mf { color: #666666 } /* Literal.Number.Float */
+.pygments-mh { color: #666666 } /* Literal.Number.Hex */
+.pygments-mi { color: #666666 } /* Literal.Number.Integer */
+.pygments-mo { color: #666666 } /* Literal.Number.Oct */
+.pygments-sb { color: #BA2121 } /* Literal.String.Backtick */
+.pygments-sc { color: #BA2121 } /* Literal.String.Char */
+.pygments-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.pygments-s2 { color: #BA2121 } /* Literal.String.Double */
+.pygments-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.pygments-sh { color: #BA2121 } /* Literal.String.Heredoc */
+.pygments-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.pygments-sx { color: #008000 } /* Literal.String.Other */
+.pygments-sr { color: #BB6688 } /* Literal.String.Regex */
+.pygments-s1 { color: #BA2121 } /* Literal.String.Single */
+.pygments-ss { color: #19177C } /* Literal.String.Symbol */
+.pygments-bp { color: #008000 } /* Name.Builtin.Pseudo */
+.pygments-vc { color: #19177C } /* Name.Variable.Class */
+.pygments-vg { color: #19177C } /* Name.Variable.Global */
+.pygments-vi { color: #19177C } /* Name.Variable.Instance */
+.pygments-il { color: #666666 } /* Literal.Number.Integer.Long */
+
+
+/*** Diff Styles ***/
+.vc_diff_header {
+  background-color: #ffffff;
+}
+.vc_diff_chunk_header {
+  background-color: #eeeeee;
+}
+.vc_diff_chunk_extra {
+  font-size: smaller;
+}
+.vc_diff_empty {
+  background-color: #c8c8c8;
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_diff_add {
+  background-color: #ffff00;
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_diff_remove {
+  background-color: #ffc864;
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_diff_change {
+  background-color: #ffff96;
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_diff_change_empty {
+  background-color: #eeee77;
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_diff_nochange {
+  font-family: sans-serif;
+  font-size: smaller;
+}
+.vc_raw_diff {
+  background-color: #eeeeee;
+  font-size: 12px;
+}
+
+/*** Intraline Diff Styles ***/
+
+.vc_idiff_add {
+  background-color: #aaffaa;
+}
+.vc_idiff_change {
+  background-color:#ffff77;
+}
+.vc_idiff_remove {
+  background-color:#ffaaaa;
+}
+.vc_idiff_empty {
+  background-color:#e0e0e0;
+}
+
+table.vc_idiff col.content { 
+  width: 50%;
+}
+table.vc_idiff tbody {
+  font-family: monospace; 
+  /* unfortunately, white-space: pre-wrap isn't widely supported ... */
+  white-space: pre-wrap;      /* CSS3 */
+}
+table.vc_idiff tbody th {
+  background-color:#e0e0e0;
+  text-align:right;
+}
+
+/*** Query Form ***/
+.vc_query_form {
+  background-color: #e0e0ff;
+}

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/error.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/error.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,24 @@
+<!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">
+<!-- ViewVC :: http://www.viewvc.org/ -->
+<head>
+<title>ViewVC Exception</title>
+</head>
+<body>
+<h3>An Exception Has Occurred</h3>
+
+[if-any msg]
+  <p><pre>[msg]</pre></p>
+[end]
+[if-any status]
+  <h4>HTTP Response Status</h4>
+  <p><pre>[status]</pre></p>
+  <hr />
+[end]
+<h4>Python Traceback</h4>
+<p><pre>
+[stacktrace]
+</pre></p>
+</body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/file.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/file.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,79 @@
+[# setup page definitions]
+  [define page_title]View of /[where][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "markup"]
+[include "include/file_header.ezt"]
+<hr />
+<div class="vc_summary">
+Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end]&nbsp; 
+[if-any download_href]<a href="[download_href]" title="Download"><img src="[docroot]/images/download.png" alt="Download"/></a>[end]
+<!--[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]-->
+
+[is view "markup"]
+	[if-any annotate_href]<a href="[annotate_href]" title="Blame"><img src="[docroot]/images/tortoisesvn/blame.png" alt="Blame"/></a>[end]
+[end]
+[is view "annotate"]
+	<a href="[view_href]" title="View"><img src="[docroot]/images/text.png" alt="View"/></a>
+[end]
+
+[if-any orig_path]
+  <br />Original Path: <a href="[orig_href]"><em>[orig_path]</em></a>
+[end]
+[if-any mime_type]
+  <br />File MIME type: [mime_type]
+[end]
+[if-any size]
+  <br />File size: [size] byte(s)
+[end]
+[if-any log]
+  <pre class="vc_log">[log]</pre>
+[end]
+</div>
+
+
+[define last_rev]0[end]
+[define rowclass]vc_row_even[end]
+
+[if-any lines]
+
+<div id="vc_file">
+<table cellspacing="0" cellpadding="0">
+[for lines]
+  [is lines.rev last_rev]
+  [else]
+    [is lines.rev rev]
+      [define rowclass]vc_row_special[end]
+    [else]
+      [is rowclass "vc_row_even"]
+        [define rowclass]vc_row_odd[end]
+      [else]
+        [define rowclass]vc_row_even[end]
+      [end]
+    [end]
+  [end]
+
+  <tr class="[rowclass]" id="l[lines.line_number]">
+    <td class="vc_file_line_number">[lines.line_number]</td>
+[is annotation "annotated"]
+    <td class="vc_file_line_author">[is lines.rev last_rev]&nbsp;[else][lines.author][end]</td>
+    <td class="vc_file_line_rev">[is lines.rev last_rev]&nbsp;[else][if-any lines.diff_href]<a href="[lines.diff_href]">[end][lines.rev][if-any lines.diff_href]</a>[end][end]</td>
+[end]
+    <td class="vc_file_line_text">[lines.text]</td>
+  </tr>
+  [define last_rev][lines.rev][end]
+[end]
+</table>
+</div>
+
+[else]
+[if-any image_src_href]
+<div id="vc_file_image">
+<img src="[image_src_href]" alt="" />
+</div>
+[end]
+[end]
+
+[include "include/props.ezt"]
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/diff_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/diff_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,34 @@
+  <hr />
+  <p><a name="diff"></a>
+  This form allows you to request diffs between any two revisions of this file.
+  For each of the two "sides" of the diff,
+  enter a numeric revision.
+  </p>
+  <form method="get" action="[diff_select_action]" id="diff_select">
+
+  <table cellpadding="2" cellspacing="0" class="auto">
+  <tr>
+  <td>&nbsp;</td>
+  <td>
+  [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
+  Diffs between
+  <input type="text" size="12" name="r1"
+         value="[if-any rev_selected][rev_selected][else][first_revision][end]" />
+
+  and
+  <input type="text" size="12" name="r2" value="[last_revision]" />
+  </td>
+  </tr>
+  <tr>
+  <td>&nbsp;</td>
+  <td>
+  Type of Diff should be a
+  <select name="diff_format" onchange="submit()">
+    <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
+    <option value="u" [is diff_format "u"]selected="selected"[end]>Unidiff</option>
+  </select>
+  <input type="submit" value="  Get Diffs  " />
+  </td>
+  </tr>
+  </table>
+  </form>

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_footer.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_footer.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,28 @@
+[if-any where]
+  <table>
+    <tr>
+      <td style="text-align: right;">
+        [# 
+          Enable this section and replace protocoll://svnparentlocation with your SVN parent URL location
+          (e.g. https://server/svn) to enable direct TortoiseSVN checkouts. This works only if all your
+          repositories have the same location, e.g. if you use the SVNParentPath directive in mod_dav_svn
+        ]
+        <!--
+        <a href="tsvn:protocoll://svnparentlocation/[rootname]/[where]/" title="TortoiseSVN Checkout...">
+          <img src="[docroot]/images/tortoisesvn/checkout.png" alt="TortoiseSVN Checkout..."/>
+        </a>
+        &nbsp;
+        -->
+        [if-any tarball_href]
+        <a href="[tarball_href]" title="Download as GNU tarball">
+          <img src="[docroot]/images/download.png" alt="Download as GNU tarball"/>
+        </a>
+        [end]
+        &nbsp;
+      </td>
+    </tr>
+  </table>
+[end]
+
+[include "props.ezt"]
+[include "footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_header.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/dir_header.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,53 @@
+[# setup page definitions]
+  [define page_title]Index of /[where][end]
+  [define help_href][docroot]/help_[if-any where]dir[else]root[end]view.html[end]
+[# end]
+
+[include "header.ezt" "directory"]
+
+[if-any where][else]
+  <!-- you may insert repository access instructions here -->
+[end]
+
+<table class="auto">
+<tr>
+  <td>Directory revision:</td>
+  <td><a href="[tree_rev_href]" title="Revision [tree_rev]">[tree_rev]</a>[if-any youngest_rev] (of <a href="[youngest_rev_href]" title="Revision [youngest_rev]">[youngest_rev]</a>)[end]</td>
+</tr>
+
+<tr>
+  <td>Sticky Revision:</td>
+  <td>[include "pathrev_form.ezt"]</td>
+</tr>
+[if-any search_re]
+<tr><td>Current search:</td><td><strong>[search_re]</strong></td></tr>
+[end]
+
+[if-any queryform_href]
+<tr>
+  <td>Query:</td>
+  <td><a href="[queryform_href]">Query revision history</a></td>
+</tr>
+[end]
+</table>
+  
+[is cfg.options.use_pagesize "0"]
+[else]
+  [is picklist_len "1"]
+  [else]
+    <form method="get" action="[dir_paging_action]">
+      [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
+      <input type="submit" value="Go to:" />
+      <select name="dir_pagestart"  onchange="submit()">
+        [for picklist]
+          <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
+        [end]
+      </select>
+    </form>
+  [end]
+[end]
+
+<p><a name="dirlist"></a></p>
+
+<hr />
+

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/file_header.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/file_header.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,24 @@
+<p style="margin:0;">
+<a href="[up_href]" title="Parent Directory" class="img"><img src="[docroot]/images/tortoisesvn/back_small.png" width="16" height="16" alt="Parent Directory" /></a>&nbsp;<a href="[up_href]">Parent Directory</a>
+
+[is view "markup"]
+	[if-any log_href] 
+    	<a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]" title="Revision Log" class="img"><img src="[docroot]/images/tortoisesvn/log.png" width="16" height="16" alt="Revision Log" /></a>&nbsp;<a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]">Revision Log</a>
+	[end]
+[end]
+[is view "annotate"]
+	[if-any log_href] 
+    	<a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]" title="Revision Log" class="img"><img src="[docroot]/images/tortoisesvn/log.png" width="16" height="16" alt="Revision Log" /></a>&nbsp;<a href="[log_href][if-any log_href_rev]#rev[log_href_rev][end]">Revision Log</a>
+	[end]
+[end]
+
+
+[is view "diff"]
+    <a href="[patch_href]" title="View Patch" class="img"><img src="[docroot]/images/tortoisesvn/patch.png" width="16" height="16" alt="View Patch" /></a>&nbsp;<a href="[patch_href]">Patch</a>
+[end]
+
+[is pathtype "file"]
+[else]
+  <a href="[view_href]" title="View Directory Listing" class="img"><img src="[docroot]/images/dir.png" width="16" height="16" alt="View Directory Listing" /></a>&nbsp;<a href="[view_href]">Directory Listing</a>
+[end]
+</p>

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/footer.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/footer.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,21 @@
+[# standard footer used by all ViewVC pages ]
+
+<hr />
+
+<table>
+<tr>
+  <td>[if-any cfg.general.address]<address><a href="mailto:[cfg.general.address]";>[cfg.general.address]</a></address>[else]&nbsp;[end]</td>
+  <td style="text-align: right;">
+    <a href="http://subversion.tigris.org/"; title="Subversion"><img src="[docroot]/images/svn.png" alt="Subversion"/></a>&nbsp;
+	<a href="http://tortoisesvn.net/"; title="TortoiseSVN"><img src="[docroot]/images/tortoisesvn/tsvn.png" alt="TortoiseSVN"/></a>&nbsp;
+	<a href="http://www.viewvc.org/"; title="ViewVC" ><img src="[docroot]/images/viewvc.png" alt="ViewVC"/></a>
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td style="text-align: right;">[if-any rss_href]<a href="[rss_href]" title="RSS 2.0 feed"><img src="[docroot]/images/feed-icon-16x16.jpg" alt="RSS 2.0 feed"/></a>[else]&nbsp;[end]</td>
+</tr>
+</table>
+
+</body>
+</html>

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/header.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/header.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,49 @@
+<!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">
+<!-- ViewVC :: http://www.viewvc.org/ -->
+<head>
+  <title>[if-any rootname][[][rootname]][else]Subversion[end] [page_title]</title>
+  <meta name="generator" content="ViewVC [vsn]" />
+  [# set your favicon here ]
+  <!--
+  <link rel="shortcut icon" href="[docroot]/images/favicon-yourorganisation.ico" />
+  -->
+  <link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
+  [if-any rss_href]<link rel="alternate" type="application/rss+xml" title="RSS [[][rootname]][where]" href="[rss_href]" />[end]
+</head>
+<body>
+
+[is roottype "svn"][else][if-any roots][else]
+<h1>
+Do not use this template set if you plan to view cvs repositories through ViewVC! 
+This template-set is heavily trimmed for Subversion needs. Special CVS features are 
+untested, possibly disabled or broken.
+</h1>
+[end][end]
+
+<div style="float: right; padding: 5px;">
+  [# insert your logo and link to your organisation here ]
+  <!--
+  <a href="http://www.yourorganisation.com"; title="yourorganisation"><img src="[docroot]/images/logo-yourorganisation.png" alt="yourorganisation" /></a>
+  -->
+</div>
+
+<div class="vc_navheader">
+  <strong>[if-any roots_href]<a href="[roots_href]">[[]Repository Listing]</a> /[else]/[end]</strong>
+  [if-any nav_path]<strong>
+    [for nav_path]
+      [if-any nav_path.href]<a href="[nav_path.href]">[end]
+      [if-index nav_path first]
+        [[][nav_path.name]][else]
+        [nav_path.name][end][if-any nav_path.href]</a>[end]
+      [if-index nav_path last][else]/[end]
+    [end]
+    </strong>
+  [end]
+</div>
+
+
+<h1>[page_title]</h1>
+
+

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_footer.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_footer.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,7 @@
+[include "paging.ezt"]
+
+[is pathtype "file"]
+  [include "diff_form.ezt"]
+[end]
+
+[include "footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_header.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/log_header.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,45 @@
+[# setup page definitions]
+  [define page_title]Log of /[where][end]
+  [define help_href][docroot]/help_log.html[end]
+[# end]
+
+[include "header.ezt" "log"]
+[include "file_header.ezt"]
+
+<hr />
+
+<table class="auto">
+</tr>
+
+[is pathtype "file"]
+[if-any view_href]
+<tr>
+  <td>Links to HEAD:</td>
+  <td>
+    <a href="[view_href]" title="View"><img src="[docroot]/images/text.png" alt="View"/></a>
+    [if-any download_href]<a href="[download_href]" title="Download"><img src="[docroot]/images/download.png" alt="Download"/></a>[end]
+    [if-any annotate_href]<a href="[annotate_href]" title="Blame"><img src="[docroot]/images/tortoisesvn/blame.png" alt="Blame"/></a>[end]
+  </td>
+</tr>
+[end]
+
+[if-any tag_view_href]
+<tr>
+  <td>Links to [pathrev]:</td>
+  <td>
+    <a href="[tag_view_href]" title="View"><img src="[docroot]/images/text.png" alt="View"/></a>
+    [if-any tag_download_href]<a href="[tag_download_href]" title="Download"><img src="[docroot]/images/download.png" alt="Download"/></a>[end]
+    [if-any tag_annotate_href]<a href="[tag_annotate_href]" title="Blame"><img src="[docroot]/images/tortoisesvn/blame.png" alt="Blame"/></a>[end]
+  </td>
+</tr>
+[end]
+[end]
+
+<tr>
+  <td>Sticky [is roottype "cvs"]Tag[else]Revision[end]:</td>
+  <td>[include "pathrev_form.ezt"]</td>
+</tr>
+
+</table>
+
+[include "paging.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/paging.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/paging.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,22 @@
+  [is cfg.options.use_pagesize "0"]
+  [else]
+    [is picklist_len "1"]
+    [else]
+      <hr />
+      <form method="get" action="[log_paging_action]">
+        [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
+        <input type="submit" value="Go to:" />
+        <select name="log_pagestart"  onchange="submit()">
+          [for picklist]
+           [if-any picklist.more]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+           [else]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+           [end]
+          [end]
+        </select>
+      </form>
+    [end]
+  [end]
+
+

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/pathrev_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/pathrev_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,21 @@
+<form method="get" action="[pathrev_action]" style="display: inline">
+<div style="display: inline">
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
+  <input type="text" name="pathrev" value="[pathrev]" size="6"/>
+<input type="submit" value="Set" />
+</div>
+</form>
+
+[if-any pathrev]
+<form method="get" action="[pathrev_clear_action]" style="display: inline">
+<div style="display: inline">
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
+[if-any lastrev]
+  [is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
+  (<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)
+[else]
+  <input type="submit" value="Clear" />
+[end]
+</div>
+</form>
+[end]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/props.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/include/props.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,26 @@
+[if-any properties]
+<hr/>
+<div class="vc_properties">
+<h2>Properties</h2>
+<table cellspacing="1" cellpadding="2" class="props">
+<thead>
+  <tr>
+    <th class="vc_header_sort" width="50%">Name</th>
+    <th class="vc_header" width="50%">Value</th>
+  </tr>
+</thead>
+<tbody>
+[for properties]
+  <tr class="vc_row_[if-index properties even]even[else]odd[end]">
+    <td><strong>[properties.name]</strong></td>
+    [if-any properties.undisplayable]
+    <td><em>Property value is undisplayable.</em></td>
+    [else]
+    <td style="white-space: pre;">[properties.value]</td>
+    [end]
+  </tr>
+[end]
+</tbody>
+</table>
+</div>
+[end]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/log.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/log.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,53 @@
+[include "include/log_header.ezt"]
+
+[define first_revision][end]
+[define last_revision][end]
+
+[for entries]
+[if-index entries first][define first_revision][entries.rev][end][end]
+[if-index entries last][define last_revision][entries.rev][end][end]
+
+<div>
+  <hr />
+
+   <a name="rev[entries.rev]"></a>
+
+   Revision <a href="[entries.revision_href]"><strong>[entries.rev]</strong></a>&nbsp;
+   [is pathtype "file"]
+     [if-any entries.view_href]<a href="[entries.view_href]" title="View"><img src="[docroot]/images/text.png" alt="View"/></a>[end]
+   [else]
+     <a href="[entries.view_href]" title="Directory Listing"><img src="[docroot]/images/dir.png" alt="Directory Listing"/></a>
+   [end]
+   [if-any entries.download_href]<a href="[entries.download_href]" title="Download"><img src="[docroot]/images/download.png" alt="Download"/></a>[end]
+
+   [if-any entries.annotate_href]<a href="[entries.annotate_href]" title="Blame"><img src="[docroot]/images/tortoisesvn/blame.png" alt="Blame"/></a>[end]
+  <br />
+
+  [if-index entries last]Added[else]Modified[end]
+  
+  <em>[entries.date]</em> ([entries.ago] ago) by <em>[entries.author]</em>
+
+  [if-any entries.orig_path]
+    <br />Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a>
+  [end]
+
+  [if-any entries.size]
+  <br />File length: [entries.size] byte(s)
+  [end]
+
+  [if-any entries.copy_path]
+  <br />Copied from: <a href="[entries.copy_href]"><em>[entries.copy_path]</em></a> revision [entries.copy_rev]
+  [end]
+
+
+  [is pathtype "file"]
+   [if-any entries.prev]
+     <br />Diff to <a href="[entries.diff_to_prev_href]">previous [entries.prev]</a>
+   [end]
+ [end]
+
+<pre class="vc_log">[entries.log]</pre>
+</div>
+[end]
+
+[include "include/log_footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,241 @@
+<!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">
+<!-- ViewVC :: http://www.viewvc.org/ -->
+<head>
+  <title>Checkin Database Query</title>
+  <link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
+</head>
+
+<body>
+
+[# setup page definitions]
+  [define help_href][docroot]/help_query.html[end]
+[# end]
+
+  <p> 
+    Select your parameters for querying the CVS commit database.  You
+    can search for multiple matches by typing a comma-seperated list
+    into the text fields.  Regular expressions, and wildcards are also
+    supported.  Blank text input fields are treated as wildcards.
+  </p>
+  <p>
+    Any of the text entry fields can take a comma-seperated list of
+    search arguments.  For example, to search for all commits from
+    authors <em>jpaint</em> and <em>gstein</em>, just type: <strong>jpaint,
+    gstein</strong> in the <em>Author</em> input box.  If you are searching
+    for items containing spaces or quotes, you will need to quote your
+    request.  For example, the same search above with quotes is:
+    <strong>"jpaint", "gstein"</strong>.
+  </p>
+  <p>                           
+
+    Wildcard and regular expression searches are entered in a similar
+    way to the quoted requests.  You must quote any wildcard or
+    regular expression request, and a command charactor preceeds the
+    first quote.  The command charactor <strong>l</strong> is for wildcard
+    searches, and the wildcard charactor is a percent (<strong>%</strong>).  The
+    command charactor for regular expressions is <strong>r</strong>, and is
+    passed directly to MySQL, so you'll need to refer to the MySQL
+    manual for the exact regex syntax.  It is very similar to Perl.  A
+    wildard search for all files with a <em>.py</em> extention is:
+    <strong>l"%.py"</strong> in the <em>File</em> input box.  The same search done
+    with a regular expression is: <strong>r".*\.py"</strong>.
+  </p>
+  <p>                  
+    All search types can be mixed, as long as they are seperated by
+    commas.
+  </p>                                                    
+
+<form method="get" action="">
+
+<div class="vc_query_form">
+<table cellspacing="0" cellpadding="2" class="auto">
+ <tr>
+  <td>
+   <table>
+    <tr>
+     <td style="vertical-align:top;">
+
+      <table>
+       <tr>
+        <td align="right">CVS Repository:</td>
+        <td>
+         <input type="text" name="repository" size="40" value="[repository]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">CVS Branch:</td>
+        <td>
+         <input type="text" name="branch" size="40" value="[branch]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">Directory:</td>
+        <td>
+         <input type="text" name="directory" size="40" value="[directory]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">File:</td>
+        <td>
+         <input type="text" name="file" size="40" value="[file]" />
+        </td>
+       </tr>
+       <tr>
+        <td align="right">Author:</td>
+        <td>
+         <input type="text" name="who" size="40" value="[who]" />
+        </td>
+       </tr>
+      </table>
+
+     </td>
+     <td style="vertical-align:top;">
+
+      <table>
+       <tr>
+        <td align="left">Sort By:</td>
+        <td>
+         <select name="sortby">
+          <option value="date" [is sortby "date"]selected="selected"[end]>Date</option>
+          <option value="author" [is sortby "author"]selected="selected"[end]>Author</option>
+          <option value="file" [is sortby "file"]selected="selected"[end]>File</option>
+         </select>
+        </td>
+       </tr>
+       <tr>
+        <td colspan="2">
+         <table cellspacing="0" cellpadding="0">
+          <tr>
+           <td>Date:</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="hours"
+		  [is date "hours"]checked="checked"[end] /></td>
+           <td>In the last
+             <input type="text" name="hours" value="[hours]" size="4" />hours
+           </td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="day"
+		  [is date "day"]checked="checked"[end] /></td>
+           <td>In the last day</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="week"
+		  [is date "week"]checked="checked"[end] /></td>
+           <td>In the last week</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="month"
+		  [is date "month"]checked="checked"[end] /></td>
+           <td>In the last month</td>
+          </tr>
+          <tr>
+           <td><input type="radio" name="date" value="all"
+		  [is date "all"]checked="checked"[end] /></td>
+           <td>Since the beginning of time</td>
+          </tr>
+         </table>
+        </td>
+       </tr>
+      </table>
+
+     </td>
+    </tr>
+   </table>
+  </td>
+  <td>
+   <input type="submit" value="Search" />
+  </td>
+ </tr>
+</table>
+</div>
+
+</form>
+
+[is query "skipped"]
+[else]
+<p><strong>[num_commits]</strong> matches found.</p>
+
+[if-any commits]
+<table cellspacing="0" cellpadding="2">
+ <thead>
+ <tr class="vc_header">
+  <th>Revision</th>
+  <th>File</th>
+  <th>Branch</th>
+  <th>+/-</th>
+  <th>Date</th>
+  <th>Author</th>
+[# uncommment, if you want a separate Description column: (also see below)
+<th>Description</th>
+]
+ </tr>
+ </thead>
+[for commits]
+ <tbody>
+  [for commits.files]
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td style="vertical-align:top;">
+	[if-any commits.files.rev][commits.files.rev][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">[commits.files.link]</td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.branch][commits.files.branch][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">
+        [is commits.files.type "Add"]<ins>[end]
+        [is commits.files.type "Change"]<a href="[commits.files.difflink]">[end]
+        [is commits.files.type "Remove"]<del>[end]
+          [commits.files.plus]/[commits.files.minus]
+        [is commits.files.type "Add"]</ins>[end]
+        [is commits.files.type "Change"]</a>[end]
+        [is commits.files.type "Remove"]</del>[end]
+      </td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.date][commits.files.date][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align:top;">
+	[if-any commits.files.author][commits.files.author][else]&nbsp;[end]
+      </td>
+
+[# uncommment, if you want a separate Description column:
+      {if-index commits.files first{
+        <td style="vertical-align:top;" rowspan="{commits.num_files}">
+          {commits.log}
+        </td>
+      {end}
+
+   (substitute brackets for the braces)
+]
+    </tr>
+[# and also take the following out in the "Description column"-case:]
+      [if-index commits.files last]
+	<tr class="vc_row_[if-index commits even]even[else]odd[end]">
+	  <td>&nbsp;</td>
+	  <td colspan="5"><strong>Log:</strong><br />
+	    <pre class="vc_log">[commits.log]</pre></td>
+	</tr>
+      [end]
+[# ---]
+  [end]
+ </tbody>
+[end]
+
+ <tr class="vc_header">
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+[# uncommment, if you want a separate Description column:
+  <th style="text-align:left;vertical-align:top;">&nbsp;</th>
+]
+ </tr>
+</table>
+[end]
+[end]
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_form.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_form.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,152 @@
+[# setup page definitions]
+  [define page_title]Query on /[where][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "query"]
+
+<p>
+<a href="[dir_href]" title="Browse Directory"><img src="[docroot]/images/dir.png" width="16" height="16" alt="Browse Directory" /></a>&nbsp;
+<a href="[dir_href]" class="img">Browse Directory</a></p>
+
+<form action="[query_action]" method="get">
+
+<div class="vc_query_form">
+  [query_hidden_values]
+<table cellspacing="0" cellpadding="5" class="auto">
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Subdirectory:</th>
+    <td>
+      <input type="text" name="dir" value="[dir]" /><br />
+      (you can list multiple directories separated by commas)
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">File:</th>
+    <td>
+      <input type="text" name="file" value="[file]" /><br />
+      <label for="file_match_exact">
+        <input type="radio" name="file_match" id="file_match_exact"
+           value="exact" [is file_match "exact"]checked="checked"[end] />
+        Exact match
+      </label>
+      <label for="file_match_glob">
+        <input type="radio" name="file_match" id="file_match_glob"
+           value="glob" [is file_match "glob"]checked="checked"[end] />
+        Glob pattern match
+      </label>
+      <label for="file_match_regex">
+        <input type="radio" name="file_match" id="file_match_regex"
+           value="regex" [is file_match "regex"]checked="checked"[end] />
+        Regex match
+      </label>
+      <label for="file_match_notregex">
+        <input type="radio" name="file_match" id="file_match_notregex"
+           value="notregex" [is file_match "notregex"]checked="checked"[end] />
+        Regex doesn't match
+      </label>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Who:</th>
+    <td>
+      <input type="text" name="who" value="[who]" /><br />
+      <label for="who_match_exact">
+        <input type="radio" name="who_match" id="who_match_exact"
+           value="exact" [is who_match "exact"]checked="checked"[end] />
+        Exact match
+      </label>
+      <label for="who_match_glob">
+        <input type="radio" name="who_match" id="who_match_glob"
+           value="glob" [is who_match "glob"]checked="checked"[end] />
+        Glob pattern match
+      </label>
+      <label for="who_match_regex">
+        <input type="radio" name="who_match" id="who_match_regex"
+           value="regex" [is who_match "regex"]checked="checked"[end] />
+        Regex match
+      </label>
+      <label for="who_match_notregex">
+        <input type="radio" name="who_match" id="who_match_notregex"
+           value="notregex" [is who_match "notregex"]checked="checked"[end] />
+        Regex doesn't match
+      </label>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Sort By:</th>
+    <td>
+      <select name="querysort">
+        <option value="date" [is querysort "date"]selected="selected"[end]>Date</option>
+        <option value="author" [is querysort "author"]selected="selected"[end]>Author</option>
+        <option value="file" [is querysort "file"]selected="selected"[end]>File</option>
+      </select>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Date:</th>
+    <td>
+      <table cellspacing="0" cellpadding="0">
+        <tr>
+          <td><input type="radio" name="date" id="date_hours"
+                 value="hours" [is date "hours"]checked="checked"[end] /></td>
+          <td>
+            <label for="date_hours">In the last</label>
+            <input type="text" name="hours" value="[hours]" size="4" />
+            hours
+          </td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_day"
+                 value="day" [is date "day"]checked="checked"[end] /></td>
+          <td><label for="date_day">In the last day</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_week"
+                 value="week" [is date "week"]checked="checked"[end] /></td>
+          <td><label for="date_week">In the last week</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_month"
+                 value="month" [is date "month"]checked="checked"[end] /></td>
+          <td><label for="date_month">In the last month</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_all"
+                 value="all" [is date "all"]checked="checked"[end] /></td>
+          <td><label for="date_all">Since the beginning of time</label></td>
+        </tr>
+        <tr>
+          <td><input type="radio" name="date" id="date_explicit"
+                 value="explicit" [is date "explicit"]checked="checked"[end] /></td>
+          <td>
+            <label for="date_explicit">Between</label>
+            <input type="text" name="mindate" value="[mindate]" size="20" />
+            and
+            <input type="text" name="maxdate" value="[maxdate]" size="20" />
+            <br />
+            (use the form <strong>yyyy-mm-dd hh:mm:ss</strong>)
+          </td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+  <tr>
+    <th style="text-align:right;vertical-align:top;">Limit:</th>
+    <td>
+      Show at most
+      <input type="text" name="limit_changes" value="[limit_changes]" size="5" />
+      changed files per commit.<br />
+      (use 0 to show all files)
+    </td>
+  </tr>
+  <tr>
+    <td></td>
+    <td><input type="submit" value="Search" /></td>
+  </tr>
+</table>
+</div>
+
+</form>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_results.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/query_results.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,90 @@
+[# setup page definitions]
+  [define page_title]Query results on /[where][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt"]
+
+<p><a href="[queryform_href]" title="Modify query" class="img"><img src="[docroot]/images/tortoisesvn/back.png" alt="Modify query" width="16" height="16" /></a>&nbsp;<a href="[queryform_href]">Modify query</a></p>
+<p><strong>[english_query]</strong></p>
+[# <!-- {sql} --> ]
+<!-- <p><a href="[backout_href]">Show commands which could be used to back out these changes</a></p> -->
+
+<p><strong>+[plus_count]/-[minus_count]</strong> lines changed.</p>
+
+[if-any commits]
+<table cellspacing="1" cellpadding="2">
+ <thead>
+  <tr>
+   <th class="vc_header">Revision</th>
+   <th class="vc_header[is querysort "file"]_sort[end]">File</th>
+   <th class="vc_header">+/-</th>
+   <th class="vc_header[is querysort "date"]_sort[end]">Date</th>
+   <th class="vc_header[is querysort "author"]_sort[end]">Author</th>
+[# uncommment, if you want a separate Description column: (also see below)
+   <th class="vc_header">Description</th>
+]
+  </tr>
+ </thead>
+[for commits]
+  [for commits.files]
+    <tbody>
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td style="vertical-align: top;">
+	[if-any commits.files.rev]
+	  [is commits.files.type "Add"]<a href="[commits.files.log_href]">[end]
+	  [is commits.files.type "Change"]<a href="[commits.files.log_href]">[end]
+	  [commits.files.rev]
+	  [is commits.files.type "Add"]</a>[end]
+	  [is commits.files.type "Change"]</a>[end]
+	[else]&nbsp;[end]
+      </td>
+      <td style="vertical-align: top;">
+        <a href="[commits.files.dir_href]">[commits.files.dir]/</a>
+		
+        [is commits.files.type "Add"]<a href="[if-any commits.files.prefer_markup][commits.files.view_href][else][commits.files.download_href][end]">[end]
+		[is commits.files.type "Change"]<a href="[if-any commits.files.prefer_markup][commits.files.view_href][else][commits.files.download_href][end]">[end]
+		[commits.files.file]
+		[is commits.files.type "Add"]</a>[end]
+		[is commits.files.type "Change"]</a>[end]
+		
+		
+      </td>
+      <td style="vertical-align: top;">
+        [# only show a diff link for changes ]
+        [is commits.files.type "Add"]<ins>[end]
+        [is commits.files.type "Change"]<a href="[commits.files.diff_href]">[end]
+        [is commits.files.type "Remove"]<del>[end]
+          [commits.files.plus]/[commits.files.minus]
+        [is commits.files.type "Add"]</ins>[end]
+        [is commits.files.type "Change"]</a>[end]
+        [is commits.files.type "Remove"]</del>[end]
+      </td>
+      <td style="vertical-align: top;">
+	[if-any commits.files.date][commits.files.date][else]&nbsp;[end]
+      </td>
+      <td style="vertical-align: top;">
+	[if-any commits.files.author][commits.files.author][else]&nbsp;[end]
+      </td>
+    </tr>
+  [end]
+  [if-any commits.limited_files]
+    <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+      <td>&nbsp;</td>
+      <td colspan="5">
+        <strong><em><small>Only first [commits.num_files] files shown.
+        <a href="[limit_changes_href]">Show all files</a> or
+        <a href="[queryform_href]">adjust limit</a>.</small></em></strong>
+    </tr>
+  [end]
+  <tr class="vc_row_[if-index commits even]even[else]odd[end]">
+    <td>&nbsp;</td>
+    <td colspan="4"><strong>Log:</strong><br />
+      <pre>[commits.log]</pre></td>
+  </tr>
+  </tbody>
+[end]
+</table>
+[end]
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/revision.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/revision.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,85 @@
+[# setup page definitions]
+  [define page_title]Revision [rev][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "revision"]
+
+<hr />
+<form method="get" action="[jump_rev_action]">
+<table cellspacing="1" cellpadding="2" style="width: auto;">
+  <tr align="left">
+    <th>Jump to revision:</th>
+    <td>
+      [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
+      <input type="text" name="revision" value="[rev]" />
+      <input type="submit" value="Go" />
+      [if-any prev_href]
+        <a href="[prev_href]" title="Previous"><img src="[docroot]/images/tortoisesvn/back.png" alt="Previous" /></a>[end]
+      [if-any next_href] <a href="[next_href]" title="Next"><img src="[docroot]/images/tortoisesvn/forward.png" alt="Next" /></a>[end]
+    </td>
+  </tr>
+  <tr align="left">
+    <th>Author:</th>
+    <td>[if-any author][author][else]<em>(unknown author)</em>[end]</td>
+  </tr>
+  <tr align="left">
+    <th>Date:</th>
+    <td>[date] <em>([ago] ago)</em></td>
+  </tr>
+  <tr align="left">
+    <th>Log Message:</th>
+    <td><pre class="vc_log">[log]</pre></td>
+  </tr>
+</table>
+</form>
+
+<hr />
+
+<p><strong>Changed paths:</strong></p>
+
+[if-any more_changes]
+  <div>
+    Only [limit_changes] changes shown,
+    <a href="[more_changes_href]">display [more_changes] more changes...</a>
+  </div>
+[end]
+
+[if-any first_changes]
+  <div><a href="[first_changes_href]">Show only first [first_changes] changes...</div>
+[end]
+
+<table cellspacing="1" cellpadding="2">
+  <thead>
+  <tr align="left">
+    <th class="vc_header_sort">Path</th>
+    <th class="vc_header" width="150">Action</th>
+    <th class="vc_header" width="40"></th>
+  </tr>
+  </thead>
+  <tbody>
+  [if-any changes]
+   [for changes]
+    <tr class="vc_row_[if-index changes even]even[else]odd[end]">
+      <td>[if-any changes.view_href]<a href="[changes.view_href]">[end]<img src="[docroot]/images/[is changes.pathtype "dir"]dir[else]text[end].png" width="16" height="16" alt="[changes.path]" />&nbsp;[changes.path][is changes.pathtype "dir"]/[end][if-any changes.view_href]</a>[end]
+      [if-any changes.is_copy]<br /><em>(Copied from [changes.copy_path], r[changes.copy_rev])</em>[end]
+      </td>
+      <td>
+          [changes.action]
+          [if-any changes.prop_mods], props changed[end]
+      </td>
+      <td>
+        <a href="[changes.log_href]" title="Revision Log" class="img"><img src="[docroot]/images/tortoisesvn/log.png" width="16" height="16" alt="Revision Log" /></a>
+        [if-any changes.diff_href]<a href="[changes.diff_href]" title="Diff to previous"><img src="[docroot]/images/tortoisesvn/diff.png" alt="Diff to previous" /></a>[end]
+      </td>
+    </tr>
+   [end]
+  [else]
+    <tr>
+    <td colspan="5">No changed paths.</td>
+    </tr>
+  [end]
+  </tbody>
+</table>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/roots.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/roots.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,28 @@
+[# setup page definitions]
+  [define page_title]Repository Listing[end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "directory"]
+
+<table cellspacing="1" cellpadding="2">
+<thead>
+<tr>
+  <th class="vc_header_sort">Name</th>
+</tr>
+</thead>
+
+<tbody>
+[for roots]
+  <tr class="vc_row_[if-index roots even]even[else]odd[end]">
+    <td>
+      <a href="[roots.href]" title="[roots.name]" class="img"><img src="[docroot]/images/tortoisesvn/repos.png" alt="[roots.name]" width="16" height="16" /></a>
+	  <a href="[roots.href]">[roots.name]</a>
+    </td>
+  </tr>
+[end]
+</tbody>
+
+</table>
+
+[include "include/footer.ezt"]

Added: branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/rss.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates-contrib/viewsvn/templates/rss.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+<channel>
+    <title>[rootname] checkins[if-any where] (in [where])[end]</title>
+
+    <description>Subversion commits to the[if-any where] [where] directory of the[end] [rootname] repository</description>
+
+	[for commits]<item>
+        <title>[if-any commits.rev][commits.rev]: [end][[commits.author]] [commits.short_log]</title>
+		[if-any commits.rss_url]<link>[commits.rss_url]</link>[end]
+		<author>[commits.author]</author>
+		<pubDate>[commits.rss_date]</pubDate>
+		<description>&lt;pre&gt;[format "xml"][commits.log][end]&lt;/pre&gt;</description>
+    </item>[end]
+</channel>	
+</rss>

Modified: branches/VIEWCVS_DIST/templates/diff.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/diff.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/diff.ezt	Mon Nov  3 09:44:02 2008
@@ -196,7 +196,7 @@
     <td>
       <form method="get" action="[diff_format_action]">
         <div>
-          [diff_format_hidden_values]
+          [for diff_format_hidden_values]<input type="hidden" name="[diff_format_hidden_values.name]" value="[diff_format_hidden_values.value]"/>[end]
           <select name="diff_format" onchange="submit()">
             <option value="h" [is diff_format "h"]selected="selected"[end]>Colored Diff</option>
             <option value="l" [is diff_format "l"]selected="selected"[end]>Long Colored Diff</option>

Modified: branches/VIEWCVS_DIST/templates/dir_new.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/dir_new.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/dir_new.ezt	Mon Nov  3 09:44:02 2008
@@ -43,6 +43,7 @@
     <a name="[entries.anchor]" href="[is entries.pathtype "dir"][entries.view_href][else][if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end][end]" title="[is entries.pathtype "dir"]View Directory Contents[else][if-any entries.prefer_markup]View[else]Download[end] File Contents[end]">
        <img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
        [entries.name][is entries.pathtype "dir"]/[end]</a>
+       [if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
        [is entries.state "dead"](dead)[end]
     </td>
 

Modified: branches/VIEWCVS_DIST/templates/directory.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/directory.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/directory.ezt	Mon Nov  3 09:44:02 2008
@@ -97,7 +97,9 @@
        <td>&nbsp;[if-any entries.rev]<a href="[entries.log_href]" title="View directory revision log"><strong>[entries.rev]</strong></a>[end]</td>
        [else]
        [define rev_href][if-any entries.prefer_markup][entries.view_href][else][if-any entries.download_href][entries.download_href][end][end][end]
-       <td>&nbsp;[if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]</td>
+       <td style="white-space: nowrap;">&nbsp;[if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]
+       [if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
+       </td>
        [end]
        <td>&nbsp;[entries.ago]</td>
        <td>&nbsp;[entries.author]</td>

Modified: branches/VIEWCVS_DIST/templates/docroot/help_dirview.html
==============================================================================
--- branches/VIEWCVS_DIST/templates/docroot/help_dirview.html	(original)
+++ branches/VIEWCVS_DIST/templates/docroot/help_dirview.html	Mon Nov  3 09:44:02 2008
@@ -4,31 +4,23 @@
 <head>
   <title>ViewVC Help: Directory View</title>
   <link rel="stylesheet" href="help.css" type="text/css" />
+  <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 </head>
 <body>
+  <div><a href="http://viewvc.org/index.html";><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
   <table>
     <col class="menu" />
     <col />
-    <tr>
-      <td><a href="http://viewvc.org/index.html";><img
-	     src="images/logo.png" alt="ViewVC logotype" /></a>
-      </td>
-      <td>
-	<h1>ViewVC Help: Directory View</h1>
-      </td>
-    </tr>
     <tr><td>
        <h3>Help</h3>
        <a href="help_rootview.html">General</a><br />
        <strong>Directory&nbsp;View</strong><br />
        <a href="help_log.html">Log&nbsp;View</a><br />
+       <a href="help_query.html">Query&nbsp;Database</a><br />
+    </td><td>
 
-       <h3>Internet</h3>
-       <a href="http://viewvc.org/index.html";>Home</a><br />
-       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
-       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
-       <a href="http://viewvc.org/license-1.html";>License</a><br />
-    </td><td colspan="2">
+    <h1>ViewVC Help: Directory View</h1>
 
     <p>The directory listing view should be a familiar sight to any
     computer user. It shows the path of the current directory being viewed

Modified: branches/VIEWCVS_DIST/templates/docroot/help_log.html
==============================================================================
--- branches/VIEWCVS_DIST/templates/docroot/help_log.html	(original)
+++ branches/VIEWCVS_DIST/templates/docroot/help_log.html	Mon Nov  3 09:44:02 2008
@@ -4,32 +4,24 @@
 <head>
   <title>ViewVC Help: Log View</title>
   <link rel="stylesheet" href="help.css" type="text/css" />
+  <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
   <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 </head>
 <body>
+  <div><a href="http://viewvc.org/index.html";><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
   <table>
     <col class="menu" />
     <col />
-    <tr>
-      <td><a href="http://viewvc.org/index.html";><img
-	     src="images/logo.png" alt="ViewVC logotype" /></a>
-      </td>
-      <td>
-	<h1>ViewVC Help: Log View</h1>
-      </td>
-    </tr>
     <tr><td>
        <h3>Help</h3>
        <a href="help_rootview.html">General</a><br />
        <a href="help_dirview.html">Directory&nbsp;View</a><br />
        <strong>Log&nbsp;View</strong><br />
+       <a href="help_query.html">Query&nbsp;Database</a><br />
+    </td><td>
+
+    <h1>ViewVC Help: Log View</h1>
 
-       <h3>Internet</h3>
-       <a href="http://viewvc.org/index.html";>Home</a><br />
-       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
-       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
-       <a href="http://viewvc.org/license-1.html";>License</a><br />
-    </td><td colspan="2">
     <p>
       The log view displays the revision history of the selected source
       file or directory. For each revision the following information is

Modified: branches/VIEWCVS_DIST/templates/docroot/help_query.html
==============================================================================
--- branches/VIEWCVS_DIST/templates/docroot/help_query.html	(original)
+++ branches/VIEWCVS_DIST/templates/docroot/help_query.html	Mon Nov  3 09:44:02 2008
@@ -4,64 +4,59 @@
 <head>
   <title>ViewVC Help: Query The Commit Database</title>
   <link rel="stylesheet" href="help.css" type="text/css" />
+  <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 </head>
 <body>
-<table>
-  <col class="menu" />
-  <col />
-  <tr>
-    <td><a href=".."><img
-        src="images/logo.png" alt="ViewVC logotype" /></a>
-    </td>
-    <td><h1>ViewVC Help: Query The Commit Database</h1></td>
-  </tr>
-  <tr><td>
-     <h3>Other&nbsp;Help:</h3>
-     <a href="help_rootview.html">General</a><br />
-     <a href="help_dirview.html">Directory&nbsp;View</a><br />
-     <a href="help_log.html">Classic&nbsp;Log&nbsp;View</a><br />
-     <a href="help_logtable.html">Alternative&nbsp;Log&nbsp;View</a><br />
-     <strong>Query&nbsp;Database</strong>
-
-     <h3>Internet</h3>
-     <a href="http://viewvc.org/index.html";>Home</a><br />
-     <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
-     <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
-     <a href="http://viewvc.org/license-1.html";>License</a><br />
-  </td><td colspan="2">
-
-  <p> 
-    Select your parameters for querying the CVS commit database in the
-    form at the top of the page.  You
-    can search for multiple matches by typing a comma-seperated list
-    into the text fields.  Regular expressions, and wildcards are also
-    supported.  Blank text input fields are treated as wildcards.
-  </p>
-  <p>
-    Any of the text entry fields can take a comma-seperated list of
-    search arguments.  For example, to search for all commits from
-    authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
-    gstein</code> in the <em>Author</em> input box.  If you are searching
-    for items containing spaces or quotes, you will need to quote your
-    request.  For example, the same search above with quotes is:
-    <code>"jpaint", "gstein"</code>.
-  </p>
-  <p>                           
-    Wildcard and regular expression searches are entered in a similar
-    way to the quoted requests.  You must quote any wildcard or
-    regular expression request, and a command character preceeds the
-    first quote.  The command character <code>l</code>(lowercase L) is for wildcard
-    searches, and the wildcard character is a percent (<code>%</code>).  The
-    command character for regular expressions is <code>r</code>, and is
-    passed directly to MySQL, so you'll need to refer to the MySQL
-    manual for the exact regex syntax.  It is very similar to Perl.  A
-    wildard search for all files with a <em>.py</em> extention is:
-    <code>l"%.py"</code> in the <em>File</em> input box.  The same search done
-    with a regular expression is: <code>r".*\.py"</code>.
-  </p>
-  <p>                  
-    All search types can be mixed, as long as they are seperated by
-    commas.
-  </p>                                                    
-  </td></tr></table>
-</body></html>
+  <div><a href="http://viewvc.org/index.html";><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
+  <table>
+    <col class="menu" />
+    <col />
+    <tr><td>
+       <h3>Help:</h3>
+       <a href="help_rootview.html">General</a><br />
+       <a href="help_dirview.html">Directory&nbsp;View</a><br />
+       <a href="help_log.html">Log&nbsp;View</a><br />
+       <strong>Query&nbsp;Database</strong>
+    </td><td>
+  
+    <h1>ViewVC Help: Query The Commit Database</h1>
+  
+    <p> 
+      Select your parameters for querying the CVS commit database in the
+      form at the top of the page.  You
+      can search for multiple matches by typing a comma-seperated list
+      into the text fields.  Regular expressions, and wildcards are also
+      supported.  Blank text input fields are treated as wildcards.
+    </p>
+    <p>
+      Any of the text entry fields can take a comma-seperated list of
+      search arguments.  For example, to search for all commits from
+      authors <em>jpaint</em> and <em>gstein</em>, just type: <code>jpaint,
+      gstein</code> in the <em>Author</em> input box.  If you are searching
+      for items containing spaces or quotes, you will need to quote your
+      request.  For example, the same search above with quotes is:
+      <code>"jpaint", "gstein"</code>.
+    </p>
+    <p>                           
+      Wildcard and regular expression searches are entered in a similar
+      way to the quoted requests.  You must quote any wildcard or
+      regular expression request, and a command character preceeds the
+      first quote.  The command character <code>l</code>(lowercase L) is for wildcard
+      searches, and the wildcard character is a percent (<code>%</code>).  The
+      command character for regular expressions is <code>r</code>, and is
+      passed directly to MySQL, so you'll need to refer to the MySQL
+      manual for the exact regex syntax.  It is very similar to Perl.  A
+      wildard search for all files with a <em>.py</em> extention is:
+      <code>l"%.py"</code> in the <em>File</em> input box.  The same search done
+      with a regular expression is: <code>r".*\.py"</code>.
+    </p>
+    <p>                  
+      All search types can be mixed, as long as they are seperated by
+      commas.
+    </p>                                                    
+    </td></tr></table>
+  <hr />
+  <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>
+  </body>
+</html>

Modified: branches/VIEWCVS_DIST/templates/docroot/help_rootview.html
==============================================================================
--- branches/VIEWCVS_DIST/templates/docroot/help_rootview.html	(original)
+++ branches/VIEWCVS_DIST/templates/docroot/help_rootview.html	Mon Nov  3 09:44:02 2008
@@ -4,164 +4,152 @@
 <head>
   <title>ViewVC Help: General</title>
   <link rel="stylesheet" href="help.css" type="text/css" />
+  <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 </head>
 <body>
+  <div><a href="http://viewvc.org/index.html";><img src="images/viewvc-logo.png" alt="ViewVC logotype" /></a></div>
   <table>
     <col class="menu" />
     <col />
-    <tr>
-      <td><a href=".."><img
-	     src="images/logo.png" alt="ViewVC logotype" /></a>
-      </td>
-      <td>
-	<h1>ViewVC Help: General</h1>
-      </td>
-    </tr>
     <tr><td>
        <h3>Help</h3>
        <strong>General</strong><br />
        <a href="help_dirview.html">Directory&nbsp;View</a><br />
        <a href="help_log.html">Log&nbsp;View</a><br />
+       <a href="help_query.html">Query&nbsp;Database</a><br />
+    </td><td>
 
-       <h3>Internet</h3>
-       <a href="http://viewvc.org/index.html";>Home</a><br />
-       <a href="http://viewvc.org/upgrading.html";>Upgrading</a><br />
-       <a href="http://viewvc.org/contributing.html";>Contributing</a><br />
-       <a href="http://viewvc.org/license-1.html";>License</a><br />
-    </td><td colspan="2">
-
-  <p><em>ViewVC</em> is a WWW interface for CVS and Subversion
-  repositories. It allows you to browse the files and directories in a
-  repository while showing you metadata from the repository history: log
-  messages, modification dates, author names, revision numbers, copy
-  history, and so on. It provides several different views of repository
-  data to help you find the information you are looking for:</p>
-
-  <ul>
-    <li><a name="view-dir" href="help_dirview.html"><strong>Directory
-    View</strong></a> - Shows a list of files and subdirectories in a
-    directory of the repository, along with metadata like author names and
-    log entries.</li>
-
-    <li><a name="view-log" href="help_log.html"><strong>Log
-    View</strong></a> - Shows a revision by revision list of all the
-    changes that have made to a file or directory in the repository, with
-    metadata and links to views of each revision.</li>
-
-    <li><a name="view-markup"><strong>File Contents View (Markup
-    View)</strong></a> - Shows the contents of a file at a particular
-    revision, with revision information at the top of the page. File
-    revisions which are GIF, PNG, or JPEG images are displayed inline on
-    the page. Other file types are displayed as marked up text. The markup
-    may be limited to turning URLs and email addresses into links, or
-    configured to show colorized source code.</li>
-
-    <li><a name="view-checkout"><strong>File Download (Checkout
-    View)</strong></a> - Retrieves the unaltered contents of a file
-    revision. Browsers may try to display the file, or just save it to
-    disk.</li>
-
-    <li><a name="view-annotate"><strong>File Annotate View</strong></a> -
-    Shows the contents of a file revision and breaks it down line by line,
-    showing the revision number where each one was last modified, along
-    with links and other information. <em>This view is disabled in some
-    ViewVC configurations</em></li>
-
-    <li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
-    the changes made between two revisions of a file</li>
-
-    <li><a name="view-tarball"><strong>Directory Tarball View</strong> -
-    Retrieves a gzipped tar archive containing the contents of a
-    directory.<em>This view is disabled in the default ViewVC
-    configuration.</em></li>
-
-    <li><a name="view-query"><strong>Directory Query View</strong></a> -
-    Shows information about changes made to all subdirectories and files
-    under a parent directory, sorted and filtered by criteria you specify.
-    <em>This view is disabled in the default ViewVC configuration.</em>
-    </li>
-
-    <li><a name="view-rev"><strong>Revision View</strong> - Shows
-    information about a revision including log message, author, and a list
-    of changed paths. <em>For Subversion repositories only.</em></li>
-
-    <li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
-    graphical representation of a file's revisions and branches complete
-    with tag and author names and links to markup and diff pages.
-    <em>For CVS repositories only, and disabled in the default
-    configuration.</em></li>
-  </ul>
-
-  <h3><a name="multiple-repositories">Multiple Repositories</a></h3>
-
-  <p>A single installation of ViewVC is often used to provide access to
-  more than one repository. In these installations, ViewVC shows a
-  <em>Project Root</em> drop down box in the top right corner of every
-  generated page to allow for quick access to any repository.</p>
-
-  <h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
-
-  <p>By default, ViewVC will show the files and directories and revisions
-  that currently exist in the repository. But it's also possible to browse
-  the contents of a repository at a point in its past history by choosing
-  a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
-  forms at the top of directory and log pages. They're called sticky
-  because once they're chosen, they stick around when you navigate to
-  other pages, until you reset them. When they're set, directory and log
-  pages only show revisions preceding the specified point in history. In
-  CVS, when a tag refers to a branch or a revision on a branch, only
-  revisions from the branch history are shown, including branch points and
-  their preceding revisions.</p>
-
-  <h3><a name="dead-files">Dead Files</a></h3>
-
-  <p>In CVS directory listings, ViewVC can optionally display dead files.
-  Dead files are files which used to be in a directory but are currently
-  deleted, or files which just don't exist in the currently selected
-  <a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
-  shown in Subversion repositories. The only way to see a deleted file in
-  a Subversion directory is to navigate to a sticky revision where the
-  file previously existed.</p>
-
-  <h3><a name="artificial-tags">Artificial Tags</a></h3>
-
-  <p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
-  <em>MAIN</em> to tag listings and accepts them in place of revision
-  numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
-  tag pointing at the default branch, while <em>HEAD</em> acts like a
-  revision tag pointing to the latest revision on the default branch. The
-  default branch is usually just the trunk, but may be set to other
-  branches inside individual repository files. CVS will always check out
-  revisions from a file's default branch when no other branch is specified
-  on the command line.</p>
-
-  <h3><a name="more-information">More Information</a></h3>
-
-  <p>More information about <em>ViewVC</em> is available from
-  <a href="http://viewvc.org/";>viewvc.org</a>.
-  See the links below for guides to CVS and Subversion</p>
-
-  <h4>Documentation about CVS</h4>
-  <blockquote>
-    <p>
-      <a href="http://cvsbook.red-bean.com/";><em>Open Source
-      Development with CVS</em></a><br />
-      <a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html";>CVS
-      User's Guide</a><br />
-      <a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html";>Another CVS tutorial</a><br />
-      <a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/";>Yet another CVS tutorial (a little old, but nice)</a><br />
-      <a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt";>An old but very useful FAQ about CVS</a>
-    </p>
-  </blockquote>
-
-  <h4>Documentation about Subversion</h3>
-  <blockquote>
-    <p>
-      <a href="http://svnbook.red-bean.com/";><em>Version Control with
-      Subversion</em></a><br />
-    </p>
-  </blockquote>
+    <h1>ViewVC Help: General</h1>
 
+    <p><em>ViewVC</em> is a WWW interface for CVS and Subversion
+    repositories. It allows you to browse the files and directories in a
+    repository while showing you metadata from the repository history: log
+    messages, modification dates, author names, revision numbers, copy
+    history, and so on. It provides several different views of repository
+    data to help you find the information you are looking for:</p>
+  
+    <ul>
+      <li><a name="multiple-repositories"><strong>Root Listing
+      View</strong></a> - Show a list of repositories configured for
+      display in ViewVC.</li>
+  
+      <li><a name="view-dir" href="help_dirview.html"><strong>Directory
+      View</strong></a> - Shows a list of files and subdirectories in a
+      directory of the repository, along with metadata like author names and
+      log entries.</li>
+  
+      <li><a name="view-log" href="help_log.html"><strong>Log
+      View</strong></a> - Shows a revision by revision list of all the
+      changes that have made to a file or directory in the repository, with
+      metadata and links to views of each revision.</li>
+  
+      <li><a name="view-checkout"><strong>File Download (Checkout
+      View)</strong></a> - Retrieves the unaltered contents of a file
+      revision. Browsers may try to display the file, or just save it
+      to disk.  <em>This view is disabled in the default ViewVC
+      configuration.</em></li>
+  
+      <li><a name="view-annotate"><a name="view-markup"><strong>File
+      Contents View</strong></a></a> - Shows the contents of a file at
+      a particular revision, with revision information at the top of
+      the page. File revisions which are GIF, PNG, or JPEG images are
+      displayed inline on the page. Other file types are displayed as
+      marked up text. The markup may be limited to turning URLs and
+      email addresses into links, or configured to show colorized
+      source code.  This view can optionally show line-based
+      annotation data for the file, containing the revision number
+      where each line was last modified, along with links and other
+      information.  <em>This view is disabled in some ViewVC
+      configurations.</em></li>
+  
+      <li><a name="view-diff"><strong>File Diff View</strong></a> - Shows
+      the changes made between two revisions of a file</li>
+  
+      <li><a name="view-tarball"><strong>Directory Tarball View</strong> -
+      Retrieves a gzipped tar archive containing the contents of a
+      directory.<em>This view is disabled in the default ViewVC
+      configuration.</em></li>
+  
+      <li><a name="view-query"><strong>Directory Query View</strong></a> -
+      Shows information about changes made to all subdirectories and files
+      under a parent directory, sorted and filtered by criteria you specify.
+      <em>This view is disabled in the default ViewVC configuration.</em>
+      </li>
+  
+      <li><a name="view-rev"><strong>Revision View</strong> - Shows
+      information about a revision including log message, author, and a list
+      of changed paths. <em>For Subversion repositories only.</em></li>
+  
+      <li><a name="view-graph"><strong>Graph View</strong></a> - Shows a
+      graphical representation of a file's revisions and branches complete
+      with tag and author names and links to markup and diff pages.
+      <em>For CVS repositories only, and disabled in the default
+      configuration.</em></li>
+    </ul>
+  
+    <h3><a name="sticky-revision-tag">Sticky Revision and Tag</a></h3>
+  
+    <p>By default, ViewVC will show the files and directories and revisions
+    that currently exist in the repository. But it's also possible to browse
+    the contents of a repository at a point in its past history by choosing
+    a "sticky tag" (in CVS) or a "sticky revision" (in Subversion) from the
+    forms at the top of directory and log pages. They're called sticky
+    because once they're chosen, they stick around when you navigate to
+    other pages, until you reset them. When they're set, directory and log
+    pages only show revisions preceding the specified point in history. In
+    CVS, when a tag refers to a branch or a revision on a branch, only
+    revisions from the branch history are shown, including branch points and
+    their preceding revisions.</p>
+  
+    <h3><a name="dead-files">Dead Files</a></h3>
+  
+    <p>In CVS directory listings, ViewVC can optionally display dead files.
+    Dead files are files which used to be in a directory but are currently
+    deleted, or files which just don't exist in the currently selected
+    <a href="#sticky-revision-tag">sticky tag</a>. Dead files cannot be
+    shown in Subversion repositories. The only way to see a deleted file in
+    a Subversion directory is to navigate to a sticky revision where the
+    file previously existed.</p>
+  
+    <h3><a name="artificial-tags">Artificial Tags</a></h3>
+  
+    <p>In CVS Repositories, ViewVC adds artificial tags <em>HEAD</em> and
+    <em>MAIN</em> to tag listings and accepts them in place of revision
+    numbers and real tag names in all URLs. <em>MAIN</em> acts like a branch
+    tag pointing at the default branch, while <em>HEAD</em> acts like a
+    revision tag pointing to the latest revision on the default branch. The
+    default branch is usually just the trunk, but may be set to other
+    branches inside individual repository files. CVS will always check out
+    revisions from a file's default branch when no other branch is specified
+    on the command line.</p>
+  
+    <h3><a name="more-information">More Information</a></h3>
+  
+    <p>More information about <em>ViewVC</em> is available from
+    <a href="http://viewvc.org/";>viewvc.org</a>.
+    See the links below for guides to CVS and Subversion</p>
+  
+    <h4>Documentation about CVS</h4>
+    <blockquote>
+      <p>
+        <a href="http://cvsbook.red-bean.com/";><em>Open Source
+        Development with CVS</em></a><br />
+        <a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html";>CVS
+        User's Guide</a><br />
+        <a href="http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html";>Another CVS tutorial</a><br />
+        <a href="http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/";>Yet another CVS tutorial (a little old, but nice)</a><br />
+        <a href="http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt";>An old but very useful FAQ about CVS</a>
+      </p>
+    </blockquote>
+  
+    <h4>Documentation about Subversion</h3>
+    <blockquote>
+      <p>
+        <a href="http://svnbook.red-bean.com/";><em>Version Control with
+        Subversion</em></a><br />
+      </p>
+    </blockquote>
   </td></tr></table>
   <hr />
   <address><a href="mailto:users viewvc tigris org">ViewVC Users Mailinglist</a></address>

Added: branches/VIEWCVS_DIST/templates/docroot/images/favicon.ico
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates/docroot/images/lock.png
==============================================================================
Binary file. No diff available.

Added: branches/VIEWCVS_DIST/templates/docroot/images/viewvc-logo.png
==============================================================================
Binary file. No diff available.

Modified: branches/VIEWCVS_DIST/templates/docroot/styles.css
==============================================================================
--- branches/VIEWCVS_DIST/templates/docroot/styles.css	(original)
+++ branches/VIEWCVS_DIST/templates/docroot/styles.css	Mon Nov  3 09:44:02 2008
@@ -6,6 +6,7 @@
 html, body {
   color: #000000;
   background-color: #ffffff;
+  font-family: sans-serif;
 }
 
 a:link    { color: #0000ff; }
@@ -31,8 +32,10 @@
   white-space: nowrap;
 }
 tr, td, th { vertical-align: top; }
+th { white-space: nowrap; }
 form { margin: 0; }
 
+
 /*** Icons ***/
 .vc_icon {
   width: 16px;
@@ -45,6 +48,10 @@
 /*** Navigation Headers ***/
 .vc_navheader {
   background-color: #cccccc;
+  padding: .25em;
+}
+.vc_navheader .pathdiv {
+  padding: 0 3px;
 }
 
 
@@ -65,7 +72,7 @@
   background-color: #ffffff;
 }
 .vc_row_odd {
-  background-color: #ccccee;
+  background-color: #f0f0f0;
 }
 .vc_row_special {
   background-color: #ffff7f;
@@ -83,45 +90,105 @@
 }
 
 
-/*** Markup Summary Header ***/
-.vc_summary {
-  background-color: #eeeeee;
+/*** Properties Listing ***/
+.vc_properties {
+  margin: 1em 0;
+}
+.vc_properties h2 {
+  font-size: 115%;
 }
 
-/*** Highlight Markup Styles ***/
-#vc_markup .num  { color: #000000; }
-#vc_markup .esc  { color: #bd8d8b; }
-#vc_markup .str  { color: #bd8d8b; }
-#vc_markup .dstr { color: #bd8d8b; }
-#vc_markup .slc  { color: #ac2020; font-style: italic; }
-#vc_markup .com  { color: #ac2020; font-style: italic; }
-#vc_markup .dir  { color: #000000; }
-#vc_markup .sym  { color: #000000; }
-#vc_markup .line { color: #555555; }
-#vc_markup .kwa  { color: #9c20ee; font-weight: bold; }
-#vc_markup .kwb  { color: #208920; }
-#vc_markup .kwc  { color: #0000ff; }
-#vc_markup .kwd  { color: #404040; }
-
-/*** Py2html Markup Styles  ***/
-#vc_markup .PY_STRING     { color: #bd8d8b; }
-#vc_markup .PY_COMMENT    { color: #ac2020; font-style: italic; }
-#vc_markup .PY_KEYWORD    { color: #9c20ee; font-weight: bold; }
-#vc_markup .PY_IDENTIFIER { color: #404040; }
 
-/*** Line numbers outputted by highlight colorizer ***/
-.line {
-  border-right-width: 1px;
+/*** File Content Markup Styles ***/
+.vc_summary {
+  background-color: #eeeeee;
+}
+#vc_file td {
   border-right-style: solid;
   border-right-color: #505050;
-  padding: 1px;
-  background-color: #eeeeee;
-  color: #505050;
   text-decoration: none;
   font-weight: normal;
   font-style: normal;
+  padding: 1px 5px;
+}
+.vc_file_line_number {
+  border-right-width: 1px;
+  background-color: #eeeeee;
+  color: #505050;
+  text-align: right;
+}
+.vc_file_line_author, .vc_file_line_rev {
+  border-right-width: 1px;
   text-align: right;
 }
+.vc_file_line_text {
+  border-right-width: 0px;
+  background-color: white;
+  font-family: monospace;
+  text-align: left;
+  white-space: pre;
+  width: 100%;
+}
+.pygments-c { color: #408080; font-style: italic } /* Comment */
+.pygments-err { border: 1px solid #FF0000 } /* Error */
+.pygments-k { color: #008000; font-weight: bold } /* Keyword */
+.pygments-o { color: #666666 } /* Operator */
+.pygments-cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.pygments-cp { color: #BC7A00 } /* Comment.Preproc */
+.pygments-c1 { color: #408080; font-style: italic } /* Comment.Single */
+.pygments-cs { color: #408080; font-style: italic } /* Comment.Special */
+.pygments-gd { color: #A00000 } /* Generic.Deleted */
+.pygments-ge { font-style: italic } /* Generic.Emph */
+.pygments-gr { color: #FF0000 } /* Generic.Error */
+.pygments-gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.pygments-gi { color: #00A000 } /* Generic.Inserted */
+.pygments-go { color: #808080 } /* Generic.Output */
+.pygments-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.pygments-gs { font-weight: bold } /* Generic.Strong */
+.pygments-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.pygments-gt { color: #0040D0 } /* Generic.Traceback */
+.pygments-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.pygments-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.pygments-kp { color: #008000 } /* Keyword.Pseudo */
+.pygments-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.pygments-kt { color: #B00040 } /* Keyword.Type */
+.pygments-m { color: #666666 } /* Literal.Number */
+.pygments-s { color: #BA2121 } /* Literal.String */
+.pygments-na { color: #7D9029 } /* Name.Attribute */
+.pygments-nb { color: #008000 } /* Name.Builtin */
+.pygments-nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.pygments-no { color: #880000 } /* Name.Constant */
+.pygments-nd { color: #AA22FF } /* Name.Decorator */
+.pygments-ni { color: #999999; font-weight: bold } /* Name.Entity */
+.pygments-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.pygments-nf { color: #0000FF } /* Name.Function */
+.pygments-nl { color: #A0A000 } /* Name.Label */
+.pygments-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.pygments-nt { color: #008000; font-weight: bold } /* Name.Tag */
+.pygments-nv { color: #19177C } /* Name.Variable */
+.pygments-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.pygments-w { color: #bbbbbb } /* Text.Whitespace */
+.pygments-mf { color: #666666 } /* Literal.Number.Float */
+.pygments-mh { color: #666666 } /* Literal.Number.Hex */
+.pygments-mi { color: #666666 } /* Literal.Number.Integer */
+.pygments-mo { color: #666666 } /* Literal.Number.Oct */
+.pygments-sb { color: #BA2121 } /* Literal.String.Backtick */
+.pygments-sc { color: #BA2121 } /* Literal.String.Char */
+.pygments-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.pygments-s2 { color: #BA2121 } /* Literal.String.Double */
+.pygments-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.pygments-sh { color: #BA2121 } /* Literal.String.Heredoc */
+.pygments-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.pygments-sx { color: #008000 } /* Literal.String.Other */
+.pygments-sr { color: #BB6688 } /* Literal.String.Regex */
+.pygments-s1 { color: #BA2121 } /* Literal.String.Single */
+.pygments-ss { color: #19177C } /* Literal.String.Symbol */
+.pygments-bp { color: #008000 } /* Name.Builtin.Pseudo */
+.pygments-vc { color: #19177C } /* Name.Variable.Class */
+.pygments-vg { color: #19177C } /* Name.Variable.Global */
+.pygments-vi { color: #19177C } /* Name.Variable.Instance */
+.pygments-il { color: #666666 } /* Literal.Number.Integer.Long */
+
 
 /*** Diff Styles ***/
 .vc_diff_header {
@@ -167,8 +234,8 @@
   font-size: smaller;
 }
 
-/*** Intraline Diff Styles ***/
 
+/*** Intraline Diff Styles ***/
 .vc_idiff_add {
   background-color: #aaffaa;
 }
@@ -181,7 +248,6 @@
 .vc_idiff_empty {
   background-color:#e0e0e0;
 }
-
 table.vc_idiff col.content { 
   width: 50%;
 }
@@ -199,33 +265,6 @@
   text-align:right;
 }
 
-/*** Annotate Styles ***/
-#vc_blame td {
-  border-right-width: 1px;
-  border-right-style: solid;
-  border-right-color: #505050;
-  text-decoration: none;
-  font-weight: normal;
-  font-style: normal;
-}
-.vc_blame_line {
-  background-color: #eeeeee;
-  color: #505050;
-  padding: 1px 1px;
-}
-.vc_blame_author, .vc_blame_rev, .vc_blame_line {
-  text-align: right;
-}
-.vc_blame_rev, .vc_blame_line {
-  padding: 1px 5px;
-}
-.vc_blame_text {
-  font-family: monospace;
-  font-size: smaller;
-  text-align: left;
-  white-space: pre;
-  width: 100%;
-}
 
 /*** Query Form ***/
 .vc_query_form {

Added: branches/VIEWCVS_DIST/templates/file.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates/file.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,106 @@
+[# setup page definitions]
+  [define page_title]Annotate of /[where][end]
+  [define help_href][docroot]/help_rootview.html[end]
+[# end]
+
+[include "include/header.ezt" "markup"]
+[include "include/file_header.ezt"]
+<hr />
+<div class="vc_summary">
+Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong></a>[else]<strong>[rev]</strong>[end] -
+([if-any annotation][is annotation "annotated"]<a href="[view_href]"><strong>hide annotations</strong></a>[end][else]<a href="[annotate_href]"><strong>show annotations</strong></a>[end])
+[if-any download_href](<a href="[download_href]"><strong>download</strong></a>)[end]
+[if-any download_text_href](<a href="[download_text_href]"><strong>as text</strong></a>)[end]
+
+[if-any vendor_branch] <em>(vendor branch)</em>[end]
+<br /><em>[if-any date][date][else](unknown date)[end]</em>
+      [if-any ago]([ago] ago)[end]
+      by <em>[if-any author][author][else](unknown author)[end]</em>
+[if-any orig_path]
+  <br />Original Path: <a href="[orig_href]"><em>[orig_path]</em></a>
+[end]
+
+[if-any branches]
+  <br />Branch: <strong>[branches]</strong>
+[end]
+[if-any tags]
+  <br />CVS Tags: <strong>[tags]</strong>
+[end]
+[if-any branch_points]
+  <br />Branch point for: <strong>[branch_points]</strong>
+[end]
+[is roottype "cvs"]
+  [if-any changed]
+    <br />Changes since <strong>[prev]: [changed] lines</strong>
+  [end]
+[end]
+[if-any mime_type]
+  <br />File MIME type: [mime_type]
+[end]
+[is roottype "svn"][if-any size]
+  <br />File size: [size] byte(s)
+[end][end]
+[if-any lockinfo]
+  <br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]
+[end]
+[if-any annotation]
+[is annotation "binary"]
+  <br /><strong>Unable to calculate annotation data on binary file contents.</strong>
+[end]
+[is annotation "error"]
+  <br /><strong>Error occurred while calculating annotation data.</strong>
+[end]
+[end]
+[is state "dead"]
+  <br /><strong><em>FILE REMOVED</em></strong>
+[end]
+[if-any log]
+  <pre class="vc_log">[log]</pre>
+[end]
+</div>
+
+
+[define last_rev]0[end]
+[define rowclass]vc_row_even[end]
+
+[if-any lines]
+
+<div id="vc_file">
+<table cellspacing="0" cellpadding="0">
+[for lines]
+  [is lines.rev last_rev]
+  [else]
+    [is lines.rev rev]
+      [define rowclass]vc_row_special[end]
+    [else]
+      [is rowclass "vc_row_even"]
+        [define rowclass]vc_row_odd[end]
+      [else]
+        [define rowclass]vc_row_even[end]
+      [end]
+    [end]
+  [end]
+
+  <tr class="[rowclass]" id="l[lines.line_number]">
+    <td class="vc_file_line_number">[lines.line_number]</td>
+[is annotation "annotated"]
+    <td class="vc_file_line_author">[is lines.rev last_rev]&nbsp;[else][lines.author][end]</td>
+    <td class="vc_file_line_rev">[is lines.rev last_rev]&nbsp;[else][if-any lines.diff_href]<a href="[lines.diff_href]">[end][lines.rev][if-any lines.diff_href]</a>[end][end]</td>
+[end]
+    <td class="vc_file_line_text">[lines.text]</td>
+  </tr>
+  [define last_rev][lines.rev][end]
+[end]
+</table>
+</div>
+
+[else]
+[if-any image_src_href]
+<div id="vc_file_image">
+<img src="[image_src_href]" alt="" />
+</div>
+[end]
+[end]
+
+[include "include/props.ezt"]
+[include "include/footer.ezt"]

Modified: branches/VIEWCVS_DIST/templates/include/diff_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/diff_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/diff_form.ezt	Mon Nov  3 09:44:02 2008
@@ -15,7 +15,7 @@
   <tr>
   <td>&nbsp;</td>
   <td>
-  [diff_select_hidden_values]
+  [for diff_select_hidden_values]<input type="hidden" name="[diff_select_hidden_values.name]" value="[diff_select_hidden_values.value]"/>[end]
   Diffs between
 [if-any tags]
   <select name="r1">

Modified: branches/VIEWCVS_DIST/templates/include/dir_footer.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/dir_footer.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/dir_footer.ezt	Mon Nov  3 09:44:02 2008
@@ -1,38 +1,9 @@
-[if-any search_re_form]
-  <hr />
-  [# this table holds the selectors on the left, and reset on the right ]
-  <table class="auto">
-        <tr>
-          <td>Show files containing the regular expression:</td>
-          <td>
-            <form method="get" action="[search_re_action]">
-              <div>
-                [search_re_hidden_values]
-                <input type="text" name="search" value="[search_re]" />
-                <input type="submit" value="Show" />
-              </div>
-            </form>
-          </td>
-        </tr>
-      [if-any search_re]
-        <tr>
-          <td>&nbsp;</td>
-          <td>
-            <form method="get" action="[search_tag_action]">
-              <div>
-                [search_tag_hidden_values]
-                <input type="submit" value="Show all files" />
-              </div>
-            </form>
-          </td>
-        </tr>
-    [end]
-  </table>
-[end]
-
 [# if you want to disable tarball generation remove the following: ]
 [if-any tarball_href]
-  <p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
+<hr/>
+<p style="margin:0;"><a href="[tarball_href]">Download GNU tarball</a></p>
 [end]
 
+[include "props.ezt"]
 [include "footer.ezt"]
+

Modified: branches/VIEWCVS_DIST/templates/include/dir_header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/dir_header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/dir_header.ezt	Mon Nov  3 09:44:02 2008
@@ -31,8 +31,27 @@
   <td>Sticky [is roottype "cvs"]Tag[else]Revision[end]:</td>
   <td>[include "pathrev_form.ezt"]</td>
 </tr>
-[if-any search_re]
-<tr><td>Current search:</td><td><strong>[search_re]</strong></td></tr>
+
+[if-any search_re_form]
+<tr>
+  <td>Filter files by content:</td>
+  <td><form method="get" action="[search_re_action]" style="display: inline;">
+      <div style="display: inline;">
+      [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+      <input type="text" name="search" value="[search_re]" />
+      <input type="submit" value="Search Regexp" />
+      </div>
+     </form>
+     [if-any search_re]
+     <form method="get" action="[search_re_action]" style="display: inline;">
+     <div style="display: inline;">
+     [for search_re_hidden_values]<input type="hidden" name="[search_re_hidden_values.name]" value="[search_re_hidden_values.value]"/>[end]
+     <input type="submit" value="Show All Files" />
+     </div>
+     </form>
+     [end]
+  </td>
+</tr>
 [end]
 
 [if-any queryform_href]
@@ -41,24 +60,25 @@
   <td><a href="[queryform_href]">Query revision history</a></td>
 </tr>
 [end]
+
 </table>
-  [is cfg.options.use_pagesize "0"]
+
+[is cfg.options.use_pagesize "0"]
+[else]
+  [is picklist_len "1"]
   [else]
-    [is picklist_len "1"]
-    [else]
-      <form method="get" action="[dir_paging_action]">
-        [dir_paging_hidden_values]
-        <input type="submit" value="Go to:" />
-        <select name="dir_pagestart"  onchange="submit()">
-          [for picklist]
-            <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
-          [end]
-        </select>
-      </form>
-    [end]
+    <form method="get" action="[dir_paging_action]">
+      [for dir_paging_hidden_values]<input type="hidden" name="[dir_paging_hidden_values.name]" value="[dir_paging_hidden_values.value]"/>[end]
+      <input type="submit" value="Go to:" />
+      <select name="dir_pagestart"  onchange="submit()">
+        [for picklist]
+          <option [is picklist.count dir_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] to [picklist.end]</option>
+        [end]
+      </select>
+    </form>
   [end]
+[end]
 
 <p><a name="dirlist"></a></p>
-
 <hr />
 

Modified: branches/VIEWCVS_DIST/templates/include/header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/header.ezt	Mon Nov  3 09:44:02 2008
@@ -5,71 +5,19 @@
 <head>
   <title>[if-any rootname][[][rootname]][else]ViewVC[end] [page_title]</title>
   <meta name="generator" content="ViewVC [vsn]" />
+  <link rel="shortcut icon" href="[docroot]/images/favicon.ico" type="image/x-icon" />
   <link rel="stylesheet" href="[docroot]/styles.css" type="text/css" />
   [if-any rss_href]<link rel="alternate" type="application/rss+xml" title="RSS [[][rootname]][where]" href="[rss_href]" />[end]
 </head>
 <body>
 <div class="vc_navheader">
-[if-any roots]
-  <form method="get" action="[change_root_action]">
-[end]
-<table style="padding:0.1em;">
-<tr>
-  <td>
-  [if-any nav_path]<strong>
-    [for nav_path]
-      [if-any nav_path.href]<a href="[nav_path.href]">[end]
-      [if-index nav_path first]
-        [[][nav_path.name]][else]
-        [nav_path.name][end][if-any nav_path.href]</a>[end]
-      [if-index nav_path last][else]/[end]
-    [end]
-    </strong>
-  [end]
-  </td>
-  <td style="text-align:right;">
-  [if-any roots]
-    [change_root_hidden_values]
-      <strong>Repository:</strong>
-      <select name="root" onchange="submit()">
-        [define cvs_root_options][end]
-        [define svn_root_options][end]
-        <option value="*viewroots*"[is view "roots"] selected="selected"[else][end]>Repository Listing</option>
-        [for roots]
-          [define root_option][end]
-          [is roots.name rootname]
-            [define root_option]<option selected="selected">[roots.name]</option>[end]
-          [else]
-            [define root_option]<option>[roots.name]</option>[end]
-          [end]
-          [is roots.type "cvs"]
-            [define cvs_root_options][cvs_root_options][root_option][end]
-          [else]
-            [is roots.type "svn"]
-              [define svn_root_options][svn_root_options][root_option][end]
-            [end]
-          [end]
-        [end]
-        [is cvs_root_options ""][else]
-          <optgroup label="CVS Repositories">[cvs_root_options]</optgroup>
-        [end]
-        [is svn_root_options ""][else]
-          <optgroup label="Subversion Repositories">[svn_root_options]</optgroup>
-        [end]
-      </select>
-      <input type="submit" value="Go" />
-  [else]
-    &nbsp;
-  [end]
-  </td>
-</tr>
-</table>
-[if-any roots]
-</form>
-[end]
+<table><tr>
+<td><strong>[if-any roots_href]<a href="[roots_href]"><span class="pathdiv">/</span></a>[else]<span class="pathdiv">/</span>[end][if-any nav_path][for nav_path][if-any nav_path.href]<a href="[nav_path.href]">[end][if-index nav_path first][[][nav_path.name]][else][nav_path.name][end][if-any nav_path.href]</a>[end][if-index nav_path last][else]<span class="pathdiv">/</span>[end][end][end]</strong></td>
+<td style="text-align: right;">[if-any username]Logged in as: <strong>[username]</strong>[end]</td>
+</tr></table>
 </div>
 
-<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/"; title="ViewVC Home"><img src="[docroot]/images/logo.png" alt="ViewVC logotype" width="128" height="48" /></a></div>
+<div style="float: right; padding: 5px;"><a href="http://www.viewvc.org/"; title="ViewVC Home"><img src="[docroot]/images/viewvc-logo.png" alt="ViewVC logotype" width="240" height="70" /></a></div>
 <h1>[page_title]</h1>
 
 

Modified: branches/VIEWCVS_DIST/templates/include/log_header.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/log_header.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/log_header.ezt	Mon Nov  3 09:44:02 2008
@@ -19,14 +19,14 @@
 [end]
 
 [is pathtype "file"]
-[if-any view_href]
+[if-any head_view_href]
 <tr>
   <td>Links to HEAD:</td>
   <td>
-    (<a href="[view_href]">view</a>)
-    [if-any download_href](<a href="[download_href]">download</a>)[end]
-    [if-any download_text_href](<a href="[download_text_href]">as text</a>)[end]
-    [if-any annotate_href](<a href="[annotate_href]">annotate</a>)[end]
+    (<a href="[head_view_href]">view</a>)
+    [if-any head_download_href](<a href="[head_download_href]">download</a>)[end]
+    [if-any head_download_text_href](<a href="[head_download_text_href]">as text</a>)[end]
+    [if-any head_annotate_href](<a href="[head_annotate_href]">annotate</a>)[end]
   </td>
 </tr>
 [end]

Modified: branches/VIEWCVS_DIST/templates/include/paging.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/paging.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/paging.ezt	Mon Nov  3 09:44:02 2008
@@ -4,11 +4,15 @@
     [else]
       <hr />
       <form method="get" action="[log_paging_action]">
-        [log_paging_hidden_values]
+        [for log_paging_hidden_values]<input type="hidden" name="[log_paging_hidden_values.name]" value="[log_paging_hidden_values.value]"/>[end]
         <input type="submit" value="Go to:">
         <select name="log_pagestart"  onchange="submit()">
           [for picklist]
+           [if-any picklist.more]
+            <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] ...</option>
+           [else]
             <option [is picklist.count log_pagestart]selected[end] value="[picklist.count]">Page [picklist.page]: [picklist.start] - [picklist.end]</option>
+           [end]
           [end]
         </select>
       </form>

Modified: branches/VIEWCVS_DIST/templates/include/pathrev_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/pathrev_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/pathrev_form.ezt	Mon Nov  3 09:44:02 2008
@@ -1,6 +1,6 @@
 <form method="get" action="[pathrev_action]" style="display: inline">
 <div style="display: inline">
-[pathrev_hidden_values]
+[for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
 [is roottype "cvs"]
   [define pathrev_selected][pathrev][end]
   <select name="pathrev" onchange="submit()">
@@ -41,7 +41,7 @@
 [if-any pathrev]
 <form method="get" action="[pathrev_clear_action]" style="display: inline">
 <div style="display: inline">
-[pathrev_clear_hidden_values]
+[for pathrev_clear_hidden_values]<input type="hidden" name="[pathrev_clear_hidden_values.name]" value="[pathrev_clear_hidden_values.value]"/>[end]
 [if-any lastrev]
   [is pathrev lastrev][else]<input type="submit" value="Set to [lastrev]" />[end]
   (<i>Current path doesn't exist after revision <strong>[lastrev]</strong></i>)

Added: branches/VIEWCVS_DIST/templates/include/props.ezt
==============================================================================
--- (empty file)
+++ branches/VIEWCVS_DIST/templates/include/props.ezt	Mon Nov  3 09:44:02 2008
@@ -0,0 +1,26 @@
+[if-any properties]
+<hr/>
+<div class="vc_properties">
+<h2>Properties</h2>
+<table cellspacing="1" cellpadding="2" class="auto">
+<thead>
+  <tr>
+    <th class="vc_header_sort">Name</th>
+    <th class="vc_header">Value</th>
+  </tr>
+</thead>
+<tbody>
+[for properties]
+  <tr class="vc_row_[if-index properties even]even[else]odd[end]">
+    <td><strong>[properties.name]</strong></td>
+    [if-any properties.undisplayable]
+    <td><em>Property value is undisplayable.</em></td>
+    [else]
+    <td style="white-space: pre;">[properties.value]</td>
+    [end]
+  </tr>
+[end]
+</tbody>
+</table>
+</div>
+[end]

Modified: branches/VIEWCVS_DIST/templates/include/sort.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/include/sort.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/include/sort.ezt	Mon Nov  3 09:44:02 2008
@@ -1,8 +1,10 @@
+[is roottype "svn"]
+[else]
 <form method="get" action="[logsort_action]">
   <div>
     <hr />
     <a name="logsort"></a>
-      [logsort_hidden_values]
+      [for logsort_hidden_values]<input type="hidden" name="[logsort_hidden_values.name]" value="[logsort_hidden_values.value]"/>[end]
       Sort log by:
       <select name="logsort" onchange="submit()">
         <option value="cvs" [is logsort "cvs"]selected="selected"[end]>Not sorted</option>
@@ -12,3 +14,4 @@
       <input type="submit" value="  Sort  " />
   </div>
 </form>
+[end]
\ No newline at end of file

Modified: branches/VIEWCVS_DIST/templates/log.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/log.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/log.ezt	Mon Nov  3 09:44:02 2008
@@ -6,6 +6,7 @@
 [for entries]
 [if-index entries first][define first_revision][entries.rev][end][end]
 [if-index entries last][define last_revision][entries.rev][end][end]
+
 <div>
   <hr />
 
@@ -97,6 +98,10 @@
     [end]
   [end]
 
+  [if-any entries.lockinfo]
+    <br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
+  [end]
+
   [is entries.state "dead"]
     <br /><strong><em>FILE REMOVED</em></strong>
   [else]

Modified: branches/VIEWCVS_DIST/templates/log_table.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/log_table.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/log_table.ezt	Mon Nov  3 09:44:02 2008
@@ -110,7 +110,7 @@
       [# Tags ]
       [if-any entries.tags]
         <form method=get action="[pathrev_action]" >
-          [pathrev_hidden_values]
+          [for pathrev_hidden_values]<input type="hidden" name="[pathrev_hidden_values.name]" value="[pathrev_hidden_values.value]"/>[end]
           <select name="pathrev" onChange="submit()">
           <option value="" [is pathrev ""]selected[end]>Show all tags</option>
           [for entries.tags]
@@ -147,9 +147,14 @@
   </tr>
   <tr class="vc_row_[if-index entries even]even[else]odd[end]">
     <td colspan=5>
+
+      [if-any entries.lockinfo]
+        <strong>Lock status</strong>: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]<br />
+      [end]
+
       [is roottype "svn"]
         [if-any entries.orig_path]
-          Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
+          <strong>Original Path</strong>: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
         [end]
 
         [if-any entries.size]

Modified: branches/VIEWCVS_DIST/templates/query_form.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/query_form.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/query_form.ezt	Mon Nov  3 09:44:02 2008
@@ -12,7 +12,7 @@
 <form action="[query_action]" method="get">
 
 <div class="vc_query_form">
-  [query_hidden_values]
+  [for query_hidden_values]<input type="hidden" name="[query_hidden_values.name]" value="[query_hidden_values.value]"/>[end]
 <table cellspacing="0" cellpadding="5" class="auto">
   [is roottype "cvs"]
   [# For subversion, the branch field is not used ]

Modified: branches/VIEWCVS_DIST/templates/revision.ezt
==============================================================================
--- branches/VIEWCVS_DIST/templates/revision.ezt	(original)
+++ branches/VIEWCVS_DIST/templates/revision.ezt	Mon Nov  3 09:44:02 2008
@@ -11,7 +11,7 @@
   <tr align="left">
     <th>Jump to revision:</th>
     <td>
-      [jump_rev_hidden_values]
+      [for jump_rev_hidden_values]<input type="hidden" name="[jump_rev_hidden_values.name]" value="[jump_rev_hidden_values.value]"/>[end]
       <input type="text" name="revision" value="[rev]" />
       <input type="submit" value="Go" />
       [if-any prev_href]

Modified: branches/VIEWCVS_DIST/tparse/tparse.h
==============================================================================
--- branches/VIEWCVS_DIST/tparse/tparse.h	(original)
+++ branches/VIEWCVS_DIST/tparse/tparse.h	Mon Nov  3 09:44:02 2008
@@ -1,5 +1,5 @@
 /*
-# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
+# Copyright (C) 1999-2007 The ViewCVS Group. All Rights Reserved.
 #
 # By using this file, you agree to the terms and conditions set forth in
 # the LICENSE.html file which can be found at the top level of the ViewVC

Modified: branches/VIEWCVS_DIST/viewvc-install
==============================================================================
--- branches/VIEWCVS_DIST/viewvc-install	(original)
+++ branches/VIEWCVS_DIST/viewvc-install	Mon Nov  3 09:44:02 2008
@@ -49,8 +49,8 @@
 FILE_INFO_LIST = [
     ("bin/cgi/viewvc.cgi",        "bin/cgi/viewvc.cgi",        0755, 1, 0, 0),
     ("bin/cgi/query.cgi",         "bin/cgi/query.cgi",         0755, 1, 0, 0),
-    ("bin/mod_python/viewvc_mp.py",  "bin/mod_python/viewvc_mp.py", 0755, 1, 0, 0),
-    ("bin/mod_python/query_mp.py",   "bin/mod_python/query_mp.py",  0755, 1, 0, 0),
+    ("bin/mod_python/viewvc.py",  "bin/mod_python/viewvc.py",  0755, 1, 0, 0),
+    ("bin/mod_python/query.py",   "bin/mod_python/query.py",   0755, 1, 0, 0),
     ("bin/mod_python/handler.py", "bin/mod_python/handler.py", 0755, 1, 0, 0),
     ("bin/mod_python/.htaccess",  "bin/mod_python/.htaccess",  0755, 0, 0, 0),
     ("bin/standalone.py",         "bin/standalone.py",         0755, 1, 0, 0),

Modified: branches/VIEWCVS_DIST/viewvc.conf.dist
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.conf.dist	(original)
+++ branches/VIEWCVS_DIST/viewvc.conf.dist	Mon Nov  3 09:44:02 2008
@@ -68,9 +68,6 @@
 #       address
 #       forbidden
 #   
-#       use_enscript
-#       use_cvsgraph
-#   
 #    To optimize delivery of ViewVC static files:
 #   
 #       docroot
@@ -237,50 +234,16 @@
 
 # Subversion command-line client, used for viewing Subversion repositories
 svn =
-# svn_dir = /usr/bin/svn
+# svn = /usr/bin/svn
 
 # GNU diff, used for showing file version differences
 diff = 
 # diff = /usr/bin/diff
 
-# GNU Enscript, a syntax highlighting program (see options.use_enscript)
-enscript =
-# enscript = /usr/bin/enscript
-
-# Highlight, a syntax highlighting program (see options.use_highlight)
-highlight =
-# highlight = /usr/bin/highlight
-
-# GNU source-highlight, a syntax highlighting program (see 
-# options.use_source_highlight)
-source_highlight = 
-# source_highlight = /usr/bin/source-highlight
-
-# Marc-Andrew Lemburg's py2html, Python colorizer (see options.use_py2html)
-py2html_dir = .
-# py2html_dir = /usr/local/lib/python1.5/site-python
-
-# PHP, used to colorize PHP files (see options.use_php)
-# (This should be set to the path of a PHP CLI executable, not the path
-# to a CGI executable. If you use a CGI executable, you may see "no input file
-# specified" or "force-cgi-redirect" errors instead of colorized source. The
-# output of "php -v" tells you whether an given executable is CLI or CGI.)
-php = php
-# php = /usr/local/bin/php
-# php = C:\Program Files\php\cli\php.exe
-
 # CvsGraph, a graphical CVS version graph generator (see options.use_cvsgraph)
 cvsgraph =
 # cvsgraph = /usr/local/bin/cvsgraph
 
-# Gzip, file compression utility (see options.allow_tar)
-gzip =
-# gzip = /usr/bin/gzip
-
-# Sed, stream editor
-sed =
-# sed = /usr/bin/sed
-
 
 #---------------------------------------------------------------------------
 [options]
@@ -303,8 +266,8 @@
 # allowed_views: List the ViewVC views which are enabled.  Views not
 # in this comma-delited list will not be served (or, will return an
 # error on attempted access).
-# Possible values: "tar", "annotate", "co", "markup"
-allowed_views = markup, annotate
+# Possible values: "tar", "annotate", "co", "markup", "roots"
+allowed_views = markup, annotate, roots
 
 # authorizer: The name of the ViewVC authorizer plugin to use when
 # authorizing access to repository contents.  This value must be the
@@ -314,26 +277,45 @@
 # vcauth.GenericViewVCAuthorizer).  You can provide custom parameters
 # to the authorizer module by defining configuration sections named
 # authz-MODULENAME and adding the parameter keys and values there.
-# ViewVC provides the following modules:  "svnauthz", "forbidden"
+#
+# ViewVC provides the following modules:
+#   svnauthz    - based on Subversion authz files
+#   forbidden   - simple path glob matches against top-level root directories
+#   forbiddenre - root and path matches against regular expressions
+#
+# NOTE: Only one authorizer may be in use for a given ViewVC request.
+# It doesn't matter if you configure the parameters of multiple
+# authorizer plugins -- only the authorizer whose name is configured
+# here (or effectively configured here via vhost configuration) will
+# be activated.
 authorizer = forbidden
 
+# hide_cvsroot: Don't show the CVSROOT directory
+#   1      Hide CVSROOT directory
+#   0      Show CVSROOT directory
+# NOTE: Someday this option may be removed in favor of letting
+# individual authorizer plugin hide the CVSROOT.
+hide_cvsroot = 1
+
 # mangle_email_addresses: Mangle email addresses in marked-up output.
-#   0      Markup un-mangled email addresses as hyperlinks
-#   1      Mangle (and don't markup as hyperlinks) email addresses
+# There are various levels of mangling available:
+#   0 - No mangling; markup un-mangled email addresses as hyperlinks
+#   1 - Obfuscation (using entity encoding); no hyperlinking
+#   2 - Data-dropping address truncation; no hyperlinking
 # Note: this will not effect the display of versioned file contents, only
 # addresses that appear in version control metadata (e.g. log messages).
 mangle_email_addresses = 0
 
-# default_file_view: "log" or "co"
+# default_file_view: "log", "co", or "markup"
 # Controls whether the default view for file URLs is a checkout view or
 # a log view. "log" is the default for backwards compatibility with old
 # ViewCVS URLs, but "co" has the advantage that it allows ViewVC to serve
 # static HTML pages directly from a repository with working links
 # to other repository files
-# Note: Changing this option may cause old ViewCVS URLs that referred
-# to log pages to load checkout pages instead.
-# Also note: If you choose the "co" view, be sure to enable it (via
-# the allowed_views option)
+# Note: Changing this option may break compatibility with existing
+# bookmarked URLs.
+# Also note: If you choose one of the "co" or "markup" views, be sure
+# to enable it (via the allowed_views option)
 default_file_view = log
 
 # http_expiration_time: Expiration time (in seconds) for cacheable
@@ -350,6 +332,12 @@
 #   0      Don't generate Etags
 generate_etags = 1
 
+# svn_config_dir: Path of the Subversion runtime configuration
+# directory ViewVC should consult for various things, including cached
+# remote authentication credentials.  If unset, Subversion will use
+# the default location(s) ($HOME/.subversion, etc.)
+svn_config_dir = 
+
 # use the rcsparse Python module to retrieve CVS repository
 # information instead of invoking rcs utilities [EXPERIMENTAL]
 use_rcsparse = 0
@@ -372,10 +360,17 @@
 #   0      Show the files which are inside the Attic subdir
 hide_attic = 1
 
+# hide_errorful_entries: Hide or show errorful directory entries
+# (perhaps due to not being readable, or some other rlog parsing
+# error, etc.)
+#   1      Hide errorful entries from the directory display
+#   0      Show errorful entries (with their errors) in the directory display
+hide_errorful_entries = 0
+
 # log_sort: Sort order for log messages
 #   date   Sort revisions by date
 #   rev    Sort revision by revision number
-#   cvs    Don't sort them. Same order as CVS/RCS shows them.
+#   none   Use the version control system's ordering
 log_sort = date
 
 # diff_format: Default diff format
@@ -384,16 +379,13 @@
 #   c      Context diff
 #   s      Side by side
 #   l      Long human readable (more context)
+#   f      Full human readable (entire file)
 diff_format = h
 
-# hide_cvsroot: Don't show the CVSROOT directory
-#   1      Hide CVSROOT directory
-#   0      Show CVSROOT directory
-hide_cvsroot = 1
-
-# set to 1 to make lines break at spaces,
-# set to 0 to make no-break lines,
-# set to a positive integer to make the lines cut at that length
+# hr_breakable: Diff view line breaks
+#   1     lines break at spaces
+#   0     no line breaking
+# Or, use a positive integer > 1 to cut lines after that many characters
 hr_breakable = 1
 
 # give out function names in human readable diffs
@@ -405,7 +397,7 @@
 # ignore whitespaces for human readable diffs
 # (indendation and stuff ..)
 # ( '-w' option to diff)
-hr_ignore_white = 1
+hr_ignore_white = 0
 
 # ignore diffs which are caused by
 # keyword-substitution like $Id - Stuff
@@ -414,13 +406,11 @@
 
 # Enable highlighting of intraline changes in human readable diffs
 # this feature is experimental and currently requires python 2.4
-# 
 hr_intraline = 0
 
 # allow compression with gzip of output if the Browser accepts it
-# (HTTP_ACCEPT_ENCODING=gzip)
-# [make sure to have gzip in the path]
-allow_compress = 1
+# (HTTP_ACCEPT_ENCODING contains "gzip")
+#allow_compress = 1
 
 # The directory which contains the EZT templates used by ViewVC to
 # customize the display of the various output views.  ViewVC looks in
@@ -432,6 +422,9 @@
 # If %lang% occurs in the pathname, then the selected language will be
 # substituted.
 #
+# See also the [templates] configuration section, where you can
+# override templates on a per-view basis.
+#
 template_dir = templates
 
 # Web path to a directory that contains ViewVC static files
@@ -442,17 +435,19 @@
 # specified by the "template_dir" option).
 #docroot = /docroot
 
-# Show last changelog message for sub directories
-# The current implementation makes many assumptions and may show the
-# incorrect file at some times. The main assumption is that the last
-# modified file has the newest filedate. But some CVS operations
+# Show last changelog message for CVS subdirectories
+# NOTE: The current implementation makes many assumptions and may show
+# the incorrect file at some times. The main assumption is that the
+# last modified file has the newest filedate. But some CVS operations
 # touches the file without even when a new version is not checked in,
 # and TAG based browsing essentially puts this out of order, unless
-# the last checkin was on the same tag as you are viewing.
-# Enable this if you like the feature, but don't rely on correct results.
+# the last checkin was on the same tag as you are viewing.  Enable
+# this if you like the feature, but don't rely on correct results.
+#
+# ** WARNING: Enabling this will currently leak unauthorized path names **
 show_subdir_lastmod = 0
 
-# show a portion of the most recent log entry in directory listings
+# Show the most recent log entry in directory listings.
 show_logs = 1
 
 # Show log when viewing file contents
@@ -465,51 +460,24 @@
 use_localtime = 0
 #use_localtime = 1
 
-# == Configuration defaults ==
-# Defaults for configuration variables that shouldn't need
-# to be configured..
+### CONFIGURATION DEFAULTS ###
+###
+### Defaults for configuration variables that shouldn't need
+### to be configured..
 
 # the length to which the most recent log entry should be truncated when
 # shown in the directory view
 short_log_len = 80
 
-# should we use Marc-Andrew Lemburg's py2html (and Just van Rossum's
-# PyFontify) to colorize Python files?
-use_py2html = 0
-
-# should we use 'enscript' for syntax coloring?
-use_enscript = 0
-
-# should we use 'highlight' for syntax coloring?
-# NOTE: use_enscript has to be 0 or enscript will be used instead
-use_highlight = 0
-
-# should we add line numbers?
-highlight_line_numbers = 1
+# should we colorize known file content syntaxes?  (requires Pygments module)
+enable_syntax_coloration = 1
 
-# convert tabs to ## spaces (use 0 for no conversion)
-highlight_convert_tabs = 2
-
-# should we use 'source-highlight' for syntax coloring?
-# NOTE: use_enscript and use_highlight have to be 0
-use_source_highlight = 0
-
-# should we add line numbers?
-source_highlight_line_numbers = 1
-
-# use php to colorize .php and .inc files?
-use_php = 0
-
-#
 # Use CvsGraph. See http://www.akhphd.au.dk/~bertho/cvsgraph/ for
 # documentation and download. 
-#
 use_cvsgraph = 0
-# use_cvsgraph = 1
+#use_cvsgraph = 1
 
-#
 # Location of the customized cvsgraph configuration file.  
-#
 cvsgraph_conf = cvsgraph.conf
 
 #
@@ -565,8 +533,9 @@
 # appropriate option below and specify the currect location of the EZT
 # template file you wish to use for that view.
 # 
-# Templates are specified relative to the directory where this config
-# file resides, but absolute paths may also be used as well.
+# Templates are specified relative to the configured template
+# directory (see the "template_dir" option), but absolute paths may
+# also be used as well.
 #
 # If %lang% occurs in the pathname, then the selected language will be
 # substituted.
@@ -575,22 +544,21 @@
 #       [general] section, and based on the request's Accept-Language
 #       header.
 #
-#annotate = templates/annotate.ezt
-#diff = templates/diff.ezt
-#directory = templates/directory.ezt
+#diff = diff.ezt
+#directory = directory.ezt
 ### an alternative directory view
-#directory = templates/dir_new.ezt   
-#error = templates/error.ezt
-#graph = templates/graph.ezt
-#log = templates/log.ezt
+#directory = dir_new.ezt   
+#error = error.ezt
+#file = file.ezt
+#graph = graph.ezt
+#log = log.ezt
 ### a table-based alternative log view
-#log = templates/log_table.ezt  
-#markup = templates/markup.ezt
-#query = templates/query.ezt
-#query_form = templates/query_form.ezt
-#query_results = templates/query_results.ezt
-#revision = templates/revision.ezt
-#roots = templates/roots.ezt
+#log = log_table.ezt  
+#query = query.ezt
+#query_form = query_form.ezt
+#query_results = query_results.ezt
+#revision = revision.ezt
+#roots = roots.ezt
 
 #---------------------------------------------------------------------------
 [cvsdb]
@@ -624,6 +592,17 @@
 # to a conservative number.)
 #rss_row_limit = 100
 
+# Check if the repository is found in the database before showing
+# the query link and RSS feeds.  Set to 1 to enable check.
+# 
+# WARNING: Enabling this check adds the cost of a database connection
+# and query to most ViewVC requests.  If all your roots are represented
+# in the commits database, or if you don't care about the creation of
+# RSS and query links that might lead ultimately to error pages for
+# certain of your roots, or if you simply don't want to add this extra
+# cost to your ViewVC requests, leave this disabled.
+#check_database_for_root = 0
+
 #---------------------------------------------------------------------------
 [vhosts]
 
@@ -684,6 +663,27 @@
 #
 
 #---------------------------------------------------------------------------
+# ViewVC recognizes per-root configuration overrides, too.  To
+# override the value of a configuration parameter only for a single
+# root, create a configuration section whose names is of the form
+# root-ROOTNAME/CONFIGSECTION.  ROOTNAME here is the name of the root
+# as defined explicitly in cvs_roots or svn_roots or implicitly as the
+# basename of a root path in root_parents.  Options found in this new
+# configuration section override for this one root the corresponding
+# options found in the base configuration section CONFIGSECTION
+# ("options", "authz-*", etc.)
+#
+# Here is an example showing how to enable Subversion authz-based
+# authorization for only the single root named "svnroot":
+# 
+# [root-svnroot/options]
+# authorizer = svnauthz
+#
+# [root-svnroot/authz-svnauthz]
+# authzfile = /path/to/authzfile
+#
+
+#---------------------------------------------------------------------------
 [authz-forbidden]
 
 # The "forbidden" authorizer forbids access to repository modules,
@@ -730,6 +730,49 @@
 forbidden = 
 
 #---------------------------------------------------------------------------
+[authz-forbiddenre]
+
+# The "forbiddenre" authorizer forbids access to repositories and
+# repository paths by comparing a list of regular expressions
+# (separated by commas) against paths consisting of the repository (or
+# root) name plus the path of the versioned file or directory to be
+# tested.  For example, to see if the user is authorized to see the
+# path "/trunk/www/index.html" in the repository whose root name is
+# "svnrepos", this authorizer will check the path
+# "svnrepos/trunk/www/index.html" against the list of forbidden
+# regular expressions.  Directory paths will be terminated by a forward
+# slash.
+#
+# Like the "forbidden" authorizer...
+#
+#   *) The "!" can be used before a module to explicitly state that it
+#      is NOT forbidden. Whenever this form is seen, then all modules will
+#      be forbidden unless one of the "!" modules match.
+#
+#   *) Tests are performed in sequence. The first match will terminate the
+#      testing. This allows for more complex allow/deny patterns.
+#
+# Unlike the "forbidden" authorizer, you can can use this to hide roots, too.
+#
+# Some examples:
+#
+#    Disallow files named "PRIVATE", but allow all others:
+#       forbiddenre = /PRIVATE$
+#
+#    Disallow the "hidden" repository, allowing all others:
+#       forbiddenre = ^hidden(/|$)
+#
+#    Allow only the "example1" and "example2" roots and the paths inside them,
+#    disallowing all others (which can be done in multiple ways):
+#       forbiddenre = !^example1(/|$), !^example2(/|$)/
+#       forbiddenre = !^example[12](/|$)
+#
+#    Only allow visibility of HTML files and the directories that hold them:
+#       forbiddenre = !^([^/]+|.*(/|\.html))$
+#
+forbiddenre = 
+
+#---------------------------------------------------------------------------
 [authz-svnauthz]
 
 # The "svnauthz" authorizer uses a Subversion authz configuration file

Modified: branches/VIEWCVS_DIST/viewvc.org/contact.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/contact.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/contact.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Contact</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -61,19 +62,25 @@
    these lists (and other project lists), as well view the list
    archives, <a
    href="http://viewvc.tigris.org/servlets/ProjectMailingListList";
-   >here</a>.</p>
+   >here</a>.  If you are having problems with ViewVC, consider
+   checking our <a href="./faq.html">Frequently Asked Questions</a>
+   page and list of <a
+   href="http://viewvc.tigris.org/issues/buglist.cgi?component=viewvc&amp;issue_status=UNCONFIRMED&amp;issue_status=NEW&amp;issue_status=STARTED&amp;issue_status=REOPENED";
+   >open issues</a> before mail our users@ list &mdash; perhaps the
+   information you need is already available in one of those
+   places.</p>
 
-<p>If you're seeking interaction that's a little more real-time, use
-   your favorite IRC client to pop into <tt><a
+<p>If you prefer interaction that's a little more real-time, use your
+   favorite IRC client to pop into <tt><a
    href="irc://irc.freenode.net/viewvc">#viewvc</a></tt> on
    irc.freenode.net.</p>
 
 <p>So, to summarize:</p>
 
 <ul>
-<li>Email, developer chatter &mdash; &#100;&#101;&#118;&#64;&#118;&#105;&#101;&#119;&#118;&#99;&#46;&#116;&#105;&#103;&#114;&#105;&#115;&#46;&#111;&#114;&#103;</li>
-<li>Email, user chatter &mdash; &#117;&#115;&#101;&#114;&#115;&#64;&#118;&#105;&#101;&#119;&#118;&#99;&#46;&#116;&#105;&#103;&#114;&#105;&#115;&#46;&#111;&#114;&#103;</li>
-<li>IRC &mdash; irc.freenode.net, #viewvc</li>
+<li>To discuss ViewVC installation, configuration, and behavior:  &#117;&#115;&#101;&#114;&#115;&#64;&#118;&#105;&#101;&#119;&#118;&#99;&#46;&#116;&#105;&#103;&#114;&#105;&#115;&#46;&#111;&#114;&#103;</li>
+<li>To discuss the development of ViewVC itself or submit patches:  &#100;&#101;&#118;&#64;&#118;&#105;&#101;&#119;&#118;&#99;&#46;&#116;&#105;&#103;&#114;&#105;&#115;&#46;&#111;&#114;&#103;</li>
+<li>To discussion anything ViewVC-related in real time:  irc.freenode.net, #viewvc</li>
 </ul>
 
 </div> <!-- section-body -->

Modified: branches/VIEWCVS_DIST/viewvc.org/contributing.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/contributing.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/contributing.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Contributing</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>

Modified: branches/VIEWCVS_DIST/viewvc.org/download.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/download.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/download.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Download</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -74,7 +75,7 @@
 <p>The source code for ViewVC is maintained in a Subversion repository
    at Tigris.org.  You can checkout the trunk of our development tree
    from <a href="http://viewvc.tigris.org/svn/viewvc/trunk/";
-   ><tt>http://viewvc.tigris.org/svn/viewvc/trunk/</tt></a>.  You'll
+   >http://viewvc.tigris.org/svn/viewvc/trunk/</a>.  You'll
    need to provide your Tigris.org username and password when so
    prompted, or, if you don't have a Tigris.org account, use "guest"
    as the username (with no, or an empty, password).</p>

Modified: branches/VIEWCVS_DIST/viewvc.org/faq.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/faq.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/faq.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Frequently Asked Questions (FAQ)</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -45,26 +46,23 @@
 </td>
 <td id="pagecolumn2">
 
-<div class="notice">
-<p>This FAQ is, shall we say, a work in progress.  At the moment, it's
-   pretty bare.  Please bare &mdash; er, <strong>bear</strong> with us
-   as we slowly populate this document.</p>
-</div>
-
 <div class="section">
 
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
 <h2 id="faq-q">Questions</h2>
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
 
 <div class="section-body">
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-q-general">General Usage</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 
 <ul>
 
+<li><a href="#installation">Where does the installation documentation,
+    if any, live?</a></li>
+
 <li><a href="#authz-support">Does ViewVC support path-based
     authorization, such as Subversion's authz-file mechanism?</a></li>
 
@@ -80,9 +78,9 @@
 
 </ul>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-q-cvs">CVS Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 
 <ul>
 
@@ -92,7 +90,8 @@
 <li><a href="#comalformedoutput">What causes "Error: COMalformedOutput: Unable to
     find filename in co output stream"?</a></li>
 
-<li><a href="#">What causes "Error: error during rlog: 0x100"?</a></li>
+<li><a href="#error-during-rlog">What causes "Error: error during
+    rlog: 0x100"?</a></li>
 
 <li><a href="#missing-files">Why do my directories have no files in them?</a></li>
 
@@ -102,9 +101,9 @@
 
 </ul>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-q-svn">Subversion Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 
 <ul>
 
@@ -116,21 +115,37 @@
 
 </ul>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 </div>
 </div>
 
 <div class="section">
 
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
 <h2 id="faq-a">Answers</h2>
-<!-- ###################################################################### -->
+<!-- ##################################################################### -->
 
 <div class="section-body">
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-a-general">General Usage</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
+
+<div id="installation">
+<p class="faq-atitle">Where does the installation documentation, if
+   any, live?</p>
+
+<p>ViewVC's installation how-to documentation lives in the INSTALL
+   file located in the root of the ViewVC source code distribution.
+   The most recent version of this document (which may cover
+   unreleased ViewVC versions) can be found
+   at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL";
+   >http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/INSTALL</a>.
+   If you are upgrading an existing ViewVC instance, you'll also want
+   to read the upgrade documentation, found
+   at <a href="http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html";
+   >http://viewvc.tigris.org/source/browse/*checkout*/viewvc/trunk/docs/upgrading-howto.html</a>.</p>
+</div>
 
 <div id="authz-support">
 <p class="faq-atitle">Does ViewVC support path-based authorization,
@@ -204,9 +219,9 @@
    additional configuration.</p>
 </div>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-a-cvs">CVS Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 
 <div id="rlog-output-ended-early">
 
@@ -235,7 +250,7 @@
 
 </div>
 
-<div id="">
+<div id="error-during-rlog">
 <p class="faq-atitle">What causes "Error: error during rlog:
    0x100"?</p>
 
@@ -251,7 +266,11 @@
 <ul>
 <li>Some folks mistakenly point ViewVC's configuration bits to their
     CVS working copies.  But ViewVC isn't a working copy browser
-    &mdash; it's a <em>repository</em> browser.</li>
+    &mdash; it's a <em>repository</em> browser.  If you don't know
+    the difference, here's a tip that might help:  CVS repositories
+    are directories trees filled with files that end with
+    "<code>,v</code>".  If your directory isn't filled with "comma
+    vee" files, it probably is <em>not</em> a CVS repository.</li>
 <li>&hellip; <!-- TODO --></li>
 </ul>
 </div>
@@ -268,11 +287,12 @@
    solution is to try to get versions of CVS/CVSNT and ViewVC which
    are better aligned, which generally means upgrading ViewVC (which
    is probably less disruptive than downgrading your version control
-   system).</p> </div>
+   system).</p>
+</div>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 <h3 class="faq-section" id="faq-a-svn">Subversion Browsing</h3>
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 
 <div id="no-module-named-svn">
 <p class="faq-atitle">What causes "Error: ImportError: No module named
@@ -323,10 +343,10 @@
          the remote repository aren't cached in
          <code>~VIEWVC_USER/.subversion</code> (where
          <code>VIEWVC_USER</code> is the system user as whom ViewVC
-         runs), stuff won't work.</p>
+         runs), stuff won't work.</p></li>
 </ul>
 
-<!-- #--------------------------------------------------------------------# -->
+<!-- #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# -->
 </div>
 </div>
 

Added: branches/VIEWCVS_DIST/viewvc.org/favicon.ico
==============================================================================
Binary file. No diff available.

Modified: branches/VIEWCVS_DIST/viewvc.org/images/title.jpg
==============================================================================
Binary files. No diff available.

Modified: branches/VIEWCVS_DIST/viewvc.org/images/title.xcf
==============================================================================
Binary files. No diff available.

Modified: branches/VIEWCVS_DIST/viewvc.org/index.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/index.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/index.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Repository Browsing</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -75,10 +76,7 @@
       href="http://www.akhphd.au.dk/~bertho/cvsgraph/";>CvsGraph</a>)
       (<em>CVS only</em>).</li>
 
-  <li>Syntax highlighting support (via integration with <a
-      href="http://www.codento.com/people/mtr/genscript/";>GNU
-      enscript</a> or
-      <a href="http://www.andre-simon.de/";>Highlight</a>).</li>
+  <li>Syntax highlighting support.</li>
 
   <li><a href="http://www.mozilla.org/projects/bonsai/";>Bonsai</a>-like
       repository query facilities.</li>

Modified: branches/VIEWCVS_DIST/viewvc.org/nightly/build-viewvc-snapshot
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/nightly/build-viewvc-snapshot	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/nightly/build-viewvc-snapshot	Mon Nov  3 09:44:02 2008
@@ -1,37 +1,119 @@
-#!/bin/sh
+#!/usr/bin/env python
 
-DATE=`date +"%Y%m%d"`
-EXPORTDIR="viewvc-${DATE}"
-PUBLISH_DIR=/www/viewvc/nightly
-
-# export HEAD of trunk
-svn export --quiet http://viewvc.tigris.org/svn/viewvc/trunk ${EXPORTDIR} --username guest --password ""
-
-# use Python to determine the version number, reading it from 
-# viewvc.__version__
-cd $EXPORTDIR/lib
-VERSION=`python -c "import viewvc; print viewvc.__version__"`
-TARGET=viewvc-${VERSION}-${DATE}
-
-# make a release
-cd ../tools
-./make-release ${TARGET}
-
-# remove results of last build
-rm -rf ${PUBLISH_DIR}/viewvc*.tar.gz ${PUBLISH_DIR}/viewvc*.zip ${PUBLISH_DIR}/index.html
-
-# publish new build
-mv ${TARGET}.* ${PUBLISH_DIR}
-cd ../..
+import sys
+import os
+import time
+import urllib
+import shutil
+import getopt
+import tempfile
+
+  
+class BuildError(Exception):
+  def __init__(self, message):
+    self.message = message
+  def __str__(self):
+    return self.message
+  
+
+def make_release(branch, export_dir, publish_dir, root_url, username, password):
+    
+  # Export the requested ViewVC source tree.
+  cmd = "svn export --quiet '%s/%s' %s " \
+        "--username '%s' --password '%s' --non-interactive --force" \
+        % (root_url, urllib.quote(branch), export_dir, username, password)
+  sys.stdout.write("Running: %s\n" % (cmd))
+  os.system(cmd)
+
+  # Get the version number from ViewVC itself.
+  sys.path.insert(0, os.path.join(export_dir, 'lib'))
+  try:
+    import viewvc
+  except ImportError:
+    raise BuildError("Unable to import viewvc module; export failed?")
+  version = viewvc.__version__
+  del sys.modules['viewvc']
+  del viewvc
+  del sys.path[0]
+
+  # Now, use ViewVC tools to make the distribution archives.
+  localtime = time.localtime()
+  date = "%4d%02d%02d" % (localtime[0], localtime[1], localtime[2])
+  distversion = "viewvc-%s" % (version)
+  distname = "%s-%s" % (distversion, date)
+  gzip_name = distname + '.tar.gz'
+  zip_name = distname + '.zip'
+  curdir = os.getcwd()
+  try:
+    os.chdir(os.path.join(export_dir, 'tools'))
+    os.system('./make-release %s' % (distname))
+  finally:
+    os.chdir(curdir)
+
+  # Finally, return the locations of the archive files we've built.
+  gzip_file = os.path.join(export_dir, 'tools', gzip_name)
+  if not os.path.exists(gzip_file):
+    gzip_file = None
+  zip_file = os.path.join(export_dir, 'tools', zip_name)
+  if not os.path.exists(zip_file):
+    zip_file = None
+
+  # Remove superceded archives.
+  if gzip_file or zip_file:
+    dirents = os.listdir(publish_dir)
+    for dirent in dirents:
+      if dirent.startswith(distversion) \
+             and ((dirent.endswith('.tar.gz') and gzip_file) \
+                  or (dirent.endswith('.zip') and zip_file)):
+        os.unlink(dirent)
+
+  # Install the new archives.
+  if gzip_file:
+    os.rename(gzip_file, os.path.join(publish_dir, gzip_name))
+  if zip_file:
+    os.rename(zip_file, os.path.join(publish_dir, zip_name))
+    
+  # Return our archive names.
+  return gzip_file and gzip_name or None, zip_file and zip_name or None
+
+
+def publish_releases(branches, publish_dir, root_url, username, password):
+  new_index_contents = get_html_index_header()
+  for branch in branches:
+    sys.stdout.write("Beginning build for branch '%s'.\n" % (branch))
+    export_dir = None
+    try:
+      export_dir = tempfile.mkdtemp("", "viewvc-nightly-")
+      gzip_file, zip_file = make_release(branch, export_dir, publish_dir,
+                                         root_url, username, password)
+      new_index_contents = new_index_contents + """
+<p>Build of %s:</p>
+<ul>
+<li><a href="%s">%s</a></li>
+<li><a href="%s">%s</a></li>
+</ul>
+""" % (branch, urllib.quote(gzip_file), gzip_file,
+       urllib.quote(zip_file), zip_file)
+    finally:
+      if export_dir:
+        sys.stdout.write("Removing temporary directory '%s'.\n" % (export_dir))
+        shutil.rmtree(export_dir)
+    sys.stdout.write("Finished build for branch '%s'.\n" % (branch))
+
+  new_index_contents = new_index_contents + get_html_index_footer()
+  open(os.path.join(publish_dir, 'index.html'), 'w').write(new_index_contents)
+       
 
-cat > ${PUBLISH_DIR}/index.html <<EOF
+def get_html_index_header():
+  return """
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: Nightly Snapshots</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="../styles.css"/>
+<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -60,7 +142,7 @@
 <h4>On this page:</h4>
 
 <ul id="bookmarks">
-  <li><a href="#sec-snapshots">Snapshots</a></li>
+  <li><a href="%s">Snapshots</a></li>
 </ul>
 
 <p><a href="http://validator.w3.org/check?uri=referer";><img
@@ -72,19 +154,13 @@
 <td id="pagecolumn2">
 
 <div class="section">
-
 <h2 id="sec-snapshots">Snapshots</h2>
-
 <div class="section-body">
-<ul>
-EOF
+""" % ("#sec-snapshots")
 
-echo "<li><a href=\"${TARGET}.tar.gz\">${TARGET}.tar.gz</a></li>" >> ${PUBLISH_DIR}/index.html
-echo "<li><a href=\"${TARGET}.zip\">${TARGET}.zip</a></li>" >> ${PUBLISH_DIR}/index.html
-
-cat >> ${PUBLISH_DIR}/index.html <<EOF
-</ul>
 
+def get_html_index_footer():
+  return """
 </div> <!-- section-body -->
 </div> <!-- section -->
 
@@ -93,7 +169,51 @@
 </table>
 </body>
 </html>
-EOF
+"""
+
 
-# more cleanup
-rm -rf ${EXPORTDIR}
+def usage_and_exit(errmsg=None):
+  stream = errmsg and sys.stderr or sys.stdout
+  progname = os.path.basename(sys.argv[0])
+  stream.write("""%s -- nightly ViewVC build generation
+  
+Usage: %s [OPTIONS] PUBLISH-DIR BRANCH ...
+
+Build an archive from one or more BRANCH in the ViewVC source
+repository, dropping them into PUBLISH-DIR alongside an index.html
+file that name and links to them.
+
+Options:
+   --help (-h, -?)  : Show this usage message
+   --username       : Username used for source export
+   --password       : Password used for source export
+   --root-url       : Alternative source repository root URL
+
+""" % (progname, progname))
+  if errmsg:
+    stream.write("ERROR: %s\n" % (errmsg))
+  sys.exit(errmsg and 1 or 0)
+
+
+if __name__ == "__main__":
+  root_url = "http://viewvc.tigris.org/svn/viewvc";
+  username = password = ""
+  opts, args = getopt.getopt(sys.argv[1:], 'h?',
+                             ['help', 'username=', 'password=', 'root-url='])
+  for name, value in opts:
+    if name == '-h' or name == '-?' or name == '--help':
+      usage_and_exit()
+    elif name == '--username':
+      username = value
+    elif name == '--password':
+      password = value
+    elif name == '--root-url':
+      root_url = value
+  argc = len(args)
+  if argc < 2:
+    usage_and_exit("Not enough arguments")
+  try:
+    publish_releases(args[1:], args[0], root_url, username, password)
+  except BuildError, e:
+    sys.stderr.write(str(e) + "\n")
+    sys.exit(1)

Modified: branches/VIEWCVS_DIST/viewvc.org/styles.css
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/styles.css	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/styles.css	Mon Nov  3 09:44:02 2008
@@ -1,15 +1,13 @@
 body {
-    background-color: rgb(180,193,205);
-    background-image: url('./images/bg-grad.jpg');
-    background-repeat: repeat-x;
+    background-color: #b2d388;
     color: black;
     font-family: trebuchet ms, arial, sans-serif;
     margin: 0;
 }
 
 #title {
-    background-color: rgb(100,128,150);
-    height: 60px;
+    background-color: #739c3e;
+    height: 70px;
 }
 
 img {
@@ -27,7 +25,7 @@
 }
 
 h2 {
-    background-color: rgb(204,213,221);
+    background-color: #94bd5e;
     padding: 2px 0.5em 2px 0.5em;
     margin: 0;
     border-bottom: dotted 1px rgb(180,193,205);

Modified: branches/VIEWCVS_DIST/viewvc.org/who.html
==============================================================================
--- branches/VIEWCVS_DIST/viewvc.org/who.html	(original)
+++ branches/VIEWCVS_DIST/viewvc.org/who.html	Mon Nov  3 09:44:02 2008
@@ -1,10 +1,11 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml";>
 <head>
 <title>ViewVC: About</title>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <link rel="stylesheet" type="text/css" href="./styles.css"/>
+<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
 </head>
 
 <body>
@@ -166,9 +167,9 @@
 <p>The ViewVC website was designed by <a
    href="http://www.cmichaelpilato.com/";>C. Michael Pilato</a>.  All
    HTML was hand-edited in Emacs, and the little splashes of graphical
-   goodness owe their existence to Adobe PhotoShop.  Textual content
-   for the site is mostly the work of Greg Stein, but has been tweaked
-   through the ages by various ViewVC contributors.</p>
+   goodness owe their existence to Open Office and the Gimp.  Textual
+   content for the site is mostly the work of Greg Stein, but has been
+   tweaked through the ages by various ViewVC contributors.</p>
 
 </div> <!-- section-body -->
 </div> <!-- section -->

Modified: branches/VIEWCVS_DIST/windows/README
==============================================================================
--- branches/VIEWCVS_DIST/windows/README	(original)
+++ branches/VIEWCVS_DIST/windows/README	Mon Nov  3 09:44:02 2008
@@ -1,301 +1,324 @@
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 DESCRIPTION
 
-This file contains special instructions for setting up ViewVC on Windows. It
-will take you through a basic installation and tell you how to set up optional
-features like code colorizing and the MySQL commit database.
+This file contains special instructions for setting up ViewVC on
+Windows. It will take you through a basic installation and tell you
+how to set up optional features like code colorizing and the MySQL
+commit database.
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 REQUIREMENTS
 
 ViewVC requires the Python interpreter which you can download from
 
-  http://python.org/
+   http://python.org/
 
 and the Python for Windows Extensions which are at
 
-  http://sourceforge.net/projects/pywin32/
+   http://sourceforge.net/projects/pywin32/
 
-For CVS support, ViewVC also requires that the CVSNT client (cvs.exe) OR the
-RCS tools (rlog.exe, rcsdiff.exe, and co.exe) be installed on your computer.
-CVSNT is available from
+For CVS support, ViewVC also requires that the CVSNT client (cvs.exe)
+OR the RCS tools (rlog.exe, rcsdiff.exe, and co.exe) be installed on
+your computer.  CVSNT is available from
 
-  http://www.cvsnt.org/wiki
+   http://www.cvsnt.org/wiki
 
 and RCS can be obtained from:
 
-  http://www.cs.purdue.edu/homes/trinkle/RCS/
+   http://www.cs.purdue.edu/homes/trinkle/RCS/
 
-For Subversion support, you'll need to have the Subversion Python bindings
-installed. Binaries are available from the Subversion website at:
+For Subversion support, you'll need to have the Subversion Python
+bindings installed. Binaries are available from the Subversion website
+at:
 
-  http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91
+   http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91
 
-Note that if you use binaries, you have to be running the same version of
-python as the binaries were built for. For example, you cannot use Subversion
-bindings built for Python 2.3 with Python 2.4. Instructions for building
-the binaries from source are available here:
+Note that if you use binaries, you have to be running the same version
+of python as the binaries were built for. For example, you cannot use
+Subversion bindings built for Python 2.3 with Python 2.4. Instructions
+for building the binaries from source are available here:
 
-  http://svn.collab.net/repos/svn/trunk/subversion/bindings/swig/INSTALL
+   http://svn.collab.net/repos/svn/trunk/subversion/bindings/swig/INSTALL
 
-The Subversion bindings also require you to have diff.exe installed in a
-directory on your system PATH. diff.exe is available as part of the GnuWin32
-project's DiffUtils package at http://gnuwin32.sf.net/.
+The Subversion bindings also require you to have diff.exe installed in
+a directory on your system PATH. diff.exe is available as part of the
+GnuWin32 project's DiffUtils package at http://gnuwin32.sf.net/.
 
-Once you've got Python and CVSNT or RCS or the Subversion bindings installed,
-you can test out ViewVC before you install it by running:
+Once you've got Python and CVSNT or RCS or the Subversion bindings
+installed, you can test out ViewVC before you install it by running:
 
-  python bin\standalone.py -r <PATH_TO_REPOSITORY>
+   python bin\standalone.py -r <PATH_TO_REPOSITORY>
 
-The standalone server has a number of features (including a GUI interface)
-which you can find out about by running
+The standalone server has a number of features (including a GUI
+interface) which you can find out about by running
 
-  python bin\standalone.py --help
+   python bin\standalone.py --help
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 BASIC INSTALLATION
 
 Run the ViewVC install script with
 
-  python viewvc-install
+   python viewvc-install
 
-The script will copy the source files into an installation directory that you
-specify, store some path information, and compile the ViewVC library files into
-Python bytecode.
-
-After the installation is finished you will need to edit the viewvc.conf file
-in the folder you installed to. The comments in that file tell you exactly what
-to do.
-
-With the config file set up you should be able to double-click standalone.py
-and access your repository with a web browser.
-
-See the sections below for information on setting up optional features and
-troubleshooting. From here on <PYTHON_DIR> will stand for the Python root
-directory (usually something like C:\Python22) and <VIEWVC_INSTALL_DIR> will
-represent the directory where ViewVC has been installed to (default is
-C:\Program Files\viewvc-VERSION).
+The script will copy the source files into an installation directory
+that you specify, store some path information, and compile the ViewVC
+library files into Python bytecode.
+
+After the installation is finished you will need to edit the
+viewvc.conf file in the folder you installed to. The comments in that
+file tell you exactly what to do.
+
+With the config file set up you should be able to double-click
+standalone.py and access your repository with a web browser.
+
+See the sections below for information on setting up optional features
+and troubleshooting. From here on <PY_DIR> will stand for the Python
+root directory (usually something like C:\Python22) and
+<VIEWVC_INSTALL_DIR> will represent the directory where ViewVC has
+been installed to (default is C:\Program Files\viewvc-VERSION).
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 SERVER CONFIGURATION
 
-If you want to make ViewVC available to a network (rather than using it on a
-standalone machine), you will need to configure a web server to host it. This
-section includes instructions for setting up ViewVC on two commonly used
-Windows web servers, IIS and Apache.
-
-With IIS, you can run ViewVC in CGI mode or ASP mode (or both modes). ASP mode
-gives better performance (faster page loads), but is harder to set up and may
-be less stable. CGI mode is stable and easy to set up but slower.
+If you want to make ViewVC available to a network (rather than using
+it on a standalone machine), you will need to configure a web server
+to host it. This section includes instructions for setting up ViewVC
+on two commonly used Windows web servers, IIS and Apache.
+
+With IIS, you can run ViewVC in CGI mode or ASP mode (or both
+modes). ASP mode gives better performance (faster page loads), but is
+harder to set up and may be less stable. CGI mode is stable and easy
+to set up but slower.
 
-On Apache, you can use CGI mode or Mod_Python mode or both modes at once.
-Mod_Python mode is faster than CGI mode.
+On Apache, you can use CGI mode or Mod_Python mode or both modes at
+once.  Mod_Python mode is faster than CGI mode.
 
 CGI Mode On IIS
 
-  1) Copy viewvc.cgi and query.cgi from <VIEWVC_INSTALL_DIR>\bin\cgi to a
-  folder that is accessible through your web server.
+   1) Copy viewvc.cgi and query.cgi from <VIEWVC_INSTALL_DIR>\bin\cgi to a
+      folder that is accessible through your web server.
 
-  2) Start up the IIS "Internet Services Manager" and right click a virtual
-  server or virtual directory that contains the files you just copied. Choose
-  "Properties" from the context menu that appears.
-
-  3) On the properties dialog that appears, navigate to [Home | Virtual]
-  Directory -> Application Settings -> Configuration. This will bring up
-  another dialog box called "Application Configuration".
-
-  4) On the "App Mappings" tab choose "Add". Fill in the following information
-
-                 Executable:  <PYTHON_DIR>\python.exe "%s"
-                  Extension:  cgi
-              Script Engine:  checked
-     Check that file exists:  unchecked
-
-  That is all. Assuming you've set up viewvc.conf to point to your
-  repositories, the CGI pages should run. See the Troubleshooting section below
-  if there are any problems.
+   2) Start up the IIS "Internet Services Manager" and right click a
+      virtual server or virtual directory that contains the files you
+      just copied. Choose "Properties" from the context menu that
+      appears.
+
+   3) On the properties dialog that appears, navigate to [Home |
+      Virtual] Directory -> Application Settings ->
+      Configuration. This will bring up another dialog box called
+      "Application Configuration".
+
+   4) On the "App Mappings" tab choose "Add". Fill in the following
+      information:
+
+                    Executable:  <PY_DIR>\python.exe "%s"
+                     Extension:  cgi
+                 Script Engine:  checked
+        Check that file exists:  unchecked
+
+   That is all. Assuming you've set up viewvc.conf to point to your
+   repositories, the CGI pages should run. See the Troubleshooting
+   section below if there are any problems.
 
 ASP Mode On IIS
 
-  In order to run ViewVC with ASP, you will need to enable Python ActiveX
-  scripting and to install the included Aspfool ISAPI filter on whatever
-  virtual server is being used to serve the viewvc pages. Step by step
-  instructions follow below. Aspfool is located in the windows\aspfool folder.
-
-  To set up ASP mode, follow these steps:
-
-  1) Run <PYTHON_DIR>\Lib\site-packages\win32comext\axscript\client\pyscript.py
-  to register Python as an ASP scripting language. (More documentation on this
-  is at http://www.python.org/windows/win32com/ActiveXScripting.html)
-
-  2) Copy the viewvc.asp and query.asp files from
-  <VIEWVC_INSTALL_DIR>\bin\asp to a folder that is accessible through your web
-  server.
+   In order to run ViewVC with ASP, you will need to enable Python
+   ActiveX scripting and to install the included Aspfool ISAPI filter
+   on whatever virtual server is being used to serve the viewvc
+   pages. Step by step instructions follow below. Aspfool is located
+   in the windows\aspfool folder.
+
+   To set up ASP mode, follow these steps:
+
+   1) Run <PY_DIR>\Lib\site-packages\win32comext\axscript\client\pyscript.py
+      to register Python as an ASP scripting language. (More
+      documentation on this is at
+      http://www.python.org/windows/win32com/ActiveXScripting.html)
+
+   2) Copy the viewvc.asp and query.asp files from
+      <VIEWVC_INSTALL_DIR>\bin\asp to a folder that is accessible
+      through your web server.
+
+   3) Start up the IIS "Internet Services Manager" and right click on
+      the virtual server that contains the files you just
+      copied. Choose "Properties" from the context menu that appears.
+
+   4) On the properties dialog that appears, click the "ISAPI Filters"
+      tab.  Click the "add" button and enter the following
+      information:
 
-  3) Start up the IIS "Internet Services Manager" and right click on the
-  virtual server that contains the files you just copied. Choose "Properties"
-  from the context menu that appears.
+         Filter Name:  aspfool
+          Executable:  aspfool.dll
 
-  4) On the properties dialog that appears, click the "ISAPI Filters" tab.
-  Click the "add" button and enter the following information:
-
-     Filter Name:  aspfool
-      Executable:  aspfool.dll
-
-  After you save these changes, the ViewVC ASP pages should begin to work.
+   After you save these changes, the ViewVC ASP pages should begin to
+   work.
 
 CGI Mode on Apache
 
-  Follow the instructions under "Apache Configuration" in the ViewVC INSTALL
-  file.
+   Follow the instructions under "Apache Configuration" in the ViewVC
+   INSTALL file.
 
 Mod_Python Mode on Apache
 
-  There are probably ten thousand different ways to set up Apache, mod_python,
-  and ViewVC together. Here are some instructions that work for me using
-  Mod_Python 3.0.3 and Apache 2.0.46. If any Apache gurus want to contribute
-  better instructions, I'd be happy to include them here.
-
-  1) Run the win32 mod_python installer from www.modpython.org.
-
-  2) Add the following line to the "Global Environment" section of httpd.conf
+   There are probably ten thousand different ways to set up Apache,
+   mod_python, and ViewVC together. Here are some instructions that
+   work for me using Mod_Python 3.0.3 and Apache 2.0.46. If any Apache
+   gurus want to contribute better instructions, I'd be happy to
+   include them here.
+
+   1) Run the win32 mod_python installer from www.modpython.org.
+
+   2) Add the following line to the "Global Environment" section of
+      httpd.conf:
+
+         LoadModule python_module modules/mod_python.so
+
+   3) Copy viewvc.py, query.py, handler.py, and .htaccess from
+      <VIEWVC_INSTALL_DIR>\bin\mod_python to a folder being served by
+      apache. Make sure overrides are allowed in this folder. The
+      relevant parent directory in httpd.conf should have
+      "AllowOverride All" set, or at least "AllowOverride FileInfo
+      Options".
 
-     LoadModule python_module modules/mod_python.so
-
-  3) Copy viewvc.py, query.py, handler.py, and .htaccess from
-  <VIEWVC_INSTALL_DIR>\bin\mod_python to a folder being served by apache. Make
-  sure overrides are allowed in this folder. The relevant parent directory in
-  httpd.conf should have "AllowOverride All" set, or at least "AllowOverride
-  FileInfo Options".
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 ENSCRIPT HIGHLIGHTING
 
-To use enscript, you'll have to install the enscript, libintl, libiconv, and
-sed packages from the gnuwin32 project (http://gnuwin32.sourceforge.net/).
-Detailed instructions are on their site, but here is the basic procedure.
-
-1) Extract all packages to a folder on your hard drive, for example c:\gnuwin32
-
-2) Add "c:\gnuwin32\bin" to the system "PATH" environment variable. If ViewVC
-is running as part of a system service like IIS you will need to reboot the
-computer so it is able to see the value. See the "Troubleshooting" section
-below for specific information on when a reboot is neccessary.
+To use enscript, you'll have to install the enscript, libintl,
+libiconv, and sed packages from the gnuwin32 project
+(http://gnuwin32.sourceforge.net/).  Detailed instructions are on
+their site, but here is the basic procedure.
+
+1) Extract all packages to a folder on your hard drive, for example
+   c:\gnuwin32
+
+2) Add "c:\gnuwin32\bin" to the system "PATH" environment variable. If
+   ViewVC is running as part of a system service like IIS you will
+   need to reboot the computer so it is able to see the value. See the
+   "Troubleshooting" section below for specific information on when a
+   reboot is neccessary.
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 BONSAI-LIKE CHECKIN DATABASE
 
-To use the checkin database, you'll need to install MySQL and the MySQL-Python
-interface. MySQL can be downloaded from www.mysql.com. The MySql-Python adapter
-is available from http://sf.net/projects/mysql-python/. Make sure to grab the
-the latest version from the "Files" section. (The "Home Page" link takes you to
-an outdated page that only links to very old versions.) Both packages come with
-GUI installers. Once you have MySQL running and set up with a username and
-password, follow these instructions to set up ViewVC.
+To use the checkin database, you'll need to install MySQL and the
+MySQL-Python interface. MySQL can be downloaded from
+www.mysql.com. The MySql-Python adapter is available from
+http://sf.net/projects/mysql-python/. Make sure to grab the the latest
+version from the "Files" section. (The "Home Page" link takes you to
+an outdated page that only links to very old versions.) Both packages
+come with GUI installers. Once you have MySQL running and set up with
+a username and password, follow these instructions to set up ViewVC.
 
 1) Open a command prompt and type these commands:
 
-   cd /d <VIEWVC_INSTALL_DIR>
-   python bin\make-database
+      cd /d <VIEWVC_INSTALL_DIR>
+      python bin\make-database
 
-The script that comes up will prompt you for the MySQL username and password
-(you should have created these during the MySQL installation), and the name of
-the database to create. The default database name "ViewVC" should be fine
-unless for some reason a database with that name already exists.
+   The script that comes up will prompt you for the MySQL username and
+   password (you should have created these during the MySQL
+   installation), and the name of the database to create. The default
+   database name "ViewVC" should be fine unless for some reason a
+   database with that name already exists.
 
-2) Enter the username, password, and database name into the [cvsdb] section of
-the <VIEWVC_INSTALL_DIR>\viewvc.conf file.
+2) Enter the username, password, and database name into the [cvsdb]
+   section of the <VIEWVC_INSTALL_DIR>\viewvc.conf file.
 
 3) At the command prompt run
 
-   python bin\cvsdbadmin rebuild <repository>
+      python bin\cvsdbadmin rebuild <REPOSITORY>
 
-where <repository> is the path to your CVS repository.
+   where <REPOSITORY> is the path to your CVS repository.
 
-4) If you want the checkin database to be dynamically updated with every
-checkin, add the following line to your CVSROOT/loginfo file:
+4) If you want the checkin database to be dynamically updated with
+   every checkin, add the following line to your CVSROOT/loginfo file:
 
-   ALL python "<VIEWVC_INSTALL_DIR>\bin\loginfo-handler" %{sVv}
+      ALL python "<VIEWVC_INSTALL_DIR>\bin\loginfo-handler" %{sVv}
 
-If you decide not to enable dynamic updates, you can periodically refresh the
-database with "python bin\cvsdbadmin update <repository>"
+   If you decide not to enable dynamic updates, you can periodically
+   refresh the database with "python bin\cvsdbadmin update <REPOSITORY>"
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 CVSGRAPH
 
-To use CvsGraph with ViewVC, just put cvsgraph.exe in a directory on your
-system PATH and set the use_cvsgraph option to 1 in your viewvc.conf file.
+To use CvsGraph with ViewVC, just put cvsgraph.exe in a directory on
+your system PATH and set the use_cvsgraph option to 1 in your
+viewvc.conf file.
 
 The CvsGraph home page is http://www.akhphd.au.dk/~bertho/cvsgraph/.
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 DOCROOT OPTIMIZATION
 
 By default ViewVC serves up image and stylesheet files in
-<VIEWVC_INSTALL_DIR>\templates\docroot\ on its own instead of relying on the
-webserver to deliver them. This simplifies web server configuration, but is
-inefficient because it means the Python interpreter has to run each time one of
-these files is downloaded. This causes ViewVC pages to load more slowly,
-especially when ViewVC is running under CGI on Windows.
+<VIEWVC_INSTALL_DIR>\templates\docroot\ on its own instead of relying
+on the webserver to deliver them. This simplifies web server
+configuration, but is inefficient because it means the Python
+interpreter has to run each time one of these files is
+downloaded. This causes ViewVC pages to load more slowly, especially
+when ViewVC is running under CGI on Windows.
 
 To make things more efficient, you can make the
-<VIEWVC_INSTALL_DIR>\templates\docroot directory available on your web server
-and then set the "docroot" value in viewvc.conf to point to the web address of
-the directory.
+<VIEWVC_INSTALL_DIR>\templates\docroot directory available on your web
+server and then set the "docroot" value in viewvc.conf to point to the
+web address of the directory.
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 TROUBLESHOOTING
 
-- By far the most common cause of errors in ViewVC is failure to successfully
-  execute the programs it depends on (cvs, rlog, rcsdiff, co, enscript, sed,
-  and cvsgraph). To help deal with this problem, ViewVC includes a special
-  debugging mode that displays output from the programs it executes on every
-  web page. This allows you to see error messages and other information that
-  isn't normally visible. To enable the debugging mode, change line 23 of
+- By far the most common cause of errors in ViewVC is failure to
+  successfully execute the programs it depends on (cvs, rlog, rcsdiff,
+  co, enscript, sed, and cvsgraph). To help deal with this problem,
+  ViewVC includes a special debugging mode that displays output from
+  the programs it executes on every web page. This allows you to see
+  error messages and other information that isn't normally visible. To
+  enable the debugging mode, change line 23 of
   <VIEWVC_INSTALL_DIR>\lib\debug.py from:
 
-    SHOW_CHILD_PROCESSES = 0
+     SHOW_CHILD_PROCESSES = 0
 
   to:
 
-    SHOW_CHILD_PROCESSES = 1
+     SHOW_CHILD_PROCESSES = 1
 
-  Important: You may need to restart your web server before this change takes
-  effect. See "Changes made to..." later in this section.
+  Important: You may need to restart your web server before this
+  change takes effect. See "Changes made to..." later in this section.
 
 - If you see the following error:
 
-    error: (2, 'CreateProcess', The system cannot find the file specified.')
+     error: (2, 'CreateProcess', The system cannot find the file specified.')
 
-  it means that a program ViewVC has tried to execute could not be found by
-  Windows. The fix to this is usually to install the program if it isn't
-  already installed or to update the path to the program in viewvc.conf.
-  Enabling the SHOW_CHILD_PROCESSES mode as described above can provide helpful
-  diagnostic information such as the command line ViewVC is using to invoke the
-  program and the value of the PATH environment variable in the environment
-  ViewVC is running under.
-
-- A common cause of server errors under IIS is permissions problems. You need
-  to make sure that the virtual directory containing the CGI or ASP files has
-  script execution enabled. You also need to make sure that the web server user
-  accounts (IUSR_machine_name and IWAM_machine_name, where machine_name is your
-  computer name) have read and execute access to the .asp or .cgi stub scripts,
-  the ViewVC lib/ folder, the paths where external tools like cvs, rcs,
-  enscript, sed, and cvsgraph live, and the CVS repositories. NTFS auditing
-  makes it very easy to track down permissions problems. Also look for IIS
-  messages in the event log.
-
-- Certain Apache configurations may hide some environment variables from the
-  ViewVC CGI scripts and the programs they launch. You can see whether an
-  environment variable is visible from the CGI environment by enabling the
-  SHOW_CHILD_PROCESSES debug mode described above. You can force Apache to let
-  variables through with the PassEnv directive
+  it means that a program ViewVC has tried to execute could not be
+  found by Windows. The fix to this is usually to install the program
+  if it isn't already installed or to update the path to the program
+  in viewvc.conf.  Enabling the SHOW_CHILD_PROCESSES mode as described
+  above can provide helpful diagnostic information such as the command
+  line ViewVC is using to invoke the program and the value of the PATH
+  environment variable in the environment ViewVC is running under.
+
+- A common cause of server errors under IIS is permissions
+  problems. You need to make sure that the virtual directory
+  containing the CGI or ASP files has script execution enabled. You
+  also need to make sure that the web server user accounts
+  (IUSR_machine_name and IWAM_machine_name, where machine_name is your
+  computer name) have read and execute access to the .asp or .cgi stub
+  scripts, the ViewVC lib/ folder, the paths where external tools like
+  cvs, rcs, enscript, sed, and cvsgraph live, and the CVS
+  repositories. NTFS auditing makes it very easy to track down
+  permissions problems. Also look for IIS messages in the event log.
+
+- Certain Apache configurations may hide some environment variables
+  from the ViewVC CGI scripts and the programs they launch. You can
+  see whether an environment variable is visible from the CGI
+  environment by enabling the SHOW_CHILD_PROCESSES debug mode
+  described above. You can force Apache to let variables through with
+  the PassEnv directive
   (http://httpd.apache.org/docs/mod/mod_env.html#passenv).
 
-- Changes made to environment variables, ViewVC source files and the ViewVC
-  configuration file do not always take effect immediately. The table below
-  shows what actions you need to take after changing any of these things before
-  they will have an effect.
+- Changes made to environment variables, ViewVC source files and the
+  ViewVC configuration file do not always take effect immediately. The
+  table below shows what actions you need to take after changing any
+  of these things before they will have an effect.
 
 +----------------+----------------+----------------+-------------------------+
 |                | Environment    | ViewVC         | ViewVC                  |
@@ -317,164 +340,182 @@
 |                |                |                | OR                      |
 |                |                |                | reload(viewvc) in stub  |
 +----------------+----------------+----------------+-------------------------+
-  * If standalone.py was launched from a command prompt and you set the
-  environment variable through the control panel, you'll need to open a new
-  command prompt.
+     * If standalone.py was launched from a command prompt and you set
+       the environment variable through the control panel, you'll need to
+       open a new command prompt.
 
   Notes:
 
-  Under ASP, changes made to the stub scripts inside the web root do take
-  effect immediately, you only need to take additional action when you make
-  changes to the main source files in <VIEWVC_INSTALL_DIR>\lib
-
-  To "Unload ASP App", go to the IIS properties dialog for the application
-  directory containing the ViewVC .asp files (in Internet Services Manager).
-  Switch to the [Home] | [Virtual] Directory tab and click the "Unload" button
-  under "Application Settings".
+  Under ASP, changes made to the stub scripts inside the web root do
+  take effect immediately, you only need to take additional action
+  when you make changes to the main source files in <VIEWVC_INSTALL_DIR>\lib
+
+  To "Unload ASP App", go to the IIS properties dialog for the
+  application directory containing the ViewVC .asp files (in Internet
+  Services Manager).  Switch to the [Home] | [Virtual] Directory tab
+  and click the "Unload" button under "Application Settings".
 
-  To "reload(viewvc) in stub", put these lines in one of the ASP or Mod_Python
-  stub scripts:
+  To "reload(viewvc) in stub", put these lines in one of the ASP or
+  Mod_Python stub scripts:
 
-    import viewvc
-    reload (viewvc)
+     import viewvc
+     reload (viewvc)
 
   then load the page in a web browser.
 
-- If you have problems getting ViewVC to work with mod_python, you can first
-  make sure mod_python works standalone with the testing instructions at
+- If you have problems getting ViewVC to work with mod_python, you can
+  first make sure mod_python works standalone with the testing
+  instructions at
   http://www.modpython.org/live/current/doc-html/inst-testing.html.
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 KNOWN ISSUES
 
 - If you see ViewVC errors like
 
-    Error parsing rlog output. Expected RCS file "c:\cvsroot\dir\file,v", found
-    "c:\cvsroot\dir\RCS/file,v"
+     Error parsing rlog output. Expected RCS file
+    "c:\cvsroot\dir\file,v", found "c:\cvsroot\dir\RCS/file,v"
 
-  it's because your RCS utilities don't recognize the RCS file suffix and are
-  treating all files specified on the command line like working copies even
-  when they end in ",v". You can fix this by including the following string in
-  your RCSINIT environment variable:
+  it's because your RCS utilities don't recognize the RCS file suffix
+  and are treating all files specified on the command line like
+  working copies even when they end in ",v". You can fix this by
+  including the following string in your RCSINIT environment variable:
 
     -x,v
 
-  Important: You may need to reboot your computer before the environment
-  variable has an effect. See "Changes made to..." in the TROUBLESHOOTING
-  section.
-
-- The GNU RCS utilities won't work with repository files that use CVSNT's
-  unicode expansion mode (-ku). Files that use this mode will show up with an
-  "rlog error: unknown expand mode u" error message in ViewVC directory
-  listings. To work around this, you can set up ViewVC to use the CVSNT
-  executable (cvs.exe) or CVSNT RCS tools (co.exe, rlog.exe, and rcsdiff.exe)
-  instead of the GNU tools.
-
-- The standalone server will not run under Cygwin Python because it does not
-  support threads. ASP pages can't be run with Cygwin Python because it does
-  not support ActiveX. To use either of these features you should install a
-  native Python interpreter.
-
-- On Windows XP and Windows 2003 Server under IIS, enscript might give an error
-  like:
-
-    enscript: couldn't open input filter "states -f
-    "K:/gnuwin32/share/enscript/hl/enscript.st" -p
-    "C://.enscript;K:/gnuwin32/share/enscript/hl" -shtml -Dcolor=1
-    -Dstyle=emacs -Dlanguage=html -Dnum_input_files=1
-    -Ddocument_title="Enscript Output" -Dtoc=0 -" for file "": No error
-    no output generated
+  Important: You may need to reboot your computer before the
+  environment variable has an effect. See "Changes made to..." in the
+  TROUBLESHOOTING section.
+
+- The GNU RCS utilities won't work with repository files that use
+  CVSNT's unicode expansion mode (-ku). Files that use this mode will
+  show up with an "rlog error: unknown expand mode u" error message in
+  ViewVC directory listings. To work around this, you can set up
+  ViewVC to use the CVSNT executable (cvs.exe) or CVSNT RCS tools
+  (co.exe, rlog.exe, and rcsdiff.exe) instead of the GNU tools.
+
+- The standalone server will not run under Cygwin Python because it
+  does not support threads. ASP pages can't be run with Cygwin Python
+  because it does not support ActiveX. To use either of these features
+  you should install a native Python interpreter.
+
+- On Windows XP and Windows 2003 Server under IIS, enscript might give
+  an error like:
+
+     enscript: couldn't open input filter "states -f
+     "K:/gnuwin32/share/enscript/hl/enscript.st" -p
+     "C://.enscript;K:/gnuwin32/share/enscript/hl" -shtml -Dcolor=1
+     -Dstyle=emacs -Dlanguage=html -Dnum_input_files=1
+     -Ddocument_title="Enscript Output" -Dtoc=0 -" for file "": No error
+     no output generated
 
   The solution is to give read & execute permissions on cmd.exe to the
-  IUSR_computername and IWAM_computername user accounts. (Enscript uses cmd.exe
-  internally to launch its little helper program, states.exe).
-
-- By default, ASP will set session cookies at each page load. ViewVC does not
-  use these cookies and they can be safely disabled. You can do this by opening
-  the IIS properties dialog for the application directory containing the ViewVC
-  .asp files. Go to the [Home] | [Virtual] Directory tab and click the
-  "Configuration" button under "Application Settings". On the dialog that comes
-  up, uncheck "Enable Session State" under "App Options" -> "Application
-  Configuration".
-
-- Python support for ASP can be a little flaky. If you get strange errors, it
-  can sometimes help to uninstall and reinstall it with pyscript.py. A number
-  of people have also encountered a problem in ActivePython 2.2 where the first
-  loads of any Python ASP page would work, but subsequent loads of the same
-  page would always return nothing (leaving the screen blank). There were a
-  number of workarounds for this problem, but the fix is to download and
-  install the latest python win32 extensions from
+  IUSR_computername and IWAM_computername user accounts. (Enscript
+  uses cmd.exe internally to launch its little helper program,
+  states.exe).
+
+- By default, ASP will set session cookies at each page load. ViewVC
+  does not use these cookies and they can be safely disabled. You can
+  do this by opening the IIS properties dialog for the application
+  directory containing the ViewVC .asp files. Go to the [Home] |
+  [Virtual] Directory tab and click the "Configuration" button under
+  "Application Settings". On the dialog that comes up, uncheck "Enable
+  Session State" under "App Options" -> "Application Configuration".
+
+- Python support for ASP can be a little flaky. If you get strange
+  errors, it can sometimes help to uninstall and reinstall it with
+  pyscript.py. A number of people have also encountered a problem in
+  ActivePython 2.2 where the first loads of any Python ASP page would
+  work, but subsequent loads of the same page would always return
+  nothing (leaving the screen blank). There were a number of
+  workarounds for this problem, but the fix is to download and install
+  the latest python win32 extensions from
   http://sourceforge.net/projects/pywin32/
 
-- ViewVC can't convert timestamps on diff pages to local time when it is used
-  with CVSNT. This is caused by a CVSNT bug, which is described at
+- ViewVC can't convert timestamps on diff pages to local time when it
+  is used with CVSNT. This is caused by a CVSNT bug, which is
+  described at
   http://www.cvsnt.org/mantis/bug_view_page.php?bug_id=0000110
 
-- Old versions of CVSNT (2.0.11 and earlier) have a bug in their rlog emulation
-  which causes them to output truncated paths to RCS files. In ViewVC, this
-  causes errors like
-
-    Error parsing rlog output. Expected RCS file "c:\cvsroot\dir\file,v", found
-    "file,v"
-
-- Old versions of CVSNT (2.0.11 and earlier) have a bug in their standalone RCS
-  tools (rlog.exe, co.exe, and rcsdiff.exe) which causes them not to properly
-  interpret arguments with spaces. This can result in ViewVC errors in
-  repositories that have spaces in file or directory names. This bug only
-  occurs when ViewVC is configured to use the standalone utilities, not when it
-  uses cvs.exe directly as it does by default.
-
-- Old versions of CVSNT (1.11.1.3-76 and earlier) don't have any RCS emulation,
-  so they can't be used as RCS parsers for ViewVC.
-
-- Very old versions of CVSNT (1.11.1.3-57g and earlier) won't work reliably
-  with our loginfo handler because they have a bug which makes them escape
-  spaces and other special characters in filenames twice. This bug can result
-  in loginfo errors or invalid data being inserted into the database.
+- Old versions of CVSNT (2.0.11 and earlier) have a bug in their rlog
+  emulation which causes them to output truncated paths to RCS
+  files. In ViewVC, this causes errors like
+
+     Error parsing rlog output. Expected RCS file
+    "c:\cvsroot\dir\file,v", found "file,v"
+
+- Old versions of CVSNT (2.0.11 and earlier) have a bug in their
+  standalone RCS tools (rlog.exe, co.exe, and rcsdiff.exe) which
+  causes them not to properly interpret arguments with spaces. This
+  can result in ViewVC errors in repositories that have spaces in file
+  or directory names. This bug only occurs when ViewVC is configured
+  to use the standalone utilities, not when it uses cvs.exe directly
+  as it does by default.
+
+- Old versions of CVSNT (1.11.1.3-76 and earlier) don't have any RCS
+  emulation, so they can't be used as RCS parsers for ViewVC.
+
+- Very old versions of CVSNT (1.11.1.3-57g and earlier) won't work
+  reliably with our loginfo handler because they have a bug which
+  makes them escape spaces and other special characters in filenames
+  twice. This bug can result in loginfo errors or invalid data being
+  inserted into the database.
 
-- Old versions of Highlight (2.4.3 and earlier) will not show line numbers
-  for .txt files or files of unknown type even when the
+- Old versions of Highlight (2.4.3 and earlier) will not show line
+  numbers for .txt files or files of unknown type even when the
   "highlight_line_numbers" option is enabled.
 
-- Highlight versions 2.4.2 and 2.4.3 start line numbering for all file types
-  at 0 instead of 1 by default. A workaround is to make ViewVC pass an
-  explicit --line-number-start=1 option to Highlight
-
-- Highlight version 2.4.4 starts line numbering for .txt files at 0 instead of
-  1. It also misinterprets the --line-number-start option for those files,
-  starting numbering one number before whatever number is specified. Since this
-  behavior does not affect unknown file types, a simple workaround is just to
-  not pass a --syntax option to Highlight for plain text files (instead of
-  passing --syntax=txt).
+- Highlight versions 2.4.2 and 2.4.3 start line numbering for all file
+  types at 0 instead of 1 by default. A workaround is to make ViewVC
+  pass an explicit --line-number-start=1 option to Highlight
+
+- Highlight version 2.4.4 starts line numbering for .txt files at 0
+  instead of 1. It also misinterprets the --line-number-start option
+  for those files, starting numbering one number before whatever
+  number is specified. Since this behavior does not affect unknown
+  file types, a simple workaround is just to not pass a --syntax
+  option to Highlight for plain text files (instead of passing
+  --syntax=txt).
 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 THANKS
 
-- Bryan T. Vold for improving the original ViewCVS patch by adding support for
-  enscript and tarball generation.
+- Bryan T. Vold for improving the original ViewCVS patch by adding
+  support for enscript and tarball generation.
+
 - David Resnick for tracking down the cause of re_search failures in
   repositories with non-rcs files and for bringing a bug in
   sapi.AspFile.header() to my attention
-- Matt Bunch for finding a better way to address the ASP blank page problem,
-  and Keith D. Zimmerman for finding another workaround.
-- Rü Koch for reporting a bug in viewvc PATH_INFO parsing code with
-  Apache for Windows as well as Jelle Ouwerkerk and Steffen Yount for providing
-  fixes.
-- Nick Minutello and Rü Koch for providing workarounds for setting
-  enscript_library environment variable with apache. David Duminy for providing
-  the first bug report on this.
-- Gyula Faller and Tony Cook for independently coming up with CVSNT loginfo
-  handlers that accept spaces and don't rely on unix-style echo commands. Tony
-  Cook's patch also eliminated the dependency on cat.exe.
-- Mathieu Mazerolle for making the unix loginfo handler handle spaces in
-  filenames
-- Paul Russell for analyzing problems with new fields in CVSNT RCS files.
-  Terry Ninnis pgen com for coming up with a partial solution
-- Bo Berglund for tracking down the cause of a case-sensitivity issue that
-  could lead to problems in the commit database and for patiently working with
-  me to finally fix the CVSNT RCS fields problem and another problem with
-  enscript.
-- Ivo Roessling for finding and fixing a bug in the query page's commit
-  grouping code.
-- Keith D. Zimmerman for experimenting with enscript and finding some new ways
-  to make it work.
+
+- Matt Bunch for finding a better way to address the ASP blank page
+  problem, and Keith D. Zimmerman for finding another workaround.
+
+- Rü Koch for reporting a bug in viewvc PATH_INFO parsing code
+  with Apache for Windows as well as Jelle Ouwerkerk and Steffen Yount
+  for providing fixes.
+
+- Nick Minutello and Rü Koch for providing workarounds for
+  setting enscript_library environment variable with apache. David
+  Duminy for providing the first bug report on this.
+
+- Gyula Faller and Tony Cook for independently coming up with CVSNT
+  loginfo handlers that accept spaces and don't rely on unix-style
+  echo commands. Tony Cook's patch also eliminated the dependency on
+  cat.exe.
+
+- Mathieu Mazerolle for making the unix loginfo handler handle spaces
+  in filenames.
+
+- Paul Russell for analyzing problems with new fields in CVSNT RCS
+  files.  Terry Ninnis pgen com for coming up with a partial solution
+
+- Bo Berglund for tracking down the cause of a case-sensitivity issue
+  that could lead to problems in the commit database and for patiently
+  working with me to finally fix the CVSNT RCS fields problem and
+  another problem with enscript.
+
+- Ivo Roessling for finding and fixing a bug in the query page's
+  commit grouping code.
+
+- Keith D. Zimmerman for experimenting with enscript and finding some
+  new ways to make it work.

Modified: branches/VIEWCVS_DIST/www/index.html
==============================================================================
--- branches/VIEWCVS_DIST/www/index.html	(original)
+++ branches/VIEWCVS_DIST/www/index.html	Mon Nov  3 09:44:02 2008
@@ -21,16 +21,7 @@
 <div class="h2">
 <h2>Latest Release</h2>
 
-<p>The most recent release of ViewVC is: <strong>1.0.4</strong></p>
-
-</div>
-
-<div class="h2">
-<h2>New IRC Channel for ViewVC</h2>
-
-<p>Use your favorite IRC client to pop into <tt><a
-   href="irc://irc.freenode.net/viewvc">#viewvc</a></tt> on
-   irc.freenode.net.</p>
+<p>The most recent release of ViewVC is: <strong>1.0.7</strong></p>
 
 </div>
 
@@ -73,6 +64,26 @@
 </div>
 
 <div class="h2">
+<h2>Wanna Talk About ViewVC?</h2>
+
+<p>If you have questions about ViewVC &mdash; how to configure it, if
+   some behavior you are seeing is expected or not, and so on &mdash;
+   send email to our users list: <a
+   href="mailto:users viewvc tigris org"
+   >users viewvc tigris org</a>.</p>
+
+<p>If you'd like to discuss the actual development of ViewVC itself,
+   or submit a patch to ViewVC's sources, you can do so on our
+   development list: <a href="mailto:dev viewvc tigris org"
+   >dev viewvc tigris org</a>.</p>
+
+<p>Finally, if you prefer realtime chatter, use your favorite IRC
+   client to pop into <tt><a href="irc://irc.freenode.net/viewvc"
+   >#viewvc</a></tt> on irc.freenode.net.</p>
+
+</div>
+
+<div class="h2">
 <h2>Screenshots</h2>
 
 <p>Who needs screenshots when you can visit and interact with running



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]