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

please unblock trac 0.11.1-2



Hello Release Team!

Trac upstream launched 0.11.1 a few weeks ago and is siting in unstable
for 14 days (previously was in experimental).
Package does not have any reported bugs and closes some.

But ... is has a big diff (of source code) to the previous version.
(debdiff and source code diff attached attached)

Upstream states: "Trac 0.11.1 contains a number of bug fixes and minor
enhancements."

Relevant debian changelog entries:

* Added dh_link to debian/rules Closes: #494003.
* Adding $(PYVER) in rules also Closes: #493079.
* Trac 0.11 also seems to close old bugs.
  ( Closes: #436293, #400774, #435321 ).
* Patch setup.py to install the contrib dir ( Closes: #495019 )

Bugs closed upstream:
http://trac.edgewall.org/query?status=closed&group=resolution&milestone=0.11.1

thank you

Luis Matos


[The following lists of changes regard files as different if they have
different names, permissions or owners.]

Files in second .deb but not in first
-------------------------------------
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/bugzilla2trac.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/checkwiki.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/emailfilter.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/htdigest.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/htpasswd.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/migrateticketmodel.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/rpm/installscript
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/rpm/makerpm
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/sourceforge2trac.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/trac-post-commit-hook.cmd
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/README
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/enterprise-workflow.ini
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/migrate_original_to_basic.py
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/opensource-workflow.ini
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/showworkflow
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/simple-workflow.ini
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/trivial-workflow.ini
-rw-r--r--  root/root   /usr/share/doc/trac/contrib/workflow/workflow_parser.py
-rw-r--r--  root/root   /usr/share/lintian/overrides/trac
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/SOURCES.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/requires.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.1.egg-info/top_level.txt
lrwxrwxrwx  root/root   /usr/share/pyshared/trac/htdocs/js/jquery.js -> ../../../../javascript/jquery/jquery.js

Files in first .deb but not in second
-------------------------------------
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/SOURCES.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/requires.txt
-rw-r--r--  root/root   /usr/share/pyshared/Trac-0.11.egg-info/top_level.txt

Control files: lines which differ (wdiff format)
------------------------------------------------
Installed-Size: [-2896-] {+3044+}
Suggests: python-docutils, {+libapache2-mod-wsgi |+} libapache2-mod-python, [-libapache2-mod-wsgi,-] python-psycopg2, python-mysqldb (>= 1.2.1), python-textile (>= 2.0), trac-git, trac-spamfilter, [-trac-bzr,-] {+trac-bzr (>= 0.2+bzr45),+} trac-mercurial (>= 0.11.0.4)
Version: [-0.11-3-] {+0.11.1-2+}
trac (0.11.1-2) unstable; urgency=low

  * Upstream version 
    "Trac 0.11.1 contains a number of bug fixes and minor enhancements."
  * Patch setup.py to install the contrib dir ( Closes: #495019 )
  * Modified compatible version of trac-bzr so that trac 0.11.1 an be
    used with the current trac-bzr version.

 -- Luis Matos <gass@otiliamatos.ath.cx>  Sat, 16 Aug 2008 00:08:30 +0100

trac (0.11.1-1) experimental; urgency=low

  * New upstream version
  * Added dh_link to debian/rules Closes: #494003.
  * Adding $(PYVER) in rules also Closes: #493079.
  * Trac 0.11 also seems to close old bugs. 
    ( Closes: #436293, #400774, #435321 ).

 -- Luis Matos <gass@otiliamatos.ath.cx>  Thu, 07 Aug 2008 02:06:25 +0100

trac (0.11+svn7384-1) experimental; urgency=low

  * updated SOURCES.txt for the svn revision version
  * Updated patch 15_remove_jquery_file for jquery 1.2.6
  * Updated source to revision 7384
  * Added a version dependency on trac-bzr because 0.2 is not trac 0.11
    compatible.
  * Changed debian/control because trac supports both mod-python and
    mod-wsgi.
  * Dropped hardcoded python version. This will please bzed!
  * Added lintian overrides because of deploy handling the interpreter's path

 -- Luis Matos <gass@otiliamatos.ath.cx>  Thu, 24 Jul 2008 01:22:53 +0100

trac (0.11-3) unstable; urgency=low

  * Updated Readme.Debian - Thanks to W. Martin Borgert. Closes: #490926
  * added the coderanger's website as trac info source
  * Removed php-cli and clearsilver from suggests 
  * Upstream prefers psycopg2 for postgresql backend
  * Removed the jquery.js file, added a dependency for jquery
  * Updated the watch file since now trac packages start with a T
  * Added Homepage field in debian/control
  * Added a suggests on libapache2-mod-wsgi
  * Added me as Uploader so lintian won't complain about NMU's

 -- Luis Matos <gass@otiliamatos.ath.cx>  Mon, 21 Jul 2008 21:23:12 +0100

trac (0.11-2) unstable; urgency=low

  * Re-added python-setup-tools to build dependences. Closes: #490320 #468705
  * New upstream release Closes: 489727
  * Added sugestion for other vcs support available: git bazaar mercurial 
  * Added spamfilter plugin to sugests
  * Moved packaging from python-support to python-central
  * Added an entry to the NEWS about the cgi Closes: #490275
  * Updated 10_remove_trac_suffix_from_title patch to be used in 0.11

 -- Luis Matos <gass@otiliamatos.ath.cx>  Sun, 13 Jul 2008 23:46:20 +0100

trac (0.11-1) unstable; urgency=low

  [ Luis Matos ]
  * New Upstream release Closes: #463201
  * Does not work with PostgreSQL 8.3 - column type conflict (Closes: #464168)
  * s/python-setuptools/python-pkg-resources/ dependency (Closes: #468705) 
  * Updated Depends and Recommends to follow bug report. Closes: #487150

 -- Otavio Salvador <otavio@debian.org>  Tue, 08 Jul 2008 20:17:04 -0300

trac (0.11~rc1-1) experimental; urgency=low

  * New upstream release
  * Bump standards-version to 3.7.3; no changes required
  * Fix typos and break a long line on extended descriptions
  * Drop binary-post-install rule since it's not required anymore
  * Add a build-depends on python-setuptools
  * Add patch to remove ' - Trac' from title. Thanks Sam Hocevar
    <sam@zoy.org>. Closes: #482181
  * Drop 01_use_global_config.dpatch since Trac now offers a better and
    more flexible way to handle it
  * Add a NEWS note about the change regarting system-wide trac.ini
    handling

 -- Otavio Salvador <otavio@debian.org>  Sat, 07 Jun 2008 19:17:43 -0300

trac (0.10.4-2) unstable; urgency=low

  [ Otavio Salvador ]
  * Remove trac/siteconfig.py on package clean up
  * debian/control: Add XS-VCS-{Git,Browser} fields.
  * Change maintainer to Debian Trac Team and move Jesus to uploaders
    field.

  [ Luis Matos ]
  * Add php5-cli to Suggests field (Closes: #407118)
  * changed README.Debian. (Closes: #405903)
  * Trac shouls at least suggest postgresql-client or mysql-client
    (Closes: #393933)
  * Moved python-psycopg2 from depends to suggests
  * workaround for instance.__dict__ not accessible in restricted mode
    (Closes: #389826)

 -- Otavio Salvador <otavio@debian.org>  Mon, 04 Jun 2007 17:39:51 -0300

trac (0.10.4-1) unstable; urgency=low

  * New upstream release (Closes: #414134, #420219)
  * Fixed typo in debian/copyright file (Closes: #422409)
  
 --  Luis Matos <gass@otiliamatos.ath.cx>  Sun, 20 May 2007 22:46:56 +0100

trac (0.10.3-1) unstable; urgency=low

  * New upstream upload. Final 0.10.3 release that will hopefully make it into
    Debian 4.0 etch.
  * Add a NEWS entry for trac.ini being moved to /etc/trac/trac.ini 
    (Closes: #402937)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Wed, 13 Dec 2006 23:18:45 +0200

trac (0.10.3~rc1-1) unstable; urgency=low

  * This is the "Luis Matos" release. Without his help and dedication we would
    have never had it. Thanks.
  * New upstream release candidate.
  * Change the global path for the config file from /usr/share to /etc/trac
    (Closes: #393226, #337243, #386415, #400826)
  * The "NoSuchChangeset" problem is solved in this release (Closes: #400489)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Tue, 12 Dec 2006 00:20:33 +0200

trac (0.10.2-1) unstable; urgency=high

  * New upstream release, fixing 3 RC bugs introduced at 0.10.1, which were
    not triggered in normal conditions.
    - Fixes deadlock when using authz_file config option
    - Makes the CSRF code play nice with the XmlRpcPlugin
    - Fixes Timeline breakage after svn commit when using sqlite

 -- Jesus Climent <jesus.climent@hispalinux.es>  Mon, 13 Nov 2006 22:46:59 +0200

trac (0.10.1.svn4235-1) unstable; urgency=high

  * Subversion stable checkout to get a fix for Timeline and Browse Source.
  * Urgency high because this is an RC candidate.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Fri, 11 Nov 2006 14:25:36 +0200

trac (0.10.1-1) unstable; urgency=high

  * New Upstream Release (Closes: #397683)
  * Depend on python-psycopg2 (Closes: #397725)
  * Security fix, hence urgency=high. No DSA or CVS available yet.
  * Upstream changes (most important ones):
    - fixed CSRF vulnerability
    - better database handling
    - only TICKET_ADMIN can assign a passed milestone to a ticket
    - failed to upload attachments
    - more (comprehensive list can be found at
      http://trac.edgewall.org/query?status=closed&milestone=0.10.1)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Thu,  9 Nov 2006 11:53:53 +0200

trac (0.10-3) unstable; urgency=low

  * debian/control: changed the Conflicts: entry with a versioned oned
    (Closes: #393842, #384381)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Wed, 18 Oct 2006 11:47:41 +0300

trac (0.10-2) unstable; urgency=medium

  * debian/control: Added a Conflicts: against libapache2-mod-python2.3 to
    avoid breakage if using it through apache2 (Closes: #384381).
  * Urgency = high to get it back in etch.
  * Added missing changelog entries from Andres Salomon.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Mon, 16 Oct 2006 21:58:29 +0300

trac (0.10-1) unstable; urgency=low

  * New upstream release
  * Add a watch file
  * Add a NEWS entry to remember user that he needs to handle the upgrade
    byhand

 -- Otavio Salvador <otavio@debian.org>  Thu,  5 Oct 2006 13:51:10 -0300

trac (0.10~b1-1) experimental; urgency=low

  * New upstream release, finally.
  * Incorporate new python policy magic (closes: #384969).

 -- Andres Salomon <dilinger@debian.org>  Wed, 30 Aug 2006 01:36:55 +0000

trac (0.9.99+0.10svn20060710-1) experimental; urgency=low

  * New snapshot of 0.10dev (revision 3519).  Note that this includes
    the security update that was in the 0.9.6 release.

 -- Andres Salomon <dilinger@debian.org>  Mon, 10 Jul 2006 15:36:51 -0400

trac (0.9.99+0.10svn20060626-1) experimental; urgency=low

  * New snapshot of 0.10dev (revision 3488).

 -- Andres Salomon <dilinger@debian.org>  Mon, 26 Jun 2006 17:33:41 -0400

trac (0.9.99+0.10svn20060610-1) experimental; urgency=low

  * New upstream release; stick a snapshot of 0.10dev (revision 3390) into
    experimental (closes: #370657).

 -- Andres Salomon <dilinger@debian.org>  Sat, 10 Jun 2006 18:29:25 -0400

trac (0.9.6-3) unstable; urgency=low

  * Make the python-support build-dep-indep a normal build-depends, and
    drop the python dep (python-support pulls in python).
  * Reset permissions on wikitoolbar.js during build.
  * Drop old usr/lib/python2.3/site-packages/trac/ path from package, which
    cdbs seemed to be picking up for some reason (closes: #385166).

 -- Andres Salomon <dilinger@debian.org>  Wed, 30 Aug 2006 01:53:25 +0000

trac (0.9.6-2) unstable; urgency=low

  * Upgraded to the new Python policy (Closes: #380977)
  * Standards updated to 3.7.2, no changes needed.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Thu, 10 Aug 2006 21:41:04 +0300

trac (0.9.6-1) unstable; urgency=high

  * New upstream release.
  * Security upload, hence urgency set to high.
    - Fixed reStructuredText breach of privacy and denial of service
      vulnerability found by Felix Wiemann.
    - trac-post-commit-hook fix.
  * Added -f to rm to enforce removal of file, even if it does not exist.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Thu,  6 Jul 2006 23:28:04 +0300

trac (0.9.5-2) unstable; urgency=low

  * Add myself to uploaders.
  * Ack NMU; thanks Lars!
  * Drop debian-specific manpages; upstream already includes them.  Allow
    debhelper to create manpage directory, as well.
  * Change the path for test.py in debian/rules to match regardless of
    the python version.
  * Fix grammar errors in README.Debian; thanks to Micah Anderson for the
    patch (closes: #372188).

 -- Andres Salomon <dilinger@debian.org>  Sat, 10 Jun 2006 05:44:19 +0000

trac (0.9.5-1.1) unstable; urgency=low

  * Non-maintainer upload.
  * Fix debian/rules clean target so it doesn't break by trying to remove
    files even when they don't exist. Closes: #366827.
  * Updated build dependency for debhelper to be at leat 4.1.0, since that
    is required for cdbs's debhelper.mk to work (according to linda, at
    least).

 -- Lars Wirzenius <liw@iki.fi>  Sun, 21 May 2006 07:41:47 +0300

trac (0.9.5-1) unstable; urgency=high

  * New upstream release.
  * Security upload, hence urgency set to HIGH.
    - Fixed wiki macro XSS vulnerability.
    - Smaller memory usage when accessing subversion history.
    - Fixed issue with incorrectly generated urls when installed behind a web
      proxy.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Tue, 18 Apr 2006 20:04:25 +0000

trac (0.9.4-3) unstable; urgency=low

  * Set a proper python-subversion dependency (Closes: #356797)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Tue, 28 Mar 2006 18:49:06 +0000

trac (0.9.4-2) unstable; urgency=low

  * Revert db_default.py move. (Reopen: #332657)

 -- Otavio Salvador <otavio@debian.org>  Thu, 16 Feb 2006 10:45:24 -0200

trac (0.9.4-1) unstable; urgency=low

  * New upstream release.
  * Revert back compatibility level to 4 allowing easier backporting to
    Sarge.
  * Move db_default.py to /etc/trac allowing better user customizability
    (Closes: #332657).

 -- Otavio Salvador <otavio@debian.org>  Thu, 16 Feb 2006 10:12:23 -0200

trac (0.9.3-1) unstable; urgency=high

  * New upstream release.
  * Security update (thus urgengy high), fixing:
    - Fixed XSS vulnerabilities.
  * Also, fixes:
    - Timeline RSS feed validity issue resolved.
    - "trac-admin initenv" now handles empty repositories.
    - Textile unicode support.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Sun,  8 Jan 2006 20:24:43 +0000

trac (0.9.2-1) unstable; urgency=high

  * New upstream release.
  * Security update (urgency high), fixing:
    - an SQL injection vulnerability in the search module.
    - broken email ticket notifications.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Mon,  5 Dec 2005 19:36:02 +0000

trac (0.9.1-2) unstable; urgency=low

  * The new version solves upgrade problems from experimental 
    (Closes: #338122)
  * Tras was relicensed as with a modified BSD license. Change "copyright"
    accordingly.
  * Added ${python:Depends} to handle dependencies.
  * Compat updated to 5.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Thu,  1 Dec 2005 21:46:10 +0000

trac (0.9.1-1) unstable; urgency=HIGH

  * New upstream release
    - Fix a SQL injection security bug.
  
 -- Otavio Salvador <otavio@debian.org>  Thu,  1 Dec 2005 20:02:37 -0200

trac (0.9-1) unstable; urgency=low

  * New upstream release
    - 10_stolen_from_0.8-branch.patch: not need anymore.
    - 11_fix_misleading_error.patch: not need anymore.
    - Fix leak of temporary files; (Closes: #327803)
    - Apache configuration snip was improved; (Closes: #327206)
  * debian/control:
    - Add recommends of python2.3-setuptools to support plugins;
    - Add python2.3-pysqlite2 and python2.3-psycopg as alternatives to
      python2.3-sqlite;
    - Add suggests of libapache2-mod-python;
    - Add depends of python2.3 package to leave lintain happy.
  * debian/README.Debian: cite the need of a ready to use Subversion
    repository to setup Trac environment. (Closes: #327205)
  
 -- Otavio Salvador <otavio@debian.org>  Mon, 31 Oct 2005 18:02:30 -0200

trac (0.8.4-2) unstable; urgency=low

  * Add 10_stolen_from_0.8-branch.patch sync with r2041.
  * Add 11_fix_misleading_error.patch. (Closes: #320926)
  * Bumb Standards-Version to 3.6.2.
  
 -- Otavio Salvador <otavio@debian.org>  Tue,  2 Aug 2005 07:18:11 -0300

trac (0.8.4-1) unstable; urgency=critical

  * New upstream release.
    - Fixed file upload vulnerability. Trac could be tricked into uploading
      files outside the environment directory.

 -- Otavio Salvador <otavio@debian.org>  Sun, 19 Jun 2005 16:06:42 -0300

trac (0.8.3-1) unstable; urgency=low

  * New upstream release:
    - 01_sync_from_0.8-branch.diff droped since all patches was included
      on this release.
    - Support Subversion 1.2 was add (Closes: #314200)

 -- Otavio Salvador <otavio@debian.org>  Wed, 15 Jun 2005 19:57:06 -0300
  
trac (0.8.1-3) unstable; urgency=low

  * debian/patches/01_sync_from_0.8-branch.diff: 
    - Sync with r1520. This have all previous fixes and more.

 -- Otavio Salvador <otavio@debian.org>  Sun, 17 Apr 2005 19:09:59 -0300

trac (0.8.1-2) unstable; urgency=low

  * debian/rules:
    - Add support for patching in build process;
    - Include contrib/ on doc directory. (Closes: #298969)
  * debian/patches/01_sync_from_0.8-branch.diff: 
    - Added in sync with r1461. This include the fix for AssertionError
      raised when visiting WikiRestructuredTextLinks after clean install
      bug. (Closes: #301151)

 -- Otavio Salvador <otavio@debian.org>  Tue, 29 Mar 2005 20:44:07 -0300

trac (0.8.1-1) unstable; urgency=low

  * debian/control:
    - Add suggestion of enscript and python-docutils (Closes: #284094)
    - Change debhelper build-dependencie to build-depends-indep and set it
      to be (>= 4.0.0)
    - Recommends a http server instead of depends of it (Closes: #294674)
  * New upstream release (Closes: #298011)

 -- Otavio Salvador <otavio@debian.org>  Sat,  5 Mar 2005 17:29:21 -0300

trac (0.8-1) unstable; urgency=low

  * New upstream release (Closes: #282010)

 -- Otavio Salvador <otavio@debian.org>  Mon, 20 Dec 2004 22:49:48 -0200

trac (0.7.1-4) unstable; urgency=low

  * debian/control
    - changed the order httpd<>apache2
    - added python as build-dependency (Closes: #270180)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Mon,  6 Sep 2004 09:06:28 +0000

trac (0.7.1-3) unstable; urgency=low

  * debian/control: Depends: changed to include virtual httpd (Closes: #267890)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Sat, 28 Aug 2004 17:48:55 +0300

trac (0.7.1-2) unstable; urgency=low

  * debian/control:
    - Fixed typo (Closes: #266868)

 -- Jesus Climent <jesus.climent@hispalinux.es>  Thu, 19 Aug 2004 17:03:39 +0000

trac (0.7.1-1) unstable; urgency=low

  * First package upload.
  * Man pages taken from trunk.

 -- Jesus Climent <jesus.climent@hispalinux.es>  Mon, 19 Jul 2004 12:01:17 +0000
Index: branches/0.11-stable/RELEASE
===================================================================
--- branches/0.11-stable/RELEASE (revision 7232)
+++ branches/0.11-stable/RELEASE (revision 7447)
@@ -1,8 +1,23 @@
-Release Notes for Trac 0.11 Genshi Release
-==========================================
-June 22, 2008
-
-Highlights
-----------
+Release Notes for Trac 0.11.1 Genshi Release
+============================================
+August 6, 2008
+
+Trac 0.11.1 is a maintenance release and contains a number of bug fixes
+and minor enhancements. The following list contains only a few highlights:
+
+ * Improved DB connection handling (new connection pool)
+ * Better MySQL backend unicode support. "utf8" and "utf8_bin" is the
+   recommended database charset and collation settings.
+ * Fixes intermittent "constraint violation" and "invalid form token"
+   error messages.
+ * Fixes roadmap layout glitch in Firefox 3.
+ * Safer default umask value for tracd (can be set using --umask option)
+ * Better default PYTHON_EGG_CACHE value.
+
+The complete list of closed tickets can be found here:
+http://trac.edgewall.org/query?status=closed&milestone=0.11.1
+
+Highlights in 0.11
+------------------
  * New template engine for generating content (Genshi)
  * New configurable workflow in the ticket subsystem
Index: branches/0.11-stable/ChangeLog
===================================================================
--- branches/0.11-stable/ChangeLog (revision 7232)
+++ branches/0.11-stable/ChangeLog (revision 7447)
@@ -1,2 +1,20 @@
+Trac 0.11.1 (August 6, 2008)
+http://svn.edgewall.org/repos/trac/tags/trac-0.11.1
+
+ Trac 0.11.1 contains a number of bug fixes and minor enhancements.
+ The following list contains only a few highlights:
+
+ * Improved DB connection handling (new connection pool)
+ * Better MySQL backend unicode support. "utf8" and "utf8_bin" is the
+   recommended database charset and collation settings.
+ * Fixes intermittent "constraint violation" and "invalid form token"
+   error messages.
+ * Fixes roadmap layout glitch in Firefox 3.
+ * Safer default umask value for tracd (can be set using --umask option)
+ * Better default PYTHON_EGG_CACHE value.
+
+ The complete list of closed tickets can be found here:
+   http://trac.edgewall.org/query?status=closed&milestone=0.11.1
+
 Trac 0.11 'Genshi' (June 22, 2008)
 http://svn.edgewall.org/repos/trac/tags/trac-0.11
@@ -39,4 +57,20 @@
 
  See 0.11b2.
+
+Trac 0.10.5 (Jun 23, 2008)
+http://svn.edgewall.org/repos/trac/tags/trac-0.10.5
+
+ Trac 0.10.5 contains two security fixes and a couple of bug fixes.
+ The following list contains only a few highlights:
+ 
+ * Fixes a cross-site redirection vulnerability in the quickjump function
+   reported by Russ McRee.
+ * Fixes a wiki engine XSS vulnerability found by Nathan Collins.
+ * Added PostgreSQL 8.3 support.
+ * Fixes FineGrainedPermissions for scoped repositories.
+ * Fixes problem with repository syncing raising exceptions.
+
+ The complete list of closed tickets can be found here:
+   http://trac.edgewall.org/query?status=closed&milestone=0.10.5
 
 Trac 0.10.4 (April 20, 2007)
Index: branches/0.11-stable/THANKS
===================================================================
--- branches/0.11-stable/THANKS (revision 6690)
+++ branches/0.11-stable/THANKS (revision 7357)
@@ -5,4 +5,5 @@
  * Jani Averbach                  jaa@jaa.iki.fi
  * Juanma Barranquero             lektu@terra.es
+ * Remy Blank                     remy.blank@pobox.com
  * Christian Boos                 cboos@bct-technology.com
  * Rocky Burt                     rocky.burt@myrealbox.com
Index: branches/0.11-stable/trac/core.py
===================================================================
--- branches/0.11-stable/trac/core.py (revision 6904)
+++ branches/0.11-stable/trac/core.py (revision 7397)
@@ -39,4 +39,6 @@
         self.show_traceback = show_traceback
 
+    def __unicode__(self):
+        return unicode(self.message)
 
 class Interface(object):
Index: branches/0.11-stable/trac/attachment.py
===================================================================
--- branches/0.11-stable/trac/attachment.py (revision 6904)
+++ branches/0.11-stable/trac/attachment.py (revision 7357)
@@ -33,4 +33,5 @@
 from trac.perm import PermissionError, PermissionSystem, IPermissionPolicy
 from trac.resource import *
+from trac.search import search_to_sql, shorten_result
 from trac.util import get_reporter_id, create_unique_file, content_disposition
 from trac.util.datefmt import to_timestamp, utc
@@ -477,4 +478,28 @@
                                       descr)
    
+    def get_search_results(self, req, resource_realm, terms):
+        """Return a search result generator suitable for ISearchSource.
+        
+        Search results are attachments on resources of the given 
+        `resource_realm.realm` whose filename, description or author match 
+        the given terms.
+        """
+        db = self.env.get_db_cnx()
+        sql_query, args = search_to_sql(db, ['filename', 'description', 
+                                        'author'], terms)
+        cursor = db.cursor()
+        cursor.execute("SELECT id,time,filename,description,author "
+                       "FROM attachment "
+                       "WHERE type = %s "
+                       "AND " + sql_query, (resource_realm.realm, ) + args)
+        
+        for id, time, filename, desc, author in cursor:
+            attachment = resource_realm(id=id).child('attachment', filename)
+            if 'ATTACHMENT_VIEW' in req.perm(attachment):
+                yield (get_resource_url(self.env, attachment, req.href),
+                       get_resource_shortname(self.env, attachment),
+                       datetime.fromtimestamp(time, utc), author,
+                       shorten_result(desc, terms))
+    
     # IResourceManager methods
     
@@ -504,7 +529,6 @@
     def get_resource_description(self, resource, format=None, **kwargs):
         if format == 'compact':
-            return '%s:%s' % (get_resource_shortname(self.env,
-                                                     resource.parent),
-                              resource.filename)
+            return '%s (%s)' % (resource.id,
+                    get_resource_name(self.env, resource.parent))
         elif format == 'summary':
             return Attachment(self.env, resource).description
Index: branches/0.11-stable/trac/mimeview/api.py
===================================================================
--- branches/0.11-stable/trac/mimeview/api.py (revision 6904)
+++ branches/0.11-stable/trac/mimeview/api.py (revision 7414)
@@ -259,4 +259,5 @@
     'text/x-fortran':         ['f'],
     'text/x-haskell':         ['hs'],
+    'text/x-ini':             ['ini', 'cfg'],
     'text/x-javascript':      ['js'],
     'text/x-objc':            ['m', 'mm'],
@@ -809,5 +810,5 @@
         Note: `content` will usually be an object with a `read` method.
         """        
-        data = {'raw_href': url,
+        data = {'raw_href': url, 'size': length,
                 'max_file_size': self.max_preview_size,
                 'max_file_size_reached': False,
Index: branches/0.11-stable/trac/mimeview/tests/pygments.py
===================================================================
--- branches/0.11-stable/trac/mimeview/tests/pygments.py (revision 7128)
+++ branches/0.11-stable/trac/mimeview/tests/pygments.py (revision 7356)
@@ -103,4 +103,11 @@
         self.assertEqual("\n\n\n", t)
 
+    def test_empty_content(self):
+        """
+        A '\n' token is generated for an empty file, so we have to bypass
+        pygments when rendering empty files.
+        """
+        result = self.pygments.render(self.context, 'text/x-python', '')
+        self.assertEqual(None, result)
 
 def suite():
Index: branches/0.11-stable/trac/mimeview/patch.py
===================================================================
--- branches/0.11-stable/trac/mimeview/patch.py (revision 7032)
+++ branches/0.11-stable/trac/mimeview/patch.py (revision 7314)
@@ -118,4 +118,5 @@
                 line = lines.next()
                 if not line.startswith('+++ '):
+                    self.log.debug('expected +++ after ---, got '+line)
                     return None
 
@@ -206,4 +207,5 @@
                             sides = [last_side]
                         else:
+                            self.log.debug('expected +, - or \\, got '+command)
                             return None
                         for side in sides:
Index: branches/0.11-stable/trac/mimeview/pygments.py
===================================================================
--- branches/0.11-stable/trac/mimeview/pygments.py (revision 7058)
+++ branches/0.11-stable/trac/mimeview/pygments.py (revision 7356)
@@ -109,7 +109,8 @@
                        req.session.get('pygments_style', self.default_style))
         try:
-            mimetype = mimetype.split(';', 1)[0]
-            language = self._types[mimetype][0]
-            return self._generate(language, content)
+            if len(content) > 0:
+                mimetype = mimetype.split(';', 1)[0]
+                language = self._types[mimetype][0]
+                return self._generate(language, content)
         except (KeyError, ValueError):
             raise Exception("No Pygments lexer found for mime-type '%s'."
Index: branches/0.11-stable/trac/ticket/web_ui.py
===================================================================
--- branches/0.11-stable/trac/ticket/web_ui.py (revision 7200)
+++ branches/0.11-stable/trac/ticket/web_ui.py (revision 7383)
@@ -76,5 +76,23 @@
 
     default_component = Option('ticket', 'default_component', '',
-        """Default component for newly created tickets""")
+        """Default component for newly created tickets.""")
+
+    default_severity = Option('ticket', 'default_severity', '',
+        """Default severity for newly created tickets.""")
+
+    default_summary = Option('ticket', 'default_summary', '',
+        """Default summary (title) for newly created tickets.""")
+
+    default_description = Option('ticket', 'default_description', '',
+        """Default description for newly created tickets.""")
+
+    default_keywords = Option('ticket', 'default_keywords', '',
+        """Default keywords for newly created tickets.""")
+
+    default_owner = Option('ticket', 'default_owner', '',
+        """Default owner for newly created tickets.""")
+
+    default_cc = Option('ticket', 'default_cc', '',
+        """Default cc: list for newly created tickets.""")
 
     default_resolution = Option('ticket', 'default_resolution', 'fixed',
@@ -195,4 +213,9 @@
                        datetime.fromtimestamp(ts, utc), author,
                        shorten_result(desc, terms))
+        
+        # Attachments
+        for result in AttachmentModule(self.env).get_search_results(
+            req, ticket_realm, terms):
+            yield result        
 
     # ITimelineEventProvider methods
@@ -1048,17 +1071,20 @@
                 milestones = [(opt, m) for opt, m in milestones
                               if 'MILESTONE_VIEW' in req.perm(m.resource)]
-                open_milestones, closed_milestones = \
-                        partition([(opt, m.is_completed)
-                                   for opt, m in milestones],
-                                  (False, True))
+                def category(m):
+                    return m.is_completed and 1 or m.due and 2 or 3
+                open_due_milestones, open_not_due_milestones, \
+                    closed_milestones = partition([(opt, category(m))
+                        for opt, m in milestones], (2, 3, 1))
+                field['options'] = []
+                field['optgroups'] = [
+                    {'label': _('Open (by due date)'), 
+                        'options': open_due_milestones},
+                    {'label': _('Open (no due date)'), 
+                        'options': open_not_due_milestones},
+                ]
                 if ticket.exists and \
                        'TICKET_ADMIN' in req.perm(ticket.resource):
-                    field['options'] = []
-                    field['optgroups'] = [
-                        {'label': _('Open'), 'options': open_milestones},
-                        {'label': _('Closed'), 'options': closed_milestones},
-                    ]
-                else:
-                    field['options'] = open_milestones
+                    field['optgroups'].append(
+                        {'label': _('Closed'), 'options': closed_milestones})
                 milestone = Resource('milestone', ticket[name])
                 field['rendered'] = render_resource_link(self.env, context,
@@ -1122,5 +1148,6 @@
             if 'comment' not in req.args: # i.e. the comment was not yet edited
                 data['comment'] = '\n'.join(
-                    ['Replying to [%s %s]:' % (link, author)] +
+                    ['Replying to [%s %s]:' % (link,
+                                        obfuscate_email_address(author))] +
                     ['> %s' % line for line in original.splitlines()] + [''])
 
Index: branches/0.11-stable/trac/ticket/report.py
===================================================================
--- branches/0.11-stable/trac/ticket/report.py (revision 7219)
+++ branches/0.11-stable/trac/ticket/report.py (revision 7396)
@@ -289,7 +289,6 @@
 
         page = int(req.args.get('page', '1'))
-        limit = self.items_per_page
-        if req.args.get('format', '') == 'rss':
-            limit = self.items_per_page_rss
+        limit = {'rss': self.items_per_page_rss,
+                 'csv': 0, 'tab': 0}.get(format, self.items_per_page)
         offset = (page - 1) * limit
         user = req.args.get('USER', None)
@@ -302,4 +301,5 @@
 
         except Exception, e:
+            db.rollback()
             data['message'] = _('Report execution failed: %(error)s',
                                 error=to_unicode(e))
@@ -324,5 +324,5 @@
             for p in shown_pages:
                 pagedata.append([req.href.report(id, asc=asc, sort=sort_col, 
-                                                 USER=user, page=p),
+                                                 page=p, **args),
                                  None, str(p), _('Page %(num)d', num=p)])          
             fields = ['href', 'class', 'string', 'title']
@@ -462,5 +462,5 @@
                      'email_map': email_map})
 
-        if id:
+        if id and id != -1:
             self.add_alternate_links(req, args)
 
Index: branches/0.11-stable/trac/ticket/tests/functional.py
===================================================================
--- branches/0.11-stable/trac/ticket/tests/functional.py (revision 7174)
+++ branches/0.11-stable/trac/ticket/tests/functional.py (revision 7388)
@@ -6,5 +6,5 @@
 
 from trac.tests.functional import *
-from trac.util.datefmt import utc, format_date
+from trac.util.datefmt import utc, localtz, format_date
 
 
@@ -425,5 +425,5 @@
         tc.formvalue('modifymilestone', 'completed', True)
         cdate = datetime.now(tz=utc) + timedelta(days=1)
-        cdate_string = format_date(cdate, tzinfo=utc)
+        cdate_string = format_date(cdate, tzinfo=localtz)
         tc.formvalue('modifymilestone', 'completeddate', cdate_string)
         tc.submit('save')
@@ -916,7 +916,7 @@
             ticket_id = self._tester.create_ticket()
             self._tester.go_to_ticket(ticket_id)
-            tc.formvalue('propform', 'action', 'reassign')
+            tc.formvalue('propertyform', 'action', 'reassign')
             tc.find('reassign_reassign_owner')
-            tc.formvalue('propform', 'action_reassign_reassign_owner', 'user')
+            tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'user')
             tc.submit('submit')
         finally:
@@ -1031,5 +1031,5 @@
         ticketid = self._tester.create_ticket("regression test 5497a")
         self._tester.go_to_ticket(ticketid)
-        tc.formvalue('propform', 'field-component', 'regression5497')
+        tc.formvalue('propertyform', 'field-component', 'regression5497')
         tc.submit('submit')
         tc.find(regex_owned_by('user'))
@@ -1041,7 +1041,7 @@
         ticketid = self._tester.create_ticket("regression test 5497b")
         self._tester.go_to_ticket(ticketid)
-        tc.formvalue('propform', 'field-component', 'regression5497')
-        tc.formvalue('propform', 'action', 'reassign')
-        tc.formvalue('propform', 'action_reassign_reassign_owner', 'admin')
+        tc.formvalue('propertyform', 'field-component', 'regression5497')
+        tc.formvalue('propertyform', 'action', 'reassign')
+        tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'admin')
         tc.submit('submit')
         tc.notfind(regex_owned_by('user'))
@@ -1079,25 +1079,25 @@
         # make ids[1] be assigned
         self._tester.go_to_ticket(ids[1])
-        tc.formvalue('propform', 'action', 'reassign')
-        tc.formvalue('propform', 'action_reassign_reassign_owner', 'admin')
+        tc.formvalue('propertyform', 'action', 'reassign')
+        tc.formvalue('propertyform', 'action_reassign_reassign_owner', 'admin')
         tc.submit('submit')
         # make ids[2] be accepted
         self._tester.go_to_ticket(ids[2])
-        tc.formvalue('propform', 'action', 'accept')
+        tc.formvalue('propertyform', 'action', 'accept')
         tc.submit('submit')
         # make ids[3] be closed
         self._tester.go_to_ticket(ids[3])
-        tc.formvalue('propform', 'action', 'resolve')
-        tc.formvalue('propform', 'action_resolve_resolve_resolution', 'fixed')
+        tc.formvalue('propertyform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
         tc.submit('submit')
         # make ids[4] be reopened
         self._tester.go_to_ticket(ids[4])
-        tc.formvalue('propform', 'action', 'resolve')
-        tc.formvalue('propform', 'action_resolve_resolve_resolution', 'fixed')
+        tc.formvalue('propertyform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
         tc.submit('submit')
         # FIXME: we have to wait a second to avoid "IntegrityError: columns
         # ticket, time, field are not unique"
         time.sleep(1)
-        tc.formvalue('propform', 'action', 'reopen')
+        tc.formvalue('propertyform', 'action', 'reopen')
         tc.submit('submit')
         tc.show()
@@ -1169,5 +1169,5 @@
         self._tester.go_to_ticket(ticket_id)
         tc.find('delete ticket')
-        tc.formvalue('propform', 'action', 'delete')
+        tc.formvalue('propertyform', 'action', 'delete')
         tc.submit('submit')
 
@@ -1225,8 +1225,8 @@
         ticket_id = self._tester.create_ticket("RegressionTestTicket6879 a")
         self._tester.go_to_ticket(ticket_id)
-        tc.formvalue('propform', 'action', 'resolve')
-        tc.formvalue('propform', 'action_resolve_resolve_resolution', 'fixed')
+        tc.formvalue('propertyform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
         tc.submit('preview')
-        tc.formvalue('propform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action', 'resolve')
         tc.submit('preview')
 
@@ -1242,8 +1242,8 @@
         ticket_id = self._tester.create_ticket("RegressionTestTicket6879 b")
         self._tester.go_to_ticket(ticket_id)
-        tc.formvalue('propform', 'action', 'resolve')
-        tc.formvalue('propform', 'action_resolve_resolve_resolution', 'fixed')
+        tc.formvalue('propertyform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action_resolve_resolve_resolution', 'fixed')
         tc.submit('preview')
-        tc.formvalue('propform', 'action', 'resolve')
+        tc.formvalue('propertyform', 'action', 'resolve')
         tc.submit('submit')
 
Index: branches/0.11-stable/trac/ticket/tests/notification.py
===================================================================
--- branches/0.11-stable/trac/ticket/tests/notification.py (revision 6904)
+++ branches/0.11-stable/trac/ticket/tests/notification.py (revision 7431)
@@ -352,10 +352,10 @@
         """SMTP domain inclusion"""
         self.env.config.set('notification', 'admit_domains',
-                            'localdomain, mail.custom')
+                            'localdomain, server')
         ticket = Ticket(self.env)
         ticket['reporter'] = 'joeuser@example.com'
         ticket['summary'] = 'This is a summary'
-        ticket['cc'] = 'joe.user@localdomain, joe.user@mail.nocustom, ' \
-                       'joe.user@mail.custom'
+        ticket['cc'] = 'joe.user@localdomain, joe.user@unknown, ' \
+                       'joe.user@server'
         ticket.insert()
         tn = TicketNotifyEmail(self.env)
@@ -368,7 +368,7 @@
         # 'Cc' list should contain addresses with SMTP included domains
         self.failIf('joe.user@localdomain' not in cclist)
-        self.failIf('joe.user@mail.custom' not in cclist)
+        self.failIf('joe.user@server' not in cclist)
         # 'Cc' list should not contain non-FQDN domains
-        self.failIf('joe.user@mail.nocustom' in cclist)
+        self.failIf('joe.user@unknown' in cclist)
         self.failIf(len(cclist) != 2+2)
 
Index: branches/0.11-stable/trac/ticket/default_workflow.py
===================================================================
--- branches/0.11-stable/trac/ticket/default_workflow.py (revision 7200)
+++ branches/0.11-stable/trac/ticket/default_workflow.py (revision 7327)
@@ -266,5 +266,8 @@
                 resolutions = [val.name for val in
                                model.Resolution.select(self.env)]
-            assert(resolutions)
+            if not resolutions:
+                raise TracError(_("Your workflow attempts to set a resolution "
+                                  "but none is defined (configuration issue, "
+                                  "please contact your Trac admin)."))
             if len(resolutions) == 1:
                 control.append(tag('as %s' % resolutions[0]))
Index: branches/0.11-stable/trac/ticket/roadmap.py
===================================================================
--- branches/0.11-stable/trac/ticket/roadmap.py (revision 7215)
+++ branches/0.11-stable/trac/ticket/roadmap.py (revision 7372)
@@ -29,4 +29,5 @@
 from trac.perm import IPermissionRequestor
 from trac.resource import *
+from trac.search import ISearchSource, search_to_sql, shorten_result
 from trac.util.compat import set, sorted
 from trac.util.datefmt import parse_date, utc, to_timestamp, to_datetime, \
@@ -472,5 +473,6 @@
 
     implements(INavigationContributor, IPermissionRequestor, IRequestHandler,
-               ITimelineEventProvider, IWikiSyntaxProvider, IResourceManager)
+               ITimelineEventProvider, IWikiSyntaxProvider, IResourceManager,
+               ISearchSource)
  
     stats_provider = ExtensionOption('milestone', 'stats_provider',
@@ -643,5 +645,5 @@
             milestone.update()
             # eventually retarget opened tickets associated with the milestone
-            if 'retarget' in req.args:
+            if 'retarget' in req.args and completed:
                 cursor = db.cursor()
                 cursor.execute("UPDATE ticket SET milestone=%s WHERE "
@@ -805,2 +807,33 @@
         else:
             return desc
+
+    # ISearchSource methods
+
+    def get_search_filters(self, req):
+        if 'MILESTONE_VIEW' in req.perm:
+            yield ('milestone', _('Milestones'))
+
+    def get_search_results(self, req, terms, filters):
+        if not 'milestone' in filters:
+            return
+        db = self.env.get_db_cnx()
+        sql_query, args = search_to_sql(db, ['name', 'description'], terms)
+        cursor = db.cursor()
+        cursor.execute("SELECT name,due,completed,description "
+                       "FROM milestone "
+                       "WHERE " + sql_query, args)
+
+        milestone_realm = Resource('milestone')
+        for name, due, completed, description in cursor:
+            milestone = milestone_realm(id=name)
+            if 'MILESTONE_VIEW' in req.perm(milestone):
+                yield (get_resource_url(self.env, milestone, req.href),
+                       get_resource_name(self.env, milestone),
+                       datetime.fromtimestamp(
+                           completed or due or time(), utc),
+                       '', shorten_result(description, terms))
+        
+        # Attachments
+        for result in AttachmentModule(self.env).get_search_results(
+            req, milestone_realm, terms):
+            yield result
Index: branches/0.11-stable/trac/ticket/query.py
===================================================================
--- branches/0.11-stable/trac/ticket/query.py (revision 7184)
+++ branches/0.11-stable/trac/ticket/query.py (revision 7449)
@@ -49,8 +49,9 @@
 
 class Query(object):
+    substitutions = ['$USER']
 
     def __init__(self, env, report=None, constraints=None, cols=None,
                  order=None, desc=0, group=None, groupdesc=0, verbose=0,
-                 rows=None, page=1, max=None):
+                 rows=None, page=None, max=None):
         self.env = env
         self.id = report # if not None, it's the corresponding saved query
@@ -63,40 +64,35 @@
         self.items_per_page = QueryModule(self.env).items_per_page
 
+        # getting page number (default_page if unspecified)
+        if not page:
+            page = self.default_page
         try:
-            if not page:
-                page = self.default_page
-            page = int(page)
-            if page < 1:
+            self.page = int(page)
+            if self.page < 1:
                 raise ValueError()
         except ValueError:
-            raise TracError(_('Query page %(page)s is invalid.',
-                              page=page))
+            raise TracError(_('Query page %(page)s is invalid.', page=page))
 
         # max=0 signifies showing all items on one page
         # max=n will show precisely n items on all pages except the last
-        # max<0 is invalid (FIXME: wouldn't -1 also do for unlimited?)
+        # max<0 is invalid
         if max in ('none', ''):
             max = 0
 
+        if max is None: # meaning unspecified
+            max = self.items_per_page
         try:
-            if max is None: # meaning unspecified
-                max = self.items_per_page
-            max = int(max)
-            if max < 0:
+            self.max = int(max)
+            if self.max < 0:
                 raise ValueError()
         except ValueError:
             raise TracError(_('Query max %(max)s is invalid.', max=max))
         
-        self.page = 0
-        self.offset = 0
-        self.max = 0
-
-        if max == 0:
+        if self.max == 0:
             self.has_more_pages = False
+            self.offset = 0
         else:
             self.has_more_pages = True
-            self.page = page
-            self.offset = max * (page - 1)
-            self.max = max
+            self.offset = self.max * (self.page - 1)
 
         if rows == None:
@@ -140,5 +136,6 @@
             # from last char of `field`, get the mode of comparison
             mode, neg = '', ''
-            if field[-1] in ('~', '^', '$'):
+            if field[-1] in ('~', '^', '$') \
+                                and not field in cls.substitutions:
                 mode = field[-1]
                 field = field[:-1]
@@ -576,5 +573,6 @@
                     val = val[1:]
                 mode = ''
-                if val[:1] in ('~', '^', '$'):
+                if val[:1] in ('~', '^', '$') \
+                                    and not val in self.substitutions:
                     mode, val = val[:1], val[1:]
                 constraint['mode'] = (neg and '!' or '') + mode
@@ -780,4 +778,8 @@
         if isinstance(rows, basestring):
             rows = [rows]
+        format = req.args.get('format')
+        max = req.args.get('max')
+        if max is None and format in ('csv', 'tab'):
+            max = 0 # unlimited unless specified explicitly
         query = Query(self.env, req.args.get('report'),
                       constraints, cols, req.args.get('order'),
@@ -786,5 +788,5 @@
                       rows,
                       req.args.get('page'), 
-                      req.args.get('max'))
+                      max)
 
         if 'update' in req.args:
@@ -802,5 +804,4 @@
                      conversion[1], conversion[4], conversion[0])
 
-        format = req.args.get('format')
         if format:
             Mimeview(self.env).send_converted(req, 'trac.ticket.Query', query,
@@ -1018,4 +1019,7 @@
     (defaults to '''id''').
 
+    The `desc` parameter indicates whether the order of the tickets
+    should be reversed (defaults to '''false''').
+
     The `group` parameter sets the field used for grouping tickets
     (defaults to not being set).
@@ -1043,11 +1047,16 @@
             kwargs['format'] = argv[0]
 
+        if 'order' not in kwargs:
+            kwargs['order'] = 'id'
+        if 'max' not in kwargs:
+            kwargs['max'] = '0' # unlimited by default
+
         format = kwargs.pop('format', 'list').strip().lower()
         if format in ('list', 'compact'): # we need 'status' and 'summary'
             kwargs['col'] = '|'.join(['status', 'summary', 
                                       kwargs.get('col', '')])
+
         query_string = '&'.join(['%s=%s' % item
                                  for item in kwargs.iteritems()])
-
         query = Query.from_string(self.env, query_string)
 
Index: branches/0.11-stable/trac/ticket/notification.py
===================================================================
--- branches/0.11-stable/trac/ticket/notification.py (revision 6904)
+++ branches/0.11-stable/trac/ticket/notification.py (revision 7384)
@@ -17,10 +17,9 @@
 #
 
-import md5
-
 from trac import __version__
 from trac.core import *
 from trac.config import *
 from trac.notification import NotifyEmail
+from trac.util import md5
 from trac.util.datefmt import to_timestamp
 from trac.util.text import CRLF, wrap, to_unicode
@@ -285,5 +284,5 @@
                                int(self.ticket.id), to_timestamp(modtime),
                                rcpt.encode('ascii', 'ignore'))
-        dig = md5.new(s).hexdigest()
+        dig = md5(s).hexdigest()
         host = self.from_email[self.from_email.find('@') + 1:]
         msgid = '<%03d.%s@%s>' % (len(s), dig, host)
Index: branches/0.11-stable/trac/ticket/templates/report_delete.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/report_delete.html (revision 6357)
+++ branches/0.11-stable/trac/ticket/templates/report_delete.html (revision 7388)
@@ -14,8 +14,8 @@
       <h1>$report.title</h1>
       <form action="${href.report()}" method="post">
-        <input type="hidden" name="id" value="$report.id"/>
-        <input type="hidden" name="action" value="delete" />
         <p><strong>Are you sure you want to delete this report?</strong></p>
         <div class="buttons">
+          <input type="hidden" name="id" value="$report.id"/>
+          <input type="hidden" name="action" value="delete" />
           <input type="submit" name="cancel" value="Cancel"/>
           <input type="submit" value="Delete report"/>
Index: branches/0.11-stable/trac/ticket/templates/milestone_delete.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/milestone_delete.html (revision 6572)
+++ branches/0.11-stable/trac/ticket/templates/milestone_delete.html (revision 7388)
@@ -22,12 +22,15 @@
 
     <form id="edit" action="" method="post">
-      <input type="hidden" name="action" value="delete" />
-      <p><strong>Are you sure you want to delete this milestone?</strong></p>
-      <input type="checkbox" id="retarget" name="retarget" checked="checked" />
-      <label for="target">Retarget associated tickets to milestone</label>
-      <select name="target" id="target">
-        <option value="">None</option>
-        <option py:for="m in milestones">${m.name}</option>
-      </select>
+      <div>
+        <input type="hidden" name="action" value="delete" />
+        <p><strong>Are you sure you want to delete this milestone?</strong></p>
+        <input type="checkbox" id="retarget" name="retarget" checked="checked" />
+        <label for="target">Retarget associated tickets to milestone</label>
+        <select name="target" id="target">
+          <option value="">None</option>
+          <option py:for="m in milestones"
+                  py:if="m.name != milestone.name">${m.name}</option>
+        </select>
+      </div>
       <div class="buttons">
        <input type="submit" name="cancel" value="Cancel" />
Index: branches/0.11-stable/trac/ticket/templates/ticket.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/ticket.html (revision 7086)
+++ branches/0.11-stable/trac/ticket/templates/ticket.html (revision 7388)
@@ -65,5 +65,7 @@
               set to <em>${field.new}</em>
             </py:when>
-            <py:otherwise>deleted</py:otherwise>
+            <py:otherwise>
+              <em>${field.old}</em> deleted
+            </py:otherwise>
           </py:choose>
         </li>
@@ -176,5 +178,5 @@
               <form py:if="ticket.exists and ticket.description and
                            'TICKET_APPEND' in perm(ticket.resource)"
-                name="addreply"
+                id="addreply"
                 method="get" action="#comment">
                 <div class="inlinebuttons">
@@ -236,5 +238,5 @@
                     'TICKET_CHGPROP' in perm(ticket.resource) or
                     ('TICKET_CREATE' in perm(ticket.resource) and not ticket.id))"
-            action="${ticket.exists and href.ticket(ticket.id) or href.newticket()}" method="post" name="propform" id="propertyform">
+            action="${ticket.exists and href.ticket(ticket.id) or href.newticket()}" method="post" id="propertyform">
         <h3 py:if="ticket.exists"><a id="edit" onfocus="$('#comment').get(0).focus()">
             Add/Change #${ticket.id} ($ticket.summary)</a></h3>
Index: branches/0.11-stable/trac/ticket/templates/milestone_edit.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/milestone_edit.html (revision 7166)
+++ branches/0.11-stable/trac/ticket/templates/milestone_edit.html (revision 7388)
@@ -39,7 +39,7 @@
 
       <form id="edit" action="" method="post">
-        <input type="hidden" name="id" value="${milestone.name}" />
-        <input type="hidden" name="action" value="edit" />
         <div class="field">
+          <input type="hidden" name="id" value="${milestone.name}" />
+          <input type="hidden" name="action" value="edit" />
           <label>Name of the milestone:<br />
             <input type="text" id="name" name="name" size="32" value="${milestone.name or req.args.get('name')}" />
@@ -67,11 +67,10 @@
             <py:if test="milestones">
               <br/>
-              <input type="checkbox" id="retarget" name="retarget" checked="checked" />
-              <label>Retarget associated open tickets to milestone:
-                <select id="target" name="target" py:with="t = req.args.get('target')">
-                  <option value="">None</option>
-                  <option py:for="m in milestones" selected="${m.name == t or None}">${m.name}</option>
-                </select>
-              </label>
+              <input type="checkbox" id="retarget" name="retarget" checked="${not milestone.completed or None}" />
+              <label for="retarget">Retarget associated open tickets to milestone:</label>
+              <select id="target" name="target" py:with="t = req.args.get('target')">
+                <option value="">None</option>
+                <option py:for="m in milestones" selected="${m.name == t or None}">${m.name}</option>
+              </select>
             </py:if>
           </div>
Index: branches/0.11-stable/trac/ticket/templates/query.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/query.html (revision 6901)
+++ branches/0.11-stable/trac/ticket/templates/query.html (revision 7374)
@@ -14,5 +14,5 @@
           $("#groupdesc").enable(this.selectedIndex != 0)
         }).change();
-        $("fieldset legend").enableFolding(false);
+        $("fieldset legend.foldable").enableFolding(false);
         /* Hide the filters for saved queries. */
         if ( window.location.href.search(/[?&amp;]report=[0-9]+/) != -1 )
@@ -39,5 +39,5 @@
         <fieldset id="filters">
           <input py:if="'id' in query.constraints" type="hidden" name="id" value="${query.constraints['id']}" />
-          <legend>Filters</legend>
+          <legend class="foldable">Filters</legend>
           <table summary="Query filters">
             <tbody>
@@ -135,5 +135,5 @@
         <!--! Allow the user to decide what columns to include in the output of the query -->
         <fieldset id="columns">
-          <legend>Columns</legend>
+          <legend class="foldable">Columns</legend>
           <div>
             <py:for each="column in all_columns">
@@ -153,5 +153,5 @@
             <option></option>
             <option py:for="field_name, field in fields.items()"
-                    py:if="field.type in ('select', 'radio') or field_name == 'owner'"
+                    py:if="field.type in ('select', 'radio') or field_name in ('owner', 'reporter')"
                     selected="${field_name == query.group or None}"
                     value="${field_name}">${field.label}</option>
Index: branches/0.11-stable/trac/ticket/templates/report_view.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/report_view.html (revision 7166)
+++ branches/0.11-stable/trac/ticket/templates/report_view.html (revision 7293)
@@ -42,5 +42,5 @@
       </div>
       <py:if test="report.id != -1">
-        <h2 py:if="paginator.has_more_pages">
+        <h2 class="report-result" py:if="paginator.has_more_pages">
           Results <span class="numresults">(${paginator.displayed_items()})</span>
         </h2>
@@ -48,5 +48,5 @@
       </py:if>
       <py:for each="value_for_group, row_group in row_groups">
-        <h2 py:if="value_for_group">$value_for_group
+        <h2 class="report-result" py:if="value_for_group">$value_for_group
         <span class="numrows" py:with="cnt = len(row_group)">(${cnt or 'No'} match${cnt != 1 and 'es' or ''})</span></h2>
         <table class="listing ${report.id == -1 and 'reports' or 'tickets'}">
Index: branches/0.11-stable/trac/ticket/templates/query_results.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/query_results.html (revision 7131)
+++ branches/0.11-stable/trac/ticket/templates/query_results.html (revision 7293)
@@ -23,10 +23,10 @@
   </py:def>
   
-  <h2 py:if="paginator.has_more_pages">
+  <h2 class="report-result" py:if="paginator.has_more_pages">
     Results <span class="numresults">(${paginator.displayed_items()})</span>
   </h2>
   <xi:include py:if="paginator.show_index" href="page_index.html" />
   <py:for each="group_index, (groupname, results) in enumerate(groups)">
-    <h2 py:if="groupname">
+    <h2 class="report-result" py:if="groupname">
       ${fields[query.group].label}:
       ${query.group in ['owner', 'reporter'] and authorinfo(groupname) or groupname}
Index: branches/0.11-stable/trac/ticket/templates/ticket.rss
===================================================================
--- branches/0.11-stable/trac/ticket/templates/ticket.rss (revision 7147)
+++ branches/0.11-stable/trac/ticket/templates/ticket.rss (revision 7382)
@@ -33,8 +33,8 @@
               </py:when>
               <py:when test="value.new">
-                changed from &lt;em&gt;$value.old&lt;/em&gt; to &lt;em&gt;$value.new&lt;/em&gt;.
+                changed from &lt;em&gt;$value.old&lt;/em&gt; to &lt;em&gt;$value.new&lt;/em&gt;
               </py:when>
               <py:otherwise>
-                deleted
+                &lt;em&gt;$value.old&lt;/em&gt; deleted
               </py:otherwise>
             </py:choose>
Index: branches/0.11-stable/trac/ticket/templates/milestone_view.html
===================================================================
--- branches/0.11-stable/trac/ticket/templates/milestone_view.html (revision 7166)
+++ branches/0.11-stable/trac/ticket/templates/milestone_view.html (revision 7388)
@@ -51,7 +51,10 @@
                       selected="${grouped_by == group.name or None}" />
             </select>
-            <noscript><input type="submit" value="Update" /></noscript>
+            <input type="submit" value="Update" class="noscript" />
+            <script type="text/javascript">
+              jQuery(document).ready(function ($) { $(".noscript").attr("style", "display: none"); });
+            </script>
           </legend>
-          <table summary="Shows the milestone completion status grouped by ${grouped_by}">
+          <table py:if="groups" summary="Shows the milestone completion status grouped by ${grouped_by}">
             <tr py:for="group in groups">
               <th scope="row" py:choose="">
@@ -84,10 +87,14 @@
            class="buttons">
         <form py:if="'MILESTONE_MODIFY' in perm(milestone.resource)" method="get" action="" id="editmilestone">
-          <input type="hidden" name="action" value="edit" />
-          <input type="submit" value="Edit milestone" />
+          <div>
+            <input type="hidden" name="action" value="edit" />
+            <input type="submit" value="Edit milestone" />
+          </div>
         </form>
         <form py:if="'MILESTONE_DELETE' in perm(milestone.resource)" method="get" action="" id="deletemilestone">
-          <input type="hidden" name="action" value="delete" />
-          <input type="submit" value="Delete milestone" />
+          <div>
+            <input type="hidden" name="action" value="delete" />
+            <input type="submit" value="Delete milestone" />
+          </div>
         </form>
         ${attach_file_form(attachments)}
Index: branches/0.11-stable/trac/htdocs/js/query.js
===================================================================
--- branches/0.11-stable/trac/htdocs/js/query.js (revision 6636)
+++ branches/0.11-stable/trac/htdocs/js/query.js (revision 7284)
@@ -28,5 +28,5 @@
       if (mode && (getAncestorByTagName(mode, "tr") == tr)) {
         // Check whether there are more 'or' rows for this filter
-        var next = tr.nextSibling;
+        var next = $(tr).next()[0];
         if (next && (next.className == propertyName)) {
           function getChildElementAt(e, idx) {
Index: branches/0.11-stable/trac/htdocs/js/jquery.js
===================================================================
--- branches/0.11-stable/trac/htdocs/js/jquery.js (revision 6577)
+++ branches/0.11-stable/trac/htdocs/js/jquery.js (revision 7315)
@@ -1,4 +1,4 @@
 /*
- * jQuery 1.2.3 - New Wave Javascript
+ * jQuery 1.2.6 - New Wave Javascript
  *
  * Copyright (c) 2008 John Resig (jquery.com)
@@ -6,6 +6,6 @@
  * and GPL (GPL-LICENSE.txt) licenses.
  *
- * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
- * $Rev: 4663 $
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
  */
-eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(J(){7(1e.3N)L w=1e.3N;L E=1e.3N=J(a,b){K 1B E.2l.4T(a,b)};7(1e.$)L D=1e.$;1e.$=E;L u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;L G=/^.[^:#\\[\\.]*$/;E.1n=E.2l={4T:J(d,b){d=d||T;7(d.15){6[0]=d;6.M=1;K 6}N 7(1o d=="25"){L c=u.2O(d);7(c&&(c[1]||!b)){7(c[1])d=E.4a([c[1]],b);N{L a=T.5J(c[3]);7(a)7(a.2w!=c[3])K E().2s(d);N{6[0]=a;6.M=1;K 6}N d=[]}}N K 1B E(b).2s(d)}N 7(E.1q(d))K 1B E(T)[E.1n.21?"21":"3U"](d);K 6.6E(d.1k==1M&&d||(d.5h||d.M&&d!=1e&&!d.15&&d[0]!=10&&d[0].15)&&E.2I(d)||[d])},5h:"1.2.3",87:J(){K 6.M},M:0,22:J(a){K a==10?E.2I(6):6[a]},2F:J(b){L a=E(b);a.54=6;K a},6E:J(a){6.M=0;1M.2l.1g.1i(6,a);K 6},R:J(a,b){K E.R(6,a,b)},4X:J(b){L a=-1;6.R(J(i){7(6==b)a=i});K a},1J:J(c,a,b){L d=c;7(c.1k==4e)7(a==10)K 6.M&&E[b||"1J"](6[0],c)||10;N{d={};d[c]=a}K 6.R(J(i){Q(c 1p d)E.1J(b?6.W:6,c,E.1l(6,d[c],b,i,c))})},1j:J(b,a){7((b==\'27\'||b==\'1R\')&&2M(a)<0)a=10;K 6.1J(b,a,"2o")},1u:J(b){7(1o b!="3V"&&b!=V)K 6.4x().3t((6[0]&&6[0].2i||T).5r(b));L a="";E.R(b||6,J(){E.R(6.3p,J(){7(6.15!=8)a+=6.15!=1?6.6K:E.1n.1u([6])})});K a},5m:J(b){7(6[0])E(b,6[0].2i).5k().3o(6[0]).2c(J(){L a=6;2b(a.1C)a=a.1C;K a}).3t(6);K 6},8w:J(a){K 6.R(J(){E(6).6z().5m(a)})},8p:J(a){K 6.R(J(){E(6).5m(a)})},3t:J(){K 6.3O(18,P,S,J(a){7(6.15==1)6.38(a)})},6q:J(){K 6.3O(18,P,P,J(a){7(6.15==1)6.3o(a,6.1C)})},6o:J(){K 6.3O(18,S,S,J(a){6.1a.3o(a,6)})},5a:J(){K 6.3O(18,S,P,J(a){6.1a.3o(a,6.2B)})},3h:J(){K 6.54||E([])},2s:J(b){L c=E.2c(6,J(a){K E.2s(b,a)});K 6.2F(/[^+>] [^+>]/.17(b)||b.1f("..")>-1?E.57(c):c)},5k:J(e){L f=6.2c(J(){7(E.14.1d&&!E.3E(6)){L a=6.69(P),4Y=T.3s("1x");4Y.38(a);K E.4a([4Y.3d])[0]}N K 6.69(P)});L d=f.2s("*").4R().R(J(){7(6[F]!=10)6[F]=V});7(e===P)6.2s("*").4R().R(J(i){7(6.15==3)K;L c=E.O(6,"2R");Q(L a 1p c)Q(L b 1p c[a])E.16.1b(d[i],a,c[a][b],c[a][b].O)});K f},1E:J(b){K 6.2F(E.1q(b)&&E.3y(6,J(a,i){K b.1P(a,i)})||E.3e(b,6))},56:J(b){7(b.1k==4e)7(G.17(b))K 6.2F(E.3e(b,6,P));N b=E.3e(b,6);L a=b.M&&b[b.M-1]!==10&&!b.15;K 6.1E(J(){K a?E.33(6,b)<0:6!=b})},1b:J(a){K!a?6:6.2F(E.37(6.22(),a.1k==4e?E(a).22():a.M!=10&&(!a.12||E.12(a,"3u"))?a:[a]))},3H:J(a){K a?E.3e(a,6).M>0:S},7j:J(a){K 6.3H("."+a)},5O:J(b){7(b==10){7(6.M){L c=6[0];7(E.12(c,"2k")){L e=c.3T,5I=[],11=c.11,2X=c.U=="2k-2X";7(e<0)K V;Q(L i=2X?e:0,2f=2X?e+1:11.M;i<2f;i++){L d=11[i];7(d.2p){b=E.14.1d&&!d.9J.1A.9y?d.1u:d.1A;7(2X)K b;5I.1g(b)}}K 5I}N K(6[0].1A||"").1r(/\\r/g,"")}K 10}K 6.R(J(){7(6.15!=1)K;7(b.1k==1M&&/5u|5t/.17(6.U))6.3k=(E.33(6.1A,b)>=0||E.33(6.31,b)>=0);N 7(E.12(6,"2k")){L a=b.1k==1M?b:[b];E("98",6).R(J(){6.2p=(E.33(6.1A,a)>=0||E.33(6.1u,a)>=0)});7(!a.M)6.3T=-1}N 6.1A=b})},3q:J(a){K a==10?(6.M?6[0].3d:V):6.4x().3t(a)},6S:J(a){K 6.5a(a).1V()},6Z:J(i){K 6.2K(i,i+1)},2K:J(){K 6.2F(1M.2l.2K.1i(6,18))},2c:J(b){K 6.2F(E.2c(6,J(a,i){K b.1P(a,i,a)}))},4R:J(){K 6.1b(6.54)},O:J(d,b){L a=d.23(".");a[1]=a[1]?"."+a[1]:"";7(b==V){L c=6.5n("8P"+a[1]+"!",[a[0]]);7(c==10&&6.M)c=E.O(6[0],d);K c==V&&a[1]?6.O(a[0]):c}N K 6.1N("8K"+a[1]+"!",[a[0],b]).R(J(){E.O(6,d,b)})},35:J(a){K 6.R(J(){E.35(6,a)})},3O:J(g,f,h,d){L e=6.M>1,3n;K 6.R(J(){7(!3n){3n=E.4a(g,6.2i);7(h)3n.8D()}L b=6;7(f&&E.12(6,"1O")&&E.12(3n[0],"4v"))b=6.3S("1U")[0]||6.38(6.2i.3s("1U"));L c=E([]);E.R(3n,J(){L a=e?E(6).5k(P)[0]:6;7(E.12(a,"1m")){c=c.1b(a)}N{7(a.15==1)c=c.1b(E("1m",a).1V());d.1P(b,a)}});c.R(6A)})}};E.2l.4T.2l=E.2l;J 6A(i,a){7(a.3Q)E.3P({1c:a.3Q,3l:S,1H:"1m"});N E.5g(a.1u||a.6x||a.3d||"");7(a.1a)a.1a.34(a)}E.1s=E.1n.1s=J(){L b=18[0]||{},i=1,M=18.M,5c=S,11;7(b.1k==8d){5c=b;b=18[1]||{};i=2}7(1o b!="3V"&&1o b!="J")b={};7(M==1){b=6;i=0}Q(;i<M;i++)7((11=18[i])!=V)Q(L a 1p 11){7(b===11[a])6w;7(5c&&11[a]&&1o 11[a]=="3V"&&b[a]&&!11[a].15)b[a]=E.1s(b[a],11[a]);N 7(11[a]!=10)b[a]=11[a]}K b};L F="3N"+(1B 3v()).3L(),6t=0,5b={};L H=/z-?4X|86-?84|1w|6k|7Z-?1R/i;E.1s({7Y:J(a){1e.$=D;7(a)1e.3N=w;K E},1q:J(a){K!!a&&1o a!="25"&&!a.12&&a.1k!=1M&&/J/i.17(a+"")},3E:J(a){K a.1F&&!a.1h||a.28&&a.2i&&!a.2i.1h},5g:J(a){a=E.3g(a);7(a){L b=T.3S("6f")[0]||T.1F,1m=T.3s("1m");1m.U="1u/4m";7(E.14.1d)1m.1u=a;N 1m.38(T.5r(a));b.38(1m);b.34(1m)}},12:J(b,a){K b.12&&b.12.2E()==a.2E()},1T:{},O:J(c,d,b){c=c==1e?5b:c;L a=c[F];7(!a)a=c[F]=++6t;7(d&&!E.1T[a])E.1T[a]={};7(b!=10)E.1T[a][d]=b;K d?E.1T[a][d]:a},35:J(c,b){c=c==1e?5b:c;L a=c[F];7(b){7(E.1T[a]){2V E.1T[a][b];b="";Q(b 1p E.1T[a])1Q;7(!b)E.35(c)}}N{1S{2V c[F]}1X(e){7(c.52)c.52(F)}2V E.1T[a]}},R:J(c,a,b){7(b){7(c.M==10){Q(L d 1p c)7(a.1i(c[d],b)===S)1Q}N Q(L i=0,M=c.M;i<M;i++)7(a.1i(c[i],b)===S)1Q}N{7(c.M==10){Q(L d 1p c)7(a.1P(c[d],d,c[d])===S)1Q}N Q(L i=0,M=c.M,1A=c[0];i<M&&a.1P(1A,i,1A)!==S;1A=c[++i]){}}K c},1l:J(b,a,c,i,d){7(E.1q(a))a=a.1P(b,i);K a&&a.1k==51&&c=="2o"&&!H.17(d)?a+"2S":a},1t:{1b:J(c,b){E.R((b||"").23(/\\s+/),J(i,a){7(c.15==1&&!E.1t.3Y(c.1t,a))c.1t+=(c.1t?" ":"")+a})},1V:J(c,b){7(c.15==1)c.1t=b!=10?E.3y(c.1t.23(/\\s+/),J(a){K!E.1t.3Y(b,a)}).6a(" "):""},3Y:J(b,a){K E.33(a,(b.1t||b).3X().23(/\\s+/))>-1}},68:J(b,c,a){L e={};Q(L d 1p c){e[d]=b.W[d];b.W[d]=c[d]}a.1P(b);Q(L d 1p c)b.W[d]=e[d]},1j:J(d,e,c){7(e=="27"||e=="1R"){L b,46={43:"4W",4U:"1Z",19:"3D"},3c=e=="27"?["7O","7M"]:["7J","7I"];J 5E(){b=e=="27"?d.7H:d.7F;L a=0,2N=0;E.R(3c,J(){a+=2M(E.2o(d,"7E"+6,P))||0;2N+=2M(E.2o(d,"2N"+6+"5X",P))||0});b-=24.7C(a+2N)}7(E(d).3H(":4d"))5E();N E.68(d,46,5E);K 24.2f(0,b)}K E.2o(d,e,c)},2o:J(e,k,j){L d;J 3x(b){7(!E.14.2d)K S;L a=T.4c.4K(b,V);K!a||a.4M("3x")==""}7(k=="1w"&&E.14.1d){d=E.1J(e.W,"1w");K d==""?"1":d}7(E.14.2z&&k=="19"){L c=e.W.50;e.W.50="0 7r 7o";e.W.50=c}7(k.1D(/4g/i))k=y;7(!j&&e.W&&e.W[k])d=e.W[k];N 7(T.4c&&T.4c.4K){7(k.1D(/4g/i))k="4g";k=k.1r(/([A-Z])/g,"-$1").2h();L h=T.4c.4K(e,V);7(h&&!3x(e))d=h.4M(k);N{L f=[],2C=[];Q(L a=e;a&&3x(a);a=a.1a)2C.4J(a);Q(L i=0;i<2C.M;i++)7(3x(2C[i])){f[i]=2C[i].W.19;2C[i].W.19="3D"}d=k=="19"&&f[2C.M-1]!=V?"2H":(h&&h.4M(k))||"";Q(L i=0;i<f.M;i++)7(f[i]!=V)2C[i].W.19=f[i]}7(k=="1w"&&d=="")d="1"}N 7(e.4n){L g=k.1r(/\\-(\\w)/g,J(a,b){K b.2E()});d=e.4n[k]||e.4n[g];7(!/^\\d+(2S)?$/i.17(d)&&/^\\d/.17(d)){L l=e.W.26,3K=e.3K.26;e.3K.26=e.4n.26;e.W.26=d||0;d=e.W.7f+"2S";e.W.26=l;e.3K.26=3K}}K d},4a:J(l,h){L k=[];h=h||T;7(1o h.3s==\'10\')h=h.2i||h[0]&&h[0].2i||T;E.R(l,J(i,d){7(!d)K;7(d.1k==51)d=d.3X();7(1o d=="25"){d=d.1r(/(<(\\w+)[^>]*?)\\/>/g,J(b,a,c){K c.1D(/^(aa|a6|7e|a5|4D|7a|a0|3m|9W|9U|9S)$/i)?b:a+"></"+c+">"});L f=E.3g(d).2h(),1x=h.3s("1x");L e=!f.1f("<9P")&&[1,"<2k 74=\'74\'>","</2k>"]||!f.1f("<9M")&&[1,"<73>","</73>"]||f.1D(/^<(9G|1U|9E|9B|9x)/)&&[1,"<1O>","</1O>"]||!f.1f("<4v")&&[2,"<1O><1U>","</1U></1O>"]||(!f.1f("<9w")||!f.1f("<9v"))&&[3,"<1O><1U><4v>","</4v></1U></1O>"]||!f.1f("<7e")&&[2,"<1O><1U></1U><6V>","</6V></1O>"]||E.14.1d&&[1,"1x<1x>","</1x>"]||[0,"",""];1x.3d=e[1]+d+e[2];2b(e[0]--)1x=1x.5o;7(E.14.1d){L g=!f.1f("<1O")&&f.1f("<1U")<0?1x.1C&&1x.1C.3p:e[1]=="<1O>"&&f.1f("<1U")<0?1x.3p:[];Q(L j=g.M-1;j>=0;--j)7(E.12(g[j],"1U")&&!g[j].3p.M)g[j].1a.34(g[j]);7(/^\\s/.17(d))1x.3o(h.5r(d.1D(/^\\s*/)[0]),1x.1C)}d=E.2I(1x.3p)}7(d.M===0&&(!E.12(d,"3u")&&!E.12(d,"2k")))K;7(d[0]==10||E.12(d,"3u")||d.11)k.1g(d);N k=E.37(k,d)});K k},1J:J(d,e,c){7(!d||d.15==3||d.15==8)K 10;L f=E.3E(d)?{}:E.46;7(e=="2p"&&E.14.2d)d.1a.3T;7(f[e]){7(c!=10)d[f[e]]=c;K d[f[e]]}N 7(E.14.1d&&e=="W")K E.1J(d.W,"9u",c);N 7(c==10&&E.14.1d&&E.12(d,"3u")&&(e=="9r"||e=="9o"))K d.9m(e).6K;N 7(d.28){7(c!=10){7(e=="U"&&E.12(d,"4D")&&d.1a)6Q"U 9i 9h\'t 9g 9e";d.9b(e,""+c)}7(E.14.1d&&/6O|3Q/.17(e)&&!E.3E(d))K d.4z(e,2);K d.4z(e)}N{7(e=="1w"&&E.14.1d){7(c!=10){d.6k=1;d.1E=(d.1E||"").1r(/6M\\([^)]*\\)/,"")+(2M(c).3X()=="96"?"":"6M(1w="+c*6L+")")}K d.1E&&d.1E.1f("1w=")>=0?(2M(d.1E.1D(/1w=([^)]*)/)[1])/6L).3X():""}e=e.1r(/-([a-z])/95,J(a,b){K b.2E()});7(c!=10)d[e]=c;K d[e]}},3g:J(a){K(a||"").1r(/^\\s+|\\s+$/g,"")},2I:J(b){L a=[];7(1o b!="93")Q(L i=0,M=b.M;i<M;i++)a.1g(b[i]);N a=b.2K(0);K a},33:J(b,a){Q(L i=0,M=a.M;i<M;i++)7(a[i]==b)K i;K-1},37:J(a,b){7(E.14.1d){Q(L i=0;b[i];i++)7(b[i].15!=8)a.1g(b[i])}N Q(L i=0;b[i];i++)a.1g(b[i]);K a},57:J(a){L c=[],2r={};1S{Q(L i=0,M=a.M;i<M;i++){L b=E.O(a[i]);7(!2r[b]){2r[b]=P;c.1g(a[i])}}}1X(e){c=a}K c},3y:J(c,a,d){L b=[];Q(L i=0,M=c.M;i<M;i++)7(!d&&a(c[i],i)||d&&!a(c[i],i))b.1g(c[i]);K b},2c:J(d,a){L c=[];Q(L i=0,M=d.M;i<M;i++){L b=a(d[i],i);7(b!==V&&b!=10){7(b.1k!=1M)b=[b];c=c.71(b)}}K c}});L v=8Y.8W.2h();E.14={5K:(v.1D(/.+(?:8T|8S|8R|8O)[\\/: ]([\\d.]+)/)||[])[1],2d:/77/.17(v),2z:/2z/.17(v),1d:/1d/.17(v)&&!/2z/.17(v),48:/48/.17(v)&&!/(8L|77)/.17(v)};L y=E.14.1d?"6H":"75";E.1s({8I:!E.14.1d||T.6F=="79",46:{"Q":"8F","8E":"1t","4g":y,75:y,6H:y,3d:"3d",1t:"1t",1A:"1A",2Y:"2Y",3k:"3k",8C:"8B",2p:"2p",8A:"8z",3T:"3T",6C:"6C",28:"28",12:"12"}});E.R({6B:J(a){K a.1a},8y:J(a){K E.4u(a,"1a")},8x:J(a){K E.2Z(a,2,"2B")},8v:J(a){K E.2Z(a,2,"4t")},8u:J(a){K E.4u(a,"2B")},8t:J(a){K E.4u(a,"4t")},8s:J(a){K E.5i(a.1a.1C,a)},8r:J(a){K E.5i(a.1C)},6z:J(a){K E.12(a,"8q")?a.8o||a.8n.T:E.2I(a.3p)}},J(c,d){E.1n[c]=J(b){L a=E.2c(6,d);7(b&&1o b=="25")a=E.3e(b,a);K 6.2F(E.57(a))}});E.R({6y:"3t",8m:"6q",3o:"6o",8l:"5a",8k:"6S"},J(c,b){E.1n[c]=J(){L a=18;K 6.R(J(){Q(L i=0,M=a.M;i<M;i++)E(a[i])[b](6)})}});E.R({8j:J(a){E.1J(6,a,"");7(6.15==1)6.52(a)},8i:J(a){E.1t.1b(6,a)},8h:J(a){E.1t.1V(6,a)},8g:J(a){E.1t[E.1t.3Y(6,a)?"1V":"1b"](6,a)},1V:J(a){7(!a||E.1E(a,[6]).r.M){E("*",6).1b(6).R(J(){E.16.1V(6);E.35(6)});7(6.1a)6.1a.34(6)}},4x:J(){E(">*",6).1V();2b(6.1C)6.34(6.1C)}},J(a,b){E.1n[a]=J(){K 6.R(b,18)}});E.R(["8f","5X"],J(i,c){L b=c.2h();E.1n[b]=J(a){K 6[0]==1e?E.14.2z&&T.1h["5e"+c]||E.14.2d&&1e["8e"+c]||T.6F=="79"&&T.1F["5e"+c]||T.1h["5e"+c]:6[0]==T?24.2f(24.2f(T.1h["5d"+c],T.1F["5d"+c]),24.2f(T.1h["5L"+c],T.1F["5L"+c])):a==10?(6.M?E.1j(6[0],b):V):6.1j(b,a.1k==4e?a:a+"2S")}});L C=E.14.2d&&4s(E.14.5K)<8c?"(?:[\\\\w*4r-]|\\\\\\\\.)":"(?:[\\\\w\\8b-\\8a*4r-]|\\\\\\\\.)",6v=1B 4q("^>\\\\s*("+C+"+)"),6u=1B 4q("^("+C+"+)(#)("+C+"+)"),6s=1B 4q("^([#.]?)("+C+"*)");E.1s({6r:{"":J(a,i,m){K m[2]=="*"||E.12(a,m[2])},"#":J(a,i,m){K a.4z("2w")==m[2]},":":{89:J(a,i,m){K i<m[3]-0},88:J(a,i,m){K i>m[3]-0},2Z:J(a,i,m){K m[3]-0==i},6Z:J(a,i,m){K m[3]-0==i},3j:J(a,i){K i==0},3J:J(a,i,m,r){K i==r.M-1},6n:J(a,i){K i%2==0},6l:J(a,i){K i%2},"3j-4p":J(a){K a.1a.3S("*")[0]==a},"3J-4p":J(a){K E.2Z(a.1a.5o,1,"4t")==a},"83-4p":J(a){K!E.2Z(a.1a.5o,2,"4t")},6B:J(a){K a.1C},4x:J(a){K!a.1C},82:J(a,i,m){K(a.6x||a.81||E(a).1u()||"").1f(m[3])>=0},4d:J(a){K"1Z"!=a.U&&E.1j(a,"19")!="2H"&&E.1j(a,"4U")!="1Z"},1Z:J(a){K"1Z"==a.U||E.1j(a,"19")=="2H"||E.1j(a,"4U")=="1Z"},80:J(a){K!a.2Y},2Y:J(a){K a.2Y},3k:J(a){K a.3k},2p:J(a){K a.2p||E.1J(a,"2p")},1u:J(a){K"1u"==a.U},5u:J(a){K"5u"==a.U},5t:J(a){K"5t"==a.U},59:J(a){K"59"==a.U},3I:J(a){K"3I"==a.U},58:J(a){K"58"==a.U},6j:J(a){K"6j"==a.U},6i:J(a){K"6i"==a.U},2G:J(a){K"2G"==a.U||E.12(a,"2G")},4D:J(a){K/4D|2k|6h|2G/i.17(a.12)},3Y:J(a,i,m){K E.2s(m[3],a).M},7X:J(a){K/h\\d/i.17(a.12)},7W:J(a){K E.3y(E.3G,J(b){K a==b.Y}).M}}},6g:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1B 4q("^([:.#]*)("+C+"+)")],3e:J(a,c,b){L d,2m=[];2b(a&&a!=d){d=a;L f=E.1E(a,c,b);a=f.t.1r(/^\\s*,\\s*/,"");2m=b?c=f.r:E.37(2m,f.r)}K 2m},2s:J(t,p){7(1o t!="25")K[t];7(p&&p.15!=1&&p.15!=9)K[];p=p||T;L d=[p],2r=[],3J,12;2b(t&&3J!=t){L r=[];3J=t;t=E.3g(t);L o=S;L g=6v;L m=g.2O(t);7(m){12=m[1].2E();Q(L i=0;d[i];i++)Q(L c=d[i].1C;c;c=c.2B)7(c.15==1&&(12=="*"||c.12.2E()==12))r.1g(c);d=r;t=t.1r(g,"");7(t.1f(" ")==0)6w;o=P}N{g=/^([>+~])\\s*(\\w*)/i;7((m=g.2O(t))!=V){r=[];L l={};12=m[2].2E();m=m[1];Q(L j=0,3f=d.M;j<3f;j++){L n=m=="~"||m=="+"?d[j].2B:d[j].1C;Q(;n;n=n.2B)7(n.15==1){L h=E.O(n);7(m=="~"&&l[h])1Q;7(!12||n.12.2E()==12){7(m=="~")l[h]=P;r.1g(n)}7(m=="+")1Q}}d=r;t=E.3g(t.1r(g,""));o=P}}7(t&&!o){7(!t.1f(",")){7(p==d[0])d.4l();2r=E.37(2r,d);r=d=[p];t=" "+t.6e(1,t.M)}N{L k=6u;L m=k.2O(t);7(m){m=[0,m[2],m[3],m[1]]}N{k=6s;m=k.2O(t)}m[2]=m[2].1r(/\\\\/g,"");L f=d[d.M-1];7(m[1]=="#"&&f&&f.5J&&!E.3E(f)){L q=f.5J(m[2]);7((E.14.1d||E.14.2z)&&q&&1o q.2w=="25"&&q.2w!=m[2])q=E(\'[@2w="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.12(q,m[3]))?[q]:[]}N{Q(L i=0;d[i];i++){L a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&d[i].12.2h()=="3V")a="3m";r=E.37(r,d[i].3S(a))}7(m[1]==".")r=E.55(r,m[2]);7(m[1]=="#"){L e=[];Q(L i=0;r[i];i++)7(r[i].4z("2w")==m[2]){e=[r[i]];1Q}r=e}d=r}t=t.1r(k,"")}}7(t){L b=E.1E(t,r);d=r=b.r;t=E.3g(b.t)}}7(t)d=[];7(d&&p==d[0])d.4l();2r=E.37(2r,d);K 2r},55:J(r,m,a){m=" "+m+" ";L c=[];Q(L i=0;r[i];i++){L b=(" "+r[i].1t+" ").1f(m)>=0;7(!a&&b||a&&!b)c.1g(r[i])}K c},1E:J(t,r,h){L d;2b(t&&t!=d){d=t;L p=E.6g,m;Q(L i=0;p[i];i++){m=p[i].2O(t);7(m){t=t.7V(m[0].M);m[2]=m[2].1r(/\\\\/g,"");1Q}}7(!m)1Q;7(m[1]==":"&&m[2]=="56")r=G.17(m[3])?E.1E(m[3],r,P).r:E(r).56(m[3]);N 7(m[1]==".")r=E.55(r,m[2],h);N 7(m[1]=="["){L g=[],U=m[3];Q(L i=0,3f=r.M;i<3f;i++){L a=r[i],z=a[E.46[m[2]]||m[2]];7(z==V||/6O|3Q|2p/.17(m[2]))z=E.1J(a,m[2])||\'\';7((U==""&&!!z||U=="="&&z==m[5]||U=="!="&&z!=m[5]||U=="^="&&z&&!z.1f(m[5])||U=="$="&&z.6e(z.M-m[5].M)==m[5]||(U=="*="||U=="~=")&&z.1f(m[5])>=0)^h)g.1g(a)}r=g}N 7(m[1]==":"&&m[2]=="2Z-4p"){L e={},g=[],17=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2O(m[3]=="6n"&&"2n"||m[3]=="6l"&&"2n+1"||!/\\D/.17(m[3])&&"7U+"+m[3]||m[3]),3j=(17[1]+(17[2]||1))-0,d=17[3]-0;Q(L i=0,3f=r.M;i<3f;i++){L j=r[i],1a=j.1a,2w=E.O(1a);7(!e[2w]){L c=1;Q(L n=1a.1C;n;n=n.2B)7(n.15==1)n.4k=c++;e[2w]=P}L b=S;7(3j==0){7(j.4k==d)b=P}N 7((j.4k-d)%3j==0&&(j.4k-d)/3j>=0)b=P;7(b^h)g.1g(j)}r=g}N{L f=E.6r[m[1]];7(1o f=="3V")f=f[m[2]];7(1o f=="25")f=6c("S||J(a,i){K "+f+";}");r=E.3y(r,J(a,i){K f(a,i,m,r)},h)}}K{r:r,t:t}},4u:J(b,c){L d=[];L a=b[c];2b(a&&a!=T){7(a.15==1)d.1g(a);a=a[c]}K d},2Z:J(a,e,c,b){e=e||1;L d=0;Q(;a;a=a[c])7(a.15==1&&++d==e)1Q;K a},5i:J(n,a){L r=[];Q(;n;n=n.2B){7(n.15==1&&(!a||n!=a))r.1g(n)}K r}});E.16={1b:J(f,i,g,e){7(f.15==3||f.15==8)K;7(E.14.1d&&f.53!=10)f=1e;7(!g.2D)g.2D=6.2D++;7(e!=10){L h=g;g=J(){K h.1i(6,18)};g.O=e;g.2D=h.2D}L j=E.O(f,"2R")||E.O(f,"2R",{}),1v=E.O(f,"1v")||E.O(f,"1v",J(){L a;7(1o E=="10"||E.16.5f)K a;a=E.16.1v.1i(18.3R.Y,18);K a});1v.Y=f;E.R(i.23(/\\s+/),J(c,b){L a=b.23(".");b=a[0];g.U=a[1];L d=j[b];7(!d){d=j[b]={};7(!E.16.2y[b]||E.16.2y[b].4j.1P(f)===S){7(f.3F)f.3F(b,1v,S);N 7(f.6b)f.6b("4i"+b,1v)}}d[g.2D]=g;E.16.2a[b]=P});f=V},2D:1,2a:{},1V:J(e,h,f){7(e.15==3||e.15==8)K;L i=E.O(e,"2R"),29,4X;7(i){7(h==10||(1o h=="25"&&h.7T(0)=="."))Q(L g 1p i)6.1V(e,g+(h||""));N{7(h.U){f=h.2q;h=h.U}E.R(h.23(/\\s+/),J(b,a){L c=a.23(".");a=c[0];7(i[a]){7(f)2V i[a][f.2D];N Q(f 1p i[a])7(!c[1]||i[a][f].U==c[1])2V i[a][f];Q(29 1p i[a])1Q;7(!29){7(!E.16.2y[a]||E.16.2y[a].4h.1P(e)===S){7(e.67)e.67(a,E.O(e,"1v"),S);N 7(e.66)e.66("4i"+a,E.O(e,"1v"))}29=V;2V i[a]}}})}Q(29 1p i)1Q;7(!29){L d=E.O(e,"1v");7(d)d.Y=V;E.35(e,"2R");E.35(e,"1v")}}},1N:J(g,c,d,f,h){c=E.2I(c||[]);7(g.1f("!")>=0){g=g.2K(0,-1);L a=P}7(!d){7(6.2a[g])E("*").1b([1e,T]).1N(g,c)}N{7(d.15==3||d.15==8)K 10;L b,29,1n=E.1q(d[g]||V),16=!c[0]||!c[0].36;7(16)c.4J(6.4Z({U:g,2L:d}));c[0].U=g;7(a)c[0].65=P;7(E.1q(E.O(d,"1v")))b=E.O(d,"1v").1i(d,c);7(!1n&&d["4i"+g]&&d["4i"+g].1i(d,c)===S)b=S;7(16)c.4l();7(h&&E.1q(h)){29=h.1i(d,b==V?c:c.71(b));7(29!==10)b=29}7(1n&&f!==S&&b!==S&&!(E.12(d,\'a\')&&g=="4V")){6.5f=P;1S{d[g]()}1X(e){}}6.5f=S}K b},1v:J(c){L a;c=E.16.4Z(c||1e.16||{});L b=c.U.23(".");c.U=b[0];L f=E.O(6,"2R")&&E.O(6,"2R")[c.U],42=1M.2l.2K.1P(18,1);42.4J(c);Q(L j 1p f){L d=f[j];42[0].2q=d;42[0].O=d.O;7(!b[1]&&!c.65||d.U==b[1]){L e=d.1i(6,42);7(a!==S)a=e;7(e===S){c.36();c.44()}}}7(E.14.1d)c.2L=c.36=c.44=c.2q=c.O=V;K a},4Z:J(c){L a=c;c=E.1s({},a);c.36=J(){7(a.36)a.36();a.7S=S};c.44=J(){7(a.44)a.44();a.7R=P};7(!c.2L)c.2L=c.7Q||T;7(c.2L.15==3)c.2L=a.2L.1a;7(!c.4S&&c.5w)c.4S=c.5w==c.2L?c.7P:c.5w;7(c.64==V&&c.63!=V){L b=T.1F,1h=T.1h;c.64=c.63+(b&&b.2v||1h&&1h.2v||0)-(b.62||0);c.7N=c.7L+(b&&b.2x||1h&&1h.2x||0)-(b.60||0)}7(!c.3c&&((c.4f||c.4f===0)?c.4f:c.5Z))c.3c=c.4f||c.5Z;7(!c.7b&&c.5Y)c.7b=c.5Y;7(!c.3c&&c.2G)c.3c=(c.2G&1?1:(c.2G&2?3:(c.2G&4?2:0)));K c},2y:{21:{4j:J(){5M();K},4h:J(){K}},3C:{4j:J(){7(E.14.1d)K S;E(6).2j("4P",E.16.2y.3C.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4P",E.16.2y.3C.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3C";K E.16.1v.1i(6,18)}},3B:{4j:J(){7(E.14.1d)K S;E(6).2j("4O",E.16.2y.3B.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4O",E.16.2y.3B.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3B";K E.16.1v.1i(6,18)}}}};E.1n.1s({2j:J(c,a,b){K c=="4H"?6.2X(c,a,b):6.R(J(){E.16.1b(6,c,b||a,b&&a)})},2X:J(d,b,c){K 6.R(J(){E.16.1b(6,d,J(a){E(6).3w(a);K(c||b).1i(6,18)},c&&b)})},3w:J(a,b){K 6.R(J(){E.16.1V(6,a,b)})},1N:J(c,a,b){K 6.R(J(){E.16.1N(c,a,6,P,b)})},5n:J(c,a,b){7(6[0])K E.16.1N(c,a,6[0],S,b);K 10},2g:J(){L b=18;K 6.4V(J(a){6.4N=0==6.4N?1:0;a.36();K b[6.4N].1i(6,18)||S})},7D:J(a,b){K 6.2j(\'3C\',a).2j(\'3B\',b)},21:J(a){5M();7(E.2Q)a.1P(T,E);N E.3A.1g(J(){K a.1P(6,E)});K 6}});E.1s({2Q:S,3A:[],21:J(){7(!E.2Q){E.2Q=P;7(E.3A){E.R(E.3A,J(){6.1i(T)});E.3A=V}E(T).5n("21")}}});L x=S;J 5M(){7(x)K;x=P;7(T.3F&&!E.14.2z)T.3F("5W",E.21,S);7(E.14.1d&&1e==3b)(J(){7(E.2Q)K;1S{T.1F.7B("26")}1X(3a){3z(18.3R,0);K}E.21()})();7(E.14.2z)T.3F("5W",J(){7(E.2Q)K;Q(L i=0;i<T.4L.M;i++)7(T.4L[i].2Y){3z(18.3R,0);K}E.21()},S);7(E.14.2d){L a;(J(){7(E.2Q)K;7(T.39!="5V"&&T.39!="1y"){3z(18.3R,0);K}7(a===10)a=E("W, 7a[7A=7z]").M;7(T.4L.M!=a){3z(18.3R,0);K}E.21()})()}E.16.1b(1e,"3U",E.21)}E.R(("7y,7x,3U,7w,5d,4H,4V,7v,"+"7G,7u,7t,4P,4O,7s,2k,"+"58,7K,7q,7p,3a").23(","),J(i,b){E.1n[b]=J(a){K a?6.2j(b,a):6.1N(b)}});L I=J(a,c){L b=a.4S;2b(b&&b!=c)1S{b=b.1a}1X(3a){b=c}K b==c};E(1e).2j("4H",J(){E("*").1b(T).3w()});E.1n.1s({3U:J(g,d,c){7(E.1q(g))K 6.2j("3U",g);L e=g.1f(" ");7(e>=0){L i=g.2K(e,g.M);g=g.2K(0,e)}c=c||J(){};L f="4Q";7(d)7(E.1q(d)){c=d;d=V}N{d=E.3m(d);f="61"}L h=6;E.3P({1c:g,U:f,1H:"3q",O:d,1y:J(a,b){7(b=="1W"||b=="5U")h.3q(i?E("<1x/>").3t(a.4b.1r(/<1m(.|\\s)*?\\/1m>/g,"")).2s(i):a.4b);h.R(c,[a.4b,b,a])}});K 6},7n:J(){K E.3m(6.5T())},5T:J(){K 6.2c(J(){K E.12(6,"3u")?E.2I(6.7m):6}).1E(J(){K 6.31&&!6.2Y&&(6.3k||/2k|6h/i.17(6.12)||/1u|1Z|3I/i.17(6.U))}).2c(J(i,c){L b=E(6).5O();K b==V?V:b.1k==1M?E.2c(b,J(a,i){K{31:c.31,1A:a}}):{31:c.31,1A:b}}).22()}});E.R("5S,6d,5R,6D,5Q,6m".23(","),J(i,o){E.1n[o]=J(f){K 6.2j(o,f)}});L B=(1B 3v).3L();E.1s({22:J(d,b,a,c){7(E.1q(b)){a=b;b=V}K E.3P({U:"4Q",1c:d,O:b,1W:a,1H:c})},7l:J(b,a){K E.22(b,V,a,"1m")},7k:J(c,b,a){K E.22(c,b,a,"3i")},7i:J(d,b,a,c){7(E.1q(b)){a=b;b={}}K E.3P({U:"61",1c:d,O:b,1W:a,1H:c})},85:J(a){E.1s(E.4I,a)},4I:{2a:P,U:"4Q",2U:0,5P:"4o/x-7h-3u-7g",5N:P,3l:P,O:V,6p:V,3I:V,49:{3M:"4o/3M, 1u/3M",3q:"1u/3q",1m:"1u/4m, 4o/4m",3i:"4o/3i, 1u/4m",1u:"1u/a7",4G:"*/*"}},4F:{},3P:J(s){L f,2W=/=\\?(&|$)/g,1z,O;s=E.1s(P,s,E.1s(P,{},E.4I,s));7(s.O&&s.5N&&1o s.O!="25")s.O=E.3m(s.O);7(s.1H=="4E"){7(s.U.2h()=="22"){7(!s.1c.1D(2W))s.1c+=(s.1c.1D(/\\?/)?"&":"?")+(s.4E||"7d")+"=?"}N 7(!s.O||!s.O.1D(2W))s.O=(s.O?s.O+"&":"")+(s.4E||"7d")+"=?";s.1H="3i"}7(s.1H=="3i"&&(s.O&&s.O.1D(2W)||s.1c.1D(2W))){f="4E"+B++;7(s.O)s.O=(s.O+"").1r(2W,"="+f+"$1");s.1c=s.1c.1r(2W,"="+f+"$1");s.1H="1m";1e[f]=J(a){O=a;1W();1y();1e[f]=10;1S{2V 1e[f]}1X(e){}7(h)h.34(g)}}7(s.1H=="1m"&&s.1T==V)s.1T=S;7(s.1T===S&&s.U.2h()=="22"){L i=(1B 3v()).3L();L j=s.1c.1r(/(\\?|&)4r=.*?(&|$)/,"$a4="+i+"$2");s.1c=j+((j==s.1c)?(s.1c.1D(/\\?/)?"&":"?")+"4r="+i:"")}7(s.O&&s.U.2h()=="22"){s.1c+=(s.1c.1D(/\\?/)?"&":"?")+s.O;s.O=V}7(s.2a&&!E.5H++)E.16.1N("5S");7((!s.1c.1f("a3")||!s.1c.1f("//"))&&s.1H=="1m"&&s.U.2h()=="22"){L h=T.3S("6f")[0];L g=T.3s("1m");g.3Q=s.1c;7(s.7c)g.a2=s.7c;7(!f){L l=S;g.9Z=g.9Y=J(){7(!l&&(!6.39||6.39=="5V"||6.39=="1y")){l=P;1W();1y();h.34(g)}}}h.38(g);K 10}L m=S;L k=1e.78?1B 78("9X.9V"):1B 76();k.9T(s.U,s.1c,s.3l,s.6p,s.3I);1S{7(s.O)k.4C("9R-9Q",s.5P);7(s.5C)k.4C("9O-5A-9N",E.4F[s.1c]||"9L, 9K 9I 9H 5z:5z:5z 9F");k.4C("X-9C-9A","76");k.4C("9z",s.1H&&s.49[s.1H]?s.49[s.1H]+", */*":s.49.4G)}1X(e){}7(s.6Y)s.6Y(k);7(s.2a)E.16.1N("6m",[k,s]);L c=J(a){7(!m&&k&&(k.39==4||a=="2U")){m=P;7(d){6I(d);d=V}1z=a=="2U"&&"2U"||!E.6X(k)&&"3a"||s.5C&&E.6J(k,s.1c)&&"5U"||"1W";7(1z=="1W"){1S{O=E.6W(k,s.1H)}1X(e){1z="5x"}}7(1z=="1W"){L b;1S{b=k.5q("6U-5A")}1X(e){}7(s.5C&&b)E.4F[s.1c]=b;7(!f)1W()}N E.5v(s,k,1z);1y();7(s.3l)k=V}};7(s.3l){L d=53(c,13);7(s.2U>0)3z(J(){7(k){k.9t();7(!m)c("2U")}},s.2U)}1S{k.9s(s.O)}1X(e){E.5v(s,k,V,e)}7(!s.3l)c();J 1W(){7(s.1W)s.1W(O,1z);7(s.2a)E.16.1N("5Q",[k,s])}J 1y(){7(s.1y)s.1y(k,1z);7(s.2a)E.16.1N("5R",[k,s]);7(s.2a&&!--E.5H)E.16.1N("6d")}K k},5v:J(s,a,b,e){7(s.3a)s.3a(a,b,e);7(s.2a)E.16.1N("6D",[a,s,e])},5H:0,6X:J(r){1S{K!r.1z&&9q.9p=="59:"||(r.1z>=6T&&r.1z<9n)||r.1z==6R||r.1z==9l||E.14.2d&&r.1z==10}1X(e){}K S},6J:J(a,c){1S{L b=a.5q("6U-5A");K a.1z==6R||b==E.4F[c]||E.14.2d&&a.1z==10}1X(e){}K S},6W:J(r,b){L c=r.5q("9k-U");L d=b=="3M"||!b&&c&&c.1f("3M")>=0;L a=d?r.9j:r.4b;7(d&&a.1F.28=="5x")6Q"5x";7(b=="1m")E.5g(a);7(b=="3i")a=6c("("+a+")");K a},3m:J(a){L s=[];7(a.1k==1M||a.5h)E.R(a,J(){s.1g(3r(6.31)+"="+3r(6.1A))});N Q(L j 1p a)7(a[j]&&a[j].1k==1M)E.R(a[j],J(){s.1g(3r(j)+"="+3r(6))});N s.1g(3r(j)+"="+3r(a[j]));K s.6a("&").1r(/%20/g,"+")}});E.1n.1s({1G:J(c,b){K c?6.2e({1R:"1G",27:"1G",1w:"1G"},c,b):6.1E(":1Z").R(J(){6.W.19=6.5s||"";7(E.1j(6,"19")=="2H"){L a=E("<"+6.28+" />").6y("1h");6.W.19=a.1j("19");7(6.W.19=="2H")6.W.19="3D";a.1V()}}).3h()},1I:J(b,a){K b?6.2e({1R:"1I",27:"1I",1w:"1I"},b,a):6.1E(":4d").R(J(){6.5s=6.5s||E.1j(6,"19");6.W.19="2H"}).3h()},6N:E.1n.2g,2g:J(a,b){K E.1q(a)&&E.1q(b)?6.6N(a,b):a?6.2e({1R:"2g",27:"2g",1w:"2g"},a,b):6.R(J(){E(6)[E(6).3H(":1Z")?"1G":"1I"]()})},9f:J(b,a){K 6.2e({1R:"1G"},b,a)},9d:J(b,a){K 6.2e({1R:"1I"},b,a)},9c:J(b,a){K 6.2e({1R:"2g"},b,a)},9a:J(b,a){K 6.2e({1w:"1G"},b,a)},99:J(b,a){K 6.2e({1w:"1I"},b,a)},97:J(c,a,b){K 6.2e({1w:a},c,b)},2e:J(l,k,j,h){L i=E.6P(k,j,h);K 6[i.2P===S?"R":"2P"](J(){7(6.15!=1)K S;L g=E.1s({},i);L f=E(6).3H(":1Z"),4A=6;Q(L p 1p l){7(l[p]=="1I"&&f||l[p]=="1G"&&!f)K E.1q(g.1y)&&g.1y.1i(6);7(p=="1R"||p=="27"){g.19=E.1j(6,"19");g.32=6.W.32}}7(g.32!=V)6.W.32="1Z";g.40=E.1s({},l);E.R(l,J(c,a){L e=1B E.2t(4A,g,c);7(/2g|1G|1I/.17(a))e[a=="2g"?f?"1G":"1I":a](l);N{L b=a.3X().1D(/^([+-]=)?([\\d+-.]+)(.*)$/),1Y=e.2m(P)||0;7(b){L d=2M(b[2]),2A=b[3]||"2S";7(2A!="2S"){4A.W[c]=(d||1)+2A;1Y=((d||1)/e.2m(P))*1Y;4A.W[c]=1Y+2A}7(b[1])d=((b[1]=="-="?-1:1)*d)+1Y;e.45(1Y,d,2A)}N e.45(1Y,a,"")}});K P})},2P:J(a,b){7(E.1q(a)||(a&&a.1k==1M)){b=a;a="2t"}7(!a||(1o a=="25"&&!b))K A(6[0],a);K 6.R(J(){7(b.1k==1M)A(6,a,b);N{A(6,a).1g(b);7(A(6,a).M==1)b.1i(6)}})},94:J(b,c){L a=E.3G;7(b)6.2P([]);6.R(J(){Q(L i=a.M-1;i>=0;i--)7(a[i].Y==6){7(c)a[i](P);a.72(i,1)}});7(!c)6.5p();K 6}});L A=J(b,c,a){7(!b)K 10;c=c||"2t";L q=E.O(b,c+"2P");7(!q||a)q=E.O(b,c+"2P",a?E.2I(a):[]);K q};E.1n.5p=J(a){a=a||"2t";K 6.R(J(){L q=A(6,a);q.4l();7(q.M)q[0].1i(6)})};E.1s({6P:J(b,a,c){L d=b&&b.1k==92?b:{1y:c||!c&&a||E.1q(b)&&b,2u:b,3Z:c&&a||a&&a.1k!=91&&a};d.2u=(d.2u&&d.2u.1k==51?d.2u:{90:8Z,9D:6T}[d.2u])||8X;d.5y=d.1y;d.1y=J(){7(d.2P!==S)E(6).5p();7(E.1q(d.5y))d.5y.1i(6)};K d},3Z:{70:J(p,n,b,a){K b+a*p},5j:J(p,n,b,a){K((-24.8V(p*24.8U)/2)+0.5)*a+b}},3G:[],3W:V,2t:J(b,c,a){6.11=c;6.Y=b;6.1l=a;7(!c.47)c.47={}}});E.2t.2l={4y:J(){7(6.11.30)6.11.30.1i(6.Y,[6.2J,6]);(E.2t.30[6.1l]||E.2t.30.4G)(6);7(6.1l=="1R"||6.1l=="27")6.Y.W.19="3D"},2m:J(a){7(6.Y[6.1l]!=V&&6.Y.W[6.1l]==V)K 6.Y[6.1l];L r=2M(E.1j(6.Y,6.1l,a));K r&&r>-8Q?r:2M(E.2o(6.Y,6.1l))||0},45:J(c,b,d){6.5B=(1B 3v()).3L();6.1Y=c;6.3h=b;6.2A=d||6.2A||"2S";6.2J=6.1Y;6.4B=6.4w=0;6.4y();L e=6;J t(a){K e.30(a)}t.Y=6.Y;E.3G.1g(t);7(E.3W==V){E.3W=53(J(){L a=E.3G;Q(L i=0;i<a.M;i++)7(!a[i]())a.72(i--,1);7(!a.M){6I(E.3W);E.3W=V}},13)}},1G:J(){6.11.47[6.1l]=E.1J(6.Y.W,6.1l);6.11.1G=P;6.45(0,6.2m());7(6.1l=="27"||6.1l=="1R")6.Y.W[6.1l]="8N";E(6.Y).1G()},1I:J(){6.11.47[6.1l]=E.1J(6.Y.W,6.1l);6.11.1I=P;6.45(6.2m(),0)},30:J(a){L t=(1B 3v()).3L();7(a||t>6.11.2u+6.5B){6.2J=6.3h;6.4B=6.4w=1;6.4y();6.11.40[6.1l]=P;L b=P;Q(L i 1p 6.11.40)7(6.11.40[i]!==P)b=S;7(b){7(6.11.19!=V){6.Y.W.32=6.11.32;6.Y.W.19=6.11.19;7(E.1j(6.Y,"19")=="2H")6.Y.W.19="3D"}7(6.11.1I)6.Y.W.19="2H";7(6.11.1I||6.11.1G)Q(L p 1p 6.11.40)E.1J(6.Y.W,p,6.11.47[p])}7(b&&E.1q(6.11.1y))6.11.1y.1i(6.Y);K S}N{L n=t-6.5B;6.4w=n/6.11.2u;6.4B=E.3Z[6.11.3Z||(E.3Z.5j?"5j":"70")](6.4w,n,0,1,6.11.2u);6.2J=6.1Y+((6.3h-6.1Y)*6.4B);6.4y()}K P}};E.2t.30={2v:J(a){a.Y.2v=a.2J},2x:J(a){a.Y.2x=a.2J},1w:J(a){E.1J(a.Y.W,"1w",a.2J)},4G:J(a){a.Y.W[a.1l]=a.2J+a.2A}};E.1n.5L=J(){L b=0,3b=0,Y=6[0],5l;7(Y)8M(E.14){L d=Y.1a,41=Y,1K=Y.1K,1L=Y.2i,5D=2d&&4s(5K)<8J&&!/a1/i.17(v),2T=E.1j(Y,"43")=="2T";7(Y.6G){L c=Y.6G();1b(c.26+24.2f(1L.1F.2v,1L.1h.2v),c.3b+24.2f(1L.1F.2x,1L.1h.2x));1b(-1L.1F.62,-1L.1F.60)}N{1b(Y.5G,Y.5F);2b(1K){1b(1K.5G,1K.5F);7(48&&!/^t(8H|d|h)$/i.17(1K.28)||2d&&!5D)2N(1K);7(!2T&&E.1j(1K,"43")=="2T")2T=P;41=/^1h$/i.17(1K.28)?41:1K;1K=1K.1K}2b(d&&d.28&&!/^1h|3q$/i.17(d.28)){7(!/^8G|1O.*$/i.17(E.1j(d,"19")))1b(-d.2v,-d.2x);7(48&&E.1j(d,"32")!="4d")2N(d);d=d.1a}7((5D&&(2T||E.1j(41,"43")=="4W"))||(48&&E.1j(41,"43")!="4W"))1b(-1L.1h.5G,-1L.1h.5F);7(2T)1b(24.2f(1L.1F.2v,1L.1h.2v),24.2f(1L.1F.2x,1L.1h.2x))}5l={3b:3b,26:b}}J 2N(a){1b(E.2o(a,"a8",P),E.2o(a,"a9",P))}J 1b(l,t){b+=4s(l)||0;3b+=4s(t)||0}K 5l}})();',62,631,'||||||this|if||||||||||||||||||||||||||||||||||||||function|return|var|length|else|data|true|for|each|false|document|type|null|style||elem||undefined|options|nodeName||browser|nodeType|event|test|arguments|display|parentNode|add|url|msie|window|indexOf|push|body|apply|css|constructor|prop|script|fn|typeof|in|isFunction|replace|extend|className|text|handle|opacity|div|complete|status|value|new|firstChild|match|filter|documentElement|show|dataType|hide|attr|offsetParent|doc|Array|trigger|table|call|break|height|try|cache|tbody|remove|success|catch|start|hidden||ready|get|split|Math|string|left|width|tagName|ret|global|while|map|safari|animate|max|toggle|toLowerCase|ownerDocument|bind|select|prototype|cur||curCSS|selected|handler|done|find|fx|duration|scrollLeft|id|scrollTop|special|opera|unit|nextSibling|stack|guid|toUpperCase|pushStack|button|none|makeArray|now|slice|target|parseFloat|border|exec|queue|isReady|events|px|fixed|timeout|delete|jsre|one|disabled|nth|step|name|overflow|inArray|removeChild|removeData|preventDefault|merge|appendChild|readyState|error|top|which|innerHTML|multiFilter|rl|trim|end|json|first|checked|async|param|elems|insertBefore|childNodes|html|encodeURIComponent|createElement|append|form|Date|unbind|color|grep|setTimeout|readyList|mouseleave|mouseenter|block|isXMLDoc|addEventListener|timers|is|password|last|runtimeStyle|getTime|xml|jQuery|domManip|ajax|src|callee|getElementsByTagName|selectedIndex|load|object|timerId|toString|has|easing|curAnim|offsetChild|args|position|stopPropagation|custom|props|orig|mozilla|accepts|clean|responseText|defaultView|visible|String|charCode|float|teardown|on|setup|nodeIndex|shift|javascript|currentStyle|application|child|RegExp|_|parseInt|previousSibling|dir|tr|state|empty|update|getAttribute|self|pos|setRequestHeader|input|jsonp|lastModified|_default|unload|ajaxSettings|unshift|getComputedStyle|styleSheets|getPropertyValue|lastToggle|mouseout|mouseover|GET|andSelf|relatedTarget|init|visibility|click|absolute|index|container|fix|outline|Number|removeAttribute|setInterval|prevObject|classFilter|not|unique|submit|file|after|windowData|deep|scroll|client|triggered|globalEval|jquery|sibling|swing|clone|results|wrapAll|triggerHandler|lastChild|dequeue|getResponseHeader|createTextNode|oldblock|checkbox|radio|handleError|fromElement|parsererror|old|00|Modified|startTime|ifModified|safari2|getWH|offsetTop|offsetLeft|active|values|getElementById|version|offset|bindReady|processData|val|contentType|ajaxSuccess|ajaxComplete|ajaxStart|serializeArray|notmodified|loaded|DOMContentLoaded|Width|ctrlKey|keyCode|clientTop|POST|clientLeft|clientX|pageX|exclusive|detachEvent|removeEventListener|swap|cloneNode|join|attachEvent|eval|ajaxStop|substr|head|parse|textarea|reset|image|zoom|odd|ajaxSend|even|before|username|prepend|expr|quickClass|uuid|quickID|quickChild|continue|textContent|appendTo|contents|evalScript|parent|defaultValue|ajaxError|setArray|compatMode|getBoundingClientRect|styleFloat|clearInterval|httpNotModified|nodeValue|100|alpha|_toggle|href|speed|throw|304|replaceWith|200|Last|colgroup|httpData|httpSuccess|beforeSend|eq|linear|concat|splice|fieldset|multiple|cssFloat|XMLHttpRequest|webkit|ActiveXObject|CSS1Compat|link|metaKey|scriptCharset|callback|col|pixelLeft|urlencoded|www|post|hasClass|getJSON|getScript|elements|serialize|black|keyup|keypress|solid|change|mousemove|mouseup|dblclick|resize|focus|blur|stylesheet|rel|doScroll|round|hover|padding|offsetHeight|mousedown|offsetWidth|Bottom|Top|keydown|clientY|Right|pageY|Left|toElement|srcElement|cancelBubble|returnValue|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|ajaxSetup|font|size|gt|lt|uFFFF|u0128|417|Boolean|inner|Height|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|contentWindow|contentDocument|wrap|iframe|children|siblings|prevAll|nextAll|prev|wrapInner|next|parents|maxLength|maxlength|readOnly|readonly|reverse|class|htmlFor|inline|able|boxModel|522|setData|compatible|with|1px|ie|getData|10000|ra|it|rv|PI|cos|userAgent|400|navigator|600|slow|Function|Object|array|stop|ig|NaN|fadeTo|option|fadeOut|fadeIn|setAttribute|slideToggle|slideUp|changed|slideDown|be|can|property|responseXML|content|1223|getAttributeNode|300|method|protocol|location|action|send|abort|cssText|th|td|cap|specified|Accept|With|colg|Requested|fast|tfoot|GMT|thead|1970|Jan|attributes|01|Thu|leg|Since|If|opt|Type|Content|embed|open|area|XMLHTTP|hr|Microsoft|onreadystatechange|onload|meta|adobeair|charset|http|1_|img|br|plain|borderLeftWidth|borderTopWidth|abbr'.split('|'),0,{}))
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(H(){J w=1b.4M,3m$=1b.$;J D=1b.4M=1b.$=H(a,b){I 2B D.17.5j(a,b)};J u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/,62=/^.[^:#\\[\\.]*$/,12;D.17=D.44={5j:H(d,b){d=d||S;G(d.16){7[0]=d;7.K=1;I 7}G(1j d=="23"){J c=u.2D(d);G(c&&(c[1]||!b)){G(c[1])d=D.4h([c[1]],b);N{J a=S.61(c[3]);G(a){G(a.2v!=c[3])I D().2q(d);I D(a)}d=[]}}N I D(b).2q(d)}N G(D.1D(d))I D(S)[D.17.27?"27":"43"](d);I 7.6Y(D.2d(d))},5w:"1.2.6",8G:H(){I 7.K},K:0,3p:H(a){I a==12?D.2d(7):7[a]},2I:H(b){J a=D(b);a.5n=7;I a},6Y:H(a){7.K=0;2p.44.1p.1w(7,a);I 7},P:H(a,b){I D.P(7,a,b)},5i:H(b){J a=-1;I D.2L(b&&b.5w?b[0]:b,7)},1K:H(c,a,b){J d=c;G(c.1q==56)G(a===12)I 7[0]&&D[b||"1K"](7[0],c);N{d={};d[c]=a}I 7.P(H(i){R(c 1n d)D.1K(b?7.V:7,c,D.1i(7,d[c],b,i,c))})},1g:H(b,a){G((b==\'2h\'||b==\'1Z\')&&3d(a)<0)a=12;I 7.1K(b,a,"2a")},1r:H(b){G(1j b!="49"&&b!=U)I 7.4E().3v((7[0]&&7[0].2z||S).5F(b));J a="";D.P(b||7,H(){D.P(7.3t,H(){G(7.16!=8)a+=7.16!=1?7.76:D.17.1r([7])})});I a},5z:H(b){G(7[0])D(b,7[0].2z).5y().39(7[0]).2l(H(){J a=7;1B(a.1x)a=a.1x;I a}).3v(7);I 7},8Y:H(a){I 7.P(H(){D(7).6Q().5z(a)})},8R:H(a){I 7.P(H(){D(7).5z(a)})},3v:H(){I 7.3W(19,M,Q,H(a){G(7.16==1)7.3U(a)})},6F:H(){I 7.3W(19,M,M,H(a){G(7.16==1)7.39(a,7.1x)})},6E:H(){I 7.3W(19,Q,Q,H(a){7.1d.39(a,7)})},5q:H(){I 7.3W(19,Q,M,H(a){7.1d.39(a,7.2H)})},3l:H(){I 7.5n||D([])},2q:H(b){J c=D.2l(7,H(a){I D.2q(b,a)});I 7.2I(/[^+>] [^+>]/.11(b)||b.1h("..")>-1?D.4r(c):c)},5y:H(e){J f=7.2l(H(){G(D.14.1f&&!D.4n(7)){J a=7.6o(M),5h=S.3h("1v");5h.3U(a);I D.4h([5h.4H])[0]}N I 7.6o(M)});J d=f.2q("*").5c().P(H(){G(7[E]!=12)7[E]=U});G(e===M)7.2q("*").5c().P(H(i){G(7.16==3)I;J c=D.L(7,"3w");R(J a 1n c)R(J b 1n c[a])D.W.1e(d[i],a,c[a][b],c[a][b].L)});I f},1E:H(b){I 7.2I(D.1D(b)&&D.3C(7,H(a,i){I b.1k(a,i)})||D.3g(b,7))},4Y:H(b){G(b.1q==56)G(62.11(b))I 7.2I(D.3g(b,7,M));N b=D.3g(b,7);J a=b.K&&b[b.K-1]!==12&&!b.16;I 7.1E(H(){I a?D.2L(7,b)<0:7!=b})},1e:H(a){I 7.2I(D.4r(D.2R(7.3p(),1j a==\'23\'?D(a):D.2d(a))))},3F:H(a){I!!a&&D.3g(a,7).K>0},7T:H(a){I 7.3F("."+a)},6e:H(b){G(b==12){G(7.K){J c=7[0];G(D.Y(c,"2A")){J e=c.64,63=[],15=c.15,2V=c.O=="2A-2V";G(e<0)I U;R(J i=2V?e:0,2f=2V?e+1:15.K;i<2f;i++){J d=15[i];G(d.2W){b=D.14.1f&&!d.at.2x.an?d.1r:d.2x;G(2V)I b;63.1p(b)}}I 63}N I(7[0].2x||"").1o(/\\r/g,"")}I 12}G(b.1q==4L)b+=\'\';I 7.P(H(){G(7.16!=1)I;G(b.1q==2p&&/5O|5L/.11(7.O))7.4J=(D.2L(7.2x,b)>=0||D.2L(7.34,b)>=0);N G(D.Y(7,"2A")){J a=D.2d(b);D("9R",7).P(H(){7.2W=(D.2L(7.2x,a)>=0||D.2L(7.1r,a)>=0)});G(!a.K)7.64=-1}N 7.2x=b})},2K:H(a){I a==12?(7[0]?7[0].4H:U):7.4E().3v(a)},7b:H(a){I 7.5q(a).21()},79:H(i){I 7.3s(i,i+1)},3s:H(){I 7.2I(2p.44.3s.1w(7,19))},2l:H(b){I 7.2I(D.2l(7,H(a,i){I b.1k(a,i,a)}))},5c:H(){I 7.1e(7.5n)},L:H(d,b){J a=d.1R(".");a[1]=a[1]?"."+a[1]:"";G(b===12){J c=7.5C("9z"+a[1]+"!",[a[0]]);G(c===12&&7.K)c=D.L(7[0],d);I c===12&&a[1]?7.L(a[0]):c}N I 7.1P("9u"+a[1]+"!",[a[0],b]).P(H(){D.L(7,d,b)})},3b:H(a){I 7.P(H(){D.3b(7,a)})},3W:H(g,f,h,d){J e=7.K>1,3x;I 7.P(H(){G(!3x){3x=D.4h(g,7.2z);G(h)3x.9o()}J b=7;G(f&&D.Y(7,"1T")&&D.Y(3x[0],"4F"))b=7.3H("22")[0]||7.3U(7.2z.3h("22"));J c=D([]);D.P(3x,H(){J a=e?D(7).5y(M)[0]:7;G(D.Y(a,"1m"))c=c.1e(a);N{G(a.16==1)c=c.1e(D("1m",a).21());d.1k(b,a)}});c.P(6T)})}};D.17.5j.44=D.17;H 6T(i,a){G(a.4d)D.3Y({1a:a.4d,31:Q,1O:"1m"});N D.5u(a.1r||a.6O||a.4H||"");G(a.1d)a.1d.37(a)}H 1z(){I+2B 8J}D.1l=D.17.1l=H(){J b=19[0]||{},i=1,K=19.K,4x=Q,15;G(b.1q==8I){4x=b;b=19[1]||{};i=2}G(1j b!="49"&&1j b!="H")b={};G(K==i){b=7;--i}R(;i<K;i++)G((15=19[i])!=U)R(J c 1n 15){J a=b[c],2w=15[c];G(b===2w)6M;G(4x&&2w&&1j 2w=="49"&&!2w.16)b[c]=D.1l(4x,a||(2w.K!=U?[]:{}),2w);N G(2w!==12)b[c]=2w}I b};J E="4M"+1z(),6K=0,5r={},6G=/z-?5i|8B-?8A|1y|6B|8v-?1Z/i,3P=S.3P||{};D.1l({8u:H(a){1b.$=3m$;G(a)1b.4M=w;I D},1D:H(a){I!!a&&1j a!="23"&&!a.Y&&a.1q!=2p&&/^[\\s[]?H/.11(a+"")},4n:H(a){I a.1C&&!a.1c||a.2j&&a.2z&&!a.2z.1c},5u:H(a){a=D.3k(a);G(a){J b=S.3H("6w")[0]||S.1C,1m=S.3h("1m");1m.O="1r/4t";G(D.14.1f)1m.1r=a;N 1m.3U(S.5F(a));b.39(1m,b.1x);b.37(1m)}},Y:H(b,a){I b.Y&&b.Y.2r()==a.2r()},1Y:{},L:H(c,d,b){c=c==1b?5r:c;J a=c[E];G(!a)a=c[E]=++6K;G(d&&!D.1Y[a])D.1Y[a]={};G(b!==12)D.1Y[a][d]=b;I d?D.1Y[a][d]:a},3b:H(c,b){c=c==1b?5r:c;J a=c[E];G(b){G(D.1Y[a]){2U D.1Y[a][b];b="";R(b 1n D.1Y[a])1X;G(!b)D.3b(c)}}N{1U{2U c[E]}1V(e){G(c.5l)c.5l(E)}2U D.1Y[a]}},P:H(d,a,c){J e,i=0,K=d.K;G(c){G(K==12){R(e 1n d)G(a.1w(d[e],c)===Q)1X}N R(;i<K;)G(a.1w(d[i++],c)===Q)1X}N{G(K==12){R(e 1n d)G(a.1k(d[e],e,d[e])===Q)1X}N R(J b=d[0];i<K&&a.1k(b,i,b)!==Q;b=d[++i]){}}I d},1i:H(b,a,c,i,d){G(D.1D(a))a=a.1k(b,i);I a&&a.1q==4L&&c=="2a"&&!6G.11(d)?a+"2X":a},1F:{1e:H(c,b){D.P((b||"").1R(/\\s+/),H(i,a){G(c.16==1&&!D.1F.3T(c.1F,a))c.1F+=(c.1F?" ":"")+a})},21:H(c,b){G(c.16==1)c.1F=b!=12?D.3C(c.1F.1R(/\\s+/),H(a){I!D.1F.3T(b,a)}).6s(" "):""},3T:H(b,a){I D.2L(a,(b.1F||b).6r().1R(/\\s+/))>-1}},6q:H(b,c,a){J e={};R(J d 1n c){e[d]=b.V[d];b.V[d]=c[d]}a.1k(b);R(J d 1n c)b.V[d]=e[d]},1g:H(d,e,c){G(e=="2h"||e=="1Z"){J b,3X={30:"5x",5g:"1G",18:"3I"},35=e=="2h"?["5e","6k"]:["5G","6i"];H 5b(){b=e=="2h"?d.8f:d.8c;J a=0,2C=0;D.P(35,H(){a+=3d(D.2a(d,"57"+7,M))||0;2C+=3d(D.2a(d,"2C"+7+"4b",M))||0});b-=29.83(a+2C)}G(D(d).3F(":4j"))5b();N D.6q(d,3X,5b);I 29.2f(0,b)}I D.2a(d,e,c)},2a:H(f,l,k){J e,V=f.V;H 3E(b){G(!D.14.2k)I Q;J a=3P.54(b,U);I!a||a.52("3E")==""}G(l=="1y"&&D.14.1f){e=D.1K(V,"1y");I e==""?"1":e}G(D.14.2G&&l=="18"){J d=V.50;V.50="0 7Y 7W";V.50=d}G(l.1I(/4i/i))l=y;G(!k&&V&&V[l])e=V[l];N G(3P.54){G(l.1I(/4i/i))l="4i";l=l.1o(/([A-Z])/g,"-$1").3y();J c=3P.54(f,U);G(c&&!3E(f))e=c.52(l);N{J g=[],2E=[],a=f,i=0;R(;a&&3E(a);a=a.1d)2E.6h(a);R(;i<2E.K;i++)G(3E(2E[i])){g[i]=2E[i].V.18;2E[i].V.18="3I"}e=l=="18"&&g[2E.K-1]!=U?"2F":(c&&c.52(l))||"";R(i=0;i<g.K;i++)G(g[i]!=U)2E[i].V.18=g[i]}G(l=="1y"&&e=="")e="1"}N G(f.4g){J h=l.1o(/\\-(\\w)/g,H(a,b){I b.2r()});e=f.4g[l]||f.4g[h];G(!/^\\d+(2X)?$/i.11(e)&&/^\\d/.11(e)){J j=V.1A,66=f.65.1A;f.65.1A=f.4g.1A;V.1A=e||0;e=V.aM+"2X";V.1A=j;f.65.1A=66}}I e},4h:H(l,h){J k=[];h=h||S;G(1j h.3h==\'12\')h=h.2z||h[0]&&h[0].2z||S;D.P(l,H(i,d){G(!d)I;G(d.1q==4L)d+=\'\';G(1j d=="23"){d=d.1o(/(<(\\w+)[^>]*?)\\/>/g,H(b,a,c){I c.1I(/^(aK|4f|7E|aG|4T|7A|aB|3n|az|ay|av)$/i)?b:a+"></"+c+">"});J f=D.3k(d).3y(),1v=h.3h("1v");J e=!f.1h("<au")&&[1,"<2A 7w=\'7w\'>","</2A>"]||!f.1h("<ar")&&[1,"<7v>","</7v>"]||f.1I(/^<(aq|22|am|ak|ai)/)&&[1,"<1T>","</1T>"]||!f.1h("<4F")&&[2,"<1T><22>","</22></1T>"]||(!f.1h("<af")||!f.1h("<ad"))&&[3,"<1T><22><4F>","</4F></22></1T>"]||!f.1h("<7E")&&[2,"<1T><22></22><7q>","</7q></1T>"]||D.14.1f&&[1,"1v<1v>","</1v>"]||[0,"",""];1v.4H=e[1]+d+e[2];1B(e[0]--)1v=1v.5T;G(D.14.1f){J g=!f.1h("<1T")&&f.1h("<22")<0?1v.1x&&1v.1x.3t:e[1]=="<1T>"&&f.1h("<22")<0?1v.3t:[];R(J j=g.K-1;j>=0;--j)G(D.Y(g[j],"22")&&!g[j].3t.K)g[j].1d.37(g[j]);G(/^\\s/.11(d))1v.39(h.5F(d.1I(/^\\s*/)[0]),1v.1x)}d=D.2d(1v.3t)}G(d.K===0&&(!D.Y(d,"3V")&&!D.Y(d,"2A")))I;G(d[0]==12||D.Y(d,"3V")||d.15)k.1p(d);N k=D.2R(k,d)});I k},1K:H(d,f,c){G(!d||d.16==3||d.16==8)I 12;J e=!D.4n(d),40=c!==12,1f=D.14.1f;f=e&&D.3X[f]||f;G(d.2j){J g=/5Q|4d|V/.11(f);G(f=="2W"&&D.14.2k)d.1d.64;G(f 1n d&&e&&!g){G(40){G(f=="O"&&D.Y(d,"4T")&&d.1d)7p"O a3 a1\'t 9V 9U";d[f]=c}G(D.Y(d,"3V")&&d.7i(f))I d.7i(f).76;I d[f]}G(1f&&e&&f=="V")I D.1K(d.V,"9T",c);G(40)d.9Q(f,""+c);J h=1f&&e&&g?d.4G(f,2):d.4G(f);I h===U?12:h}G(1f&&f=="1y"){G(40){d.6B=1;d.1E=(d.1E||"").1o(/7f\\([^)]*\\)/,"")+(3r(c)+\'\'=="9L"?"":"7f(1y="+c*7a+")")}I d.1E&&d.1E.1h("1y=")>=0?(3d(d.1E.1I(/1y=([^)]*)/)[1])/7a)+\'\':""}f=f.1o(/-([a-z])/9H,H(a,b){I b.2r()});G(40)d[f]=c;I d[f]},3k:H(a){I(a||"").1o(/^\\s+|\\s+$/g,"")},2d:H(b){J a=[];G(b!=U){J i=b.K;G(i==U||b.1R||b.4I||b.1k)a[0]=b;N 1B(i)a[--i]=b[i]}I a},2L:H(b,a){R(J i=0,K=a.K;i<K;i++)G(a[i]===b)I i;I-1},2R:H(a,b){J i=0,T,2S=a.K;G(D.14.1f){1B(T=b[i++])G(T.16!=8)a[2S++]=T}N 1B(T=b[i++])a[2S++]=T;I a},4r:H(a){J c=[],2o={};1U{R(J i=0,K=a.K;i<K;i++){J b=D.L(a[i]);G(!2o[b]){2o[b]=M;c.1p(a[i])}}}1V(e){c=a}I c},3C:H(c,a,d){J b=[];R(J i=0,K=c.K;i<K;i++)G(!d!=!a(c[i],i))b.1p(c[i]);I b},2l:H(d,a){J c=[];R(J i=0,K=d.K;i<K;i++){J b=a(d[i],i);G(b!=U)c[c.K]=b}I c.7d.1w([],c)}});J v=9B.9A.3y();D.14={5B:(v.1I(/.+(?:9y|9x|9w|9v)[\\/: ]([\\d.]+)/)||[])[1],2k:/75/.11(v),2G:/2G/.11(v),1f:/1f/.11(v)&&!/2G/.11(v),42:/42/.11(v)&&!/(9s|75)/.11(v)};J y=D.14.1f?"7o":"72";D.1l({71:!D.14.1f||S.70=="6Z",3X:{"R":"9n","9k":"1F","4i":y,72:y,7o:y,9h:"9f",9e:"9d",9b:"99"}});D.P({6W:H(a){I a.1d},97:H(a){I D.4S(a,"1d")},95:H(a){I D.3a(a,2,"2H")},91:H(a){I D.3a(a,2,"4l")},8Z:H(a){I D.4S(a,"2H")},8X:H(a){I D.4S(a,"4l")},8W:H(a){I D.5v(a.1d.1x,a)},8V:H(a){I D.5v(a.1x)},6Q:H(a){I D.Y(a,"8U")?a.8T||a.8S.S:D.2d(a.3t)}},H(c,d){D.17[c]=H(b){J a=D.2l(7,d);G(b&&1j b=="23")a=D.3g(b,a);I 7.2I(D.4r(a))}});D.P({6P:"3v",8Q:"6F",39:"6E",8P:"5q",8O:"7b"},H(c,b){D.17[c]=H(){J a=19;I 7.P(H(){R(J i=0,K=a.K;i<K;i++)D(a[i])[b](7)})}});D.P({8N:H(a){D.1K(7,a,"");G(7.16==1)7.5l(a)},8M:H(a){D.1F.1e(7,a)},8L:H(a){D.1F.21(7,a)},8K:H(a){D.1F[D.1F.3T(7,a)?"21":"1e"](7,a)},21:H(a){G(!a||D.1E(a,[7]).r.K){D("*",7).1e(7).P(H(){D.W.21(7);D.3b(7)});G(7.1d)7.1d.37(7)}},4E:H(){D(">*",7).21();1B(7.1x)7.37(7.1x)}},H(a,b){D.17[a]=H(){I 7.P(b,19)}});D.P(["6N","4b"],H(i,c){J b=c.3y();D.17[b]=H(a){I 7[0]==1b?D.14.2G&&S.1c["5t"+c]||D.14.2k&&1b["5s"+c]||S.70=="6Z"&&S.1C["5t"+c]||S.1c["5t"+c]:7[0]==S?29.2f(29.2f(S.1c["4y"+c],S.1C["4y"+c]),29.2f(S.1c["2i"+c],S.1C["2i"+c])):a==12?(7.K?D.1g(7[0],b):U):7.1g(b,a.1q==56?a:a+"2X")}});H 25(a,b){I a[0]&&3r(D.2a(a[0],b,M),10)||0}J C=D.14.2k&&3r(D.14.5B)<8H?"(?:[\\\\w*3m-]|\\\\\\\\.)":"(?:[\\\\w\\8F-\\8E*3m-]|\\\\\\\\.)",6L=2B 4v("^>\\\\s*("+C+"+)"),6J=2B 4v("^("+C+"+)(#)("+C+"+)"),6I=2B 4v("^([#.]?)("+C+"*)");D.1l({6H:{"":H(a,i,m){I m[2]=="*"||D.Y(a,m[2])},"#":H(a,i,m){I a.4G("2v")==m[2]},":":{8D:H(a,i,m){I i<m[3]-0},8C:H(a,i,m){I i>m[3]-0},3a:H(a,i,m){I m[3]-0==i},79:H(a,i,m){I m[3]-0==i},3o:H(a,i){I i==0},3S:H(a,i,m,r){I i==r.K-1},6D:H(a,i){I i%2==0},6C:H(a,i){I i%2},"3o-4u":H(a){I a.1d.3H("*")[0]==a},"3S-4u":H(a){I D.3a(a.1d.5T,1,"4l")==a},"8z-4u":H(a){I!D.3a(a.1d.5T,2,"4l")},6W:H(a){I a.1x},4E:H(a){I!a.1x},8y:H(a,i,m){I(a.6O||a.8x||D(a).1r()||"").1h(m[3])>=0},4j:H(a){I"1G"!=a.O&&D.1g(a,"18")!="2F"&&D.1g(a,"5g")!="1G"},1G:H(a){I"1G"==a.O||D.1g(a,"18")=="2F"||D.1g(a,"5g")=="1G"},8w:H(a){I!a.3R},3R:H(a){I a.3R},4J:H(a){I a.4J},2W:H(a){I a.2W||D.1K(a,"2W")},1r:H(a){I"1r"==a.O},5O:H(a){I"5O"==a.O},5L:H(a){I"5L"==a.O},5p:H(a){I"5p"==a.O},3Q:H(a){I"3Q"==a.O},5o:H(a){I"5o"==a.O},6A:H(a){I"6A"==a.O},6z:H(a){I"6z"==a.O},2s:H(a){I"2s"==a.O||D.Y(a,"2s")},4T:H(a){I/4T|2A|6y|2s/i.11(a.Y)},3T:H(a,i,m){I D.2q(m[3],a).K},8t:H(a){I/h\\d/i.11(a.Y)},8s:H(a){I D.3C(D.3O,H(b){I a==b.T}).K}}},6x:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,2B 4v("^([:.#]*)("+C+"+)")],3g:H(a,c,b){J d,1t=[];1B(a&&a!=d){d=a;J f=D.1E(a,c,b);a=f.t.1o(/^\\s*,\\s*/,"");1t=b?c=f.r:D.2R(1t,f.r)}I 1t},2q:H(t,o){G(1j t!="23")I[t];G(o&&o.16!=1&&o.16!=9)I[];o=o||S;J d=[o],2o=[],3S,Y;1B(t&&3S!=t){J r=[];3S=t;t=D.3k(t);J l=Q,3j=6L,m=3j.2D(t);G(m){Y=m[1].2r();R(J i=0;d[i];i++)R(J c=d[i].1x;c;c=c.2H)G(c.16==1&&(Y=="*"||c.Y.2r()==Y))r.1p(c);d=r;t=t.1o(3j,"");G(t.1h(" ")==0)6M;l=M}N{3j=/^([>+~])\\s*(\\w*)/i;G((m=3j.2D(t))!=U){r=[];J k={};Y=m[2].2r();m=m[1];R(J j=0,3i=d.K;j<3i;j++){J n=m=="~"||m=="+"?d[j].2H:d[j].1x;R(;n;n=n.2H)G(n.16==1){J g=D.L(n);G(m=="~"&&k[g])1X;G(!Y||n.Y.2r()==Y){G(m=="~")k[g]=M;r.1p(n)}G(m=="+")1X}}d=r;t=D.3k(t.1o(3j,""));l=M}}G(t&&!l){G(!t.1h(",")){G(o==d[0])d.4s();2o=D.2R(2o,d);r=d=[o];t=" "+t.6v(1,t.K)}N{J h=6J;J m=h.2D(t);G(m){m=[0,m[2],m[3],m[1]]}N{h=6I;m=h.2D(t)}m[2]=m[2].1o(/\\\\/g,"");J f=d[d.K-1];G(m[1]=="#"&&f&&f.61&&!D.4n(f)){J p=f.61(m[2]);G((D.14.1f||D.14.2G)&&p&&1j p.2v=="23"&&p.2v!=m[2])p=D(\'[@2v="\'+m[2]+\'"]\',f)[0];d=r=p&&(!m[3]||D.Y(p,m[3]))?[p]:[]}N{R(J i=0;d[i];i++){J a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];G(a=="*"&&d[i].Y.3y()=="49")a="3n";r=D.2R(r,d[i].3H(a))}G(m[1]==".")r=D.5m(r,m[2]);G(m[1]=="#"){J e=[];R(J i=0;r[i];i++)G(r[i].4G("2v")==m[2]){e=[r[i]];1X}r=e}d=r}t=t.1o(h,"")}}G(t){J b=D.1E(t,r);d=r=b.r;t=D.3k(b.t)}}G(t)d=[];G(d&&o==d[0])d.4s();2o=D.2R(2o,d);I 2o},5m:H(r,m,a){m=" "+m+" ";J c=[];R(J i=0;r[i];i++){J b=(" "+r[i].1F+" ").1h(m)>=0;G(!a&&b||a&&!b)c.1p(r[i])}I c},1E:H(t,r,h){J d;1B(t&&t!=d){d=t;J p=D.6x,m;R(J i=0;p[i];i++){m=p[i].2D(t);G(m){t=t.8r(m[0].K);m[2]=m[2].1o(/\\\\/g,"");1X}}G(!m)1X;G(m[1]==":"&&m[2]=="4Y")r=62.11(m[3])?D.1E(m[3],r,M).r:D(r).4Y(m[3]);N G(m[1]==".")r=D.5m(r,m[2],h);N G(m[1]=="["){J g=[],O=m[3];R(J i=0,3i=r.K;i<3i;i++){J a=r[i],z=a[D.3X[m[2]]||m[2]];G(z==U||/5Q|4d|2W/.11(m[2]))z=D.1K(a,m[2])||\'\';G((O==""&&!!z||O=="="&&z==m[5]||O=="!="&&z!=m[5]||O=="^="&&z&&!z.1h(m[5])||O=="$="&&z.6v(z.K-m[5].K)==m[5]||(O=="*="||O=="~=")&&z.1h(m[5])>=0)^h)g.1p(a)}r=g}N G(m[1]==":"&&m[2]=="3a-4u"){J e={},g=[],11=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2D(m[3]=="6D"&&"2n"||m[3]=="6C"&&"2n+1"||!/\\D/.11(m[3])&&"8q+"+m[3]||m[3]),3o=(11[1]+(11[2]||1))-0,d=11[3]-0;R(J i=0,3i=r.K;i<3i;i++){J j=r[i],1d=j.1d,2v=D.L(1d);G(!e[2v]){J c=1;R(J n=1d.1x;n;n=n.2H)G(n.16==1)n.4q=c++;e[2v]=M}J b=Q;G(3o==0){G(j.4q==d)b=M}N G((j.4q-d)%3o==0&&(j.4q-d)/3o>=0)b=M;G(b^h)g.1p(j)}r=g}N{J f=D.6H[m[1]];G(1j f=="49")f=f[m[2]];G(1j f=="23")f=6u("Q||H(a,i){I "+f+";}");r=D.3C(r,H(a,i){I f(a,i,m,r)},h)}}I{r:r,t:t}},4S:H(b,c){J a=[],1t=b[c];1B(1t&&1t!=S){G(1t.16==1)a.1p(1t);1t=1t[c]}I a},3a:H(a,e,c,b){e=e||1;J d=0;R(;a;a=a[c])G(a.16==1&&++d==e)1X;I a},5v:H(n,a){J r=[];R(;n;n=n.2H){G(n.16==1&&n!=a)r.1p(n)}I r}});D.W={1e:H(f,i,g,e){G(f.16==3||f.16==8)I;G(D.14.1f&&f.4I)f=1b;G(!g.24)g.24=7.24++;G(e!=12){J h=g;g=7.3M(h,H(){I h.1w(7,19)});g.L=e}J j=D.L(f,"3w")||D.L(f,"3w",{}),1H=D.L(f,"1H")||D.L(f,"1H",H(){G(1j D!="12"&&!D.W.5k)I D.W.1H.1w(19.3L.T,19)});1H.T=f;D.P(i.1R(/\\s+/),H(c,b){J a=b.1R(".");b=a[0];g.O=a[1];J d=j[b];G(!d){d=j[b]={};G(!D.W.2t[b]||D.W.2t[b].4p.1k(f)===Q){G(f.3K)f.3K(b,1H,Q);N G(f.6t)f.6t("4o"+b,1H)}}d[g.24]=g;D.W.26[b]=M});f=U},24:1,26:{},21:H(e,h,f){G(e.16==3||e.16==8)I;J i=D.L(e,"3w"),1L,5i;G(i){G(h==12||(1j h=="23"&&h.8p(0)=="."))R(J g 1n i)7.21(e,g+(h||""));N{G(h.O){f=h.2y;h=h.O}D.P(h.1R(/\\s+/),H(b,a){J c=a.1R(".");a=c[0];G(i[a]){G(f)2U i[a][f.24];N R(f 1n i[a])G(!c[1]||i[a][f].O==c[1])2U i[a][f];R(1L 1n i[a])1X;G(!1L){G(!D.W.2t[a]||D.W.2t[a].4A.1k(e)===Q){G(e.6p)e.6p(a,D.L(e,"1H"),Q);N G(e.6n)e.6n("4o"+a,D.L(e,"1H"))}1L=U;2U i[a]}}})}R(1L 1n i)1X;G(!1L){J d=D.L(e,"1H");G(d)d.T=U;D.3b(e,"3w");D.3b(e,"1H")}}},1P:H(h,c,f,g,i){c=D.2d(c);G(h.1h("!")>=0){h=h.3s(0,-1);J a=M}G(!f){G(7.26[h])D("*").1e([1b,S]).1P(h,c)}N{G(f.16==3||f.16==8)I 12;J b,1L,17=D.1D(f[h]||U),W=!c[0]||!c[0].32;G(W){c.6h({O:h,2J:f,32:H(){},3J:H(){},4C:1z()});c[0][E]=M}c[0].O=h;G(a)c[0].6m=M;J d=D.L(f,"1H");G(d)b=d.1w(f,c);G((!17||(D.Y(f,\'a\')&&h=="4V"))&&f["4o"+h]&&f["4o"+h].1w(f,c)===Q)b=Q;G(W)c.4s();G(i&&D.1D(i)){1L=i.1w(f,b==U?c:c.7d(b));G(1L!==12)b=1L}G(17&&g!==Q&&b!==Q&&!(D.Y(f,\'a\')&&h=="4V")){7.5k=M;1U{f[h]()}1V(e){}}7.5k=Q}I b},1H:H(b){J a,1L,38,5f,4m;b=19[0]=D.W.6l(b||1b.W);38=b.O.1R(".");b.O=38[0];38=38[1];5f=!38&&!b.6m;4m=(D.L(7,"3w")||{})[b.O];R(J j 1n 4m){J c=4m[j];G(5f||c.O==38){b.2y=c;b.L=c.L;1L=c.1w(7,19);G(a!==Q)a=1L;G(1L===Q){b.32();b.3J()}}}I a},6l:H(b){G(b[E]==M)I b;J d=b;b={8o:d};J c="8n 8m 8l 8k 2s 8j 47 5d 6j 5E 8i L 8h 8g 4K 2y 5a 59 8e 8b 58 6f 8a 88 4k 87 86 84 6d 2J 4C 6c O 82 81 35".1R(" ");R(J i=c.K;i;i--)b[c[i]]=d[c[i]];b[E]=M;b.32=H(){G(d.32)d.32();d.80=Q};b.3J=H(){G(d.3J)d.3J();d.7Z=M};b.4C=b.4C||1z();G(!b.2J)b.2J=b.6d||S;G(b.2J.16==3)b.2J=b.2J.1d;G(!b.4k&&b.4K)b.4k=b.4K==b.2J?b.6c:b.4K;G(b.58==U&&b.5d!=U){J a=S.1C,1c=S.1c;b.58=b.5d+(a&&a.2e||1c&&1c.2e||0)-(a.6b||0);b.6f=b.6j+(a&&a.2c||1c&&1c.2c||0)-(a.6a||0)}G(!b.35&&((b.47||b.47===0)?b.47:b.5a))b.35=b.47||b.5a;G(!b.59&&b.5E)b.59=b.5E;G(!b.35&&b.2s)b.35=(b.2s&1?1:(b.2s&2?3:(b.2s&4?2:0)));I b},3M:H(a,b){b.24=a.24=a.24||b.24||7.24++;I b},2t:{27:{4p:H(){55();I},4A:H(){I}},3D:{4p:H(){G(D.14.1f)I Q;D(7).2O("53",D.W.2t.3D.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("53",D.W.2t.3D.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3D";I D.W.1H.1w(7,19)}},3N:{4p:H(){G(D.14.1f)I Q;D(7).2O("51",D.W.2t.3N.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("51",D.W.2t.3N.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3N";I D.W.1H.1w(7,19)}}}};D.17.1l({2O:H(c,a,b){I c=="4X"?7.2V(c,a,b):7.P(H(){D.W.1e(7,c,b||a,b&&a)})},2V:H(d,b,c){J e=D.W.3M(c||b,H(a){D(7).4e(a,e);I(c||b).1w(7,19)});I 7.P(H(){D.W.1e(7,d,e,c&&b)})},4e:H(a,b){I 7.P(H(){D.W.21(7,a,b)})},1P:H(c,a,b){I 7.P(H(){D.W.1P(c,a,7,M,b)})},5C:H(c,a,b){I 7[0]&&D.W.1P(c,a,7[0],Q,b)},2m:H(b){J c=19,i=1;1B(i<c.K)D.W.3M(b,c[i++]);I 7.4V(D.W.3M(b,H(a){7.4Z=(7.4Z||0)%i;a.32();I c[7.4Z++].1w(7,19)||Q}))},7X:H(a,b){I 7.2O(\'3D\',a).2O(\'3N\',b)},27:H(a){55();G(D.2Q)a.1k(S,D);N D.3A.1p(H(){I a.1k(7,D)});I 7}});D.1l({2Q:Q,3A:[],27:H(){G(!D.2Q){D.2Q=M;G(D.3A){D.P(D.3A,H(){7.1k(S)});D.3A=U}D(S).5C("27")}}});J x=Q;H 55(){G(x)I;x=M;G(S.3K&&!D.14.2G)S.3K("69",D.27,Q);G(D.14.1f&&1b==1S)(H(){G(D.2Q)I;1U{S.1C.7V("1A")}1V(3e){3B(19.3L,0);I}D.27()})();G(D.14.2G)S.3K("69",H(){G(D.2Q)I;R(J i=0;i<S.4W.K;i++)G(S.4W[i].3R){3B(19.3L,0);I}D.27()},Q);G(D.14.2k){J a;(H(){G(D.2Q)I;G(S.3f!="68"&&S.3f!="1J"){3B(19.3L,0);I}G(a===12)a=D("V, 7A[7U=7S]").K;G(S.4W.K!=a){3B(19.3L,0);I}D.27()})()}D.W.1e(1b,"43",D.27)}D.P(("7R,7Q,43,85,4y,4X,4V,7P,"+"7O,7N,89,53,51,7M,2A,"+"5o,7L,7K,8d,3e").1R(","),H(i,b){D.17[b]=H(a){I a?7.2O(b,a):7.1P(b)}});J F=H(a,c){J b=a.4k;1B(b&&b!=c)1U{b=b.1d}1V(3e){b=c}I b==c};D(1b).2O("4X",H(){D("*").1e(S).4e()});D.17.1l({67:D.17.43,43:H(g,d,c){G(1j g!=\'23\')I 7.67(g);J e=g.1h(" ");G(e>=0){J i=g.3s(e,g.K);g=g.3s(0,e)}c=c||H(){};J f="2P";G(d)G(D.1D(d)){c=d;d=U}N{d=D.3n(d);f="6g"}J h=7;D.3Y({1a:g,O:f,1O:"2K",L:d,1J:H(a,b){G(b=="1W"||b=="7J")h.2K(i?D("<1v/>").3v(a.4U.1o(/<1m(.|\\s)*?\\/1m>/g,"")).2q(i):a.4U);h.P(c,[a.4U,b,a])}});I 7},aL:H(){I D.3n(7.7I())},7I:H(){I 7.2l(H(){I D.Y(7,"3V")?D.2d(7.aH):7}).1E(H(){I 7.34&&!7.3R&&(7.4J||/2A|6y/i.11(7.Y)||/1r|1G|3Q/i.11(7.O))}).2l(H(i,c){J b=D(7).6e();I b==U?U:b.1q==2p?D.2l(b,H(a,i){I{34:c.34,2x:a}}):{34:c.34,2x:b}}).3p()}});D.P("7H,7G,7F,7D,7C,7B".1R(","),H(i,o){D.17[o]=H(f){I 7.2O(o,f)}});J B=1z();D.1l({3p:H(d,b,a,c){G(D.1D(b)){a=b;b=U}I D.3Y({O:"2P",1a:d,L:b,1W:a,1O:c})},aE:H(b,a){I D.3p(b,U,a,"1m")},aD:H(c,b,a){I D.3p(c,b,a,"3z")},aC:H(d,b,a,c){G(D.1D(b)){a=b;b={}}I D.3Y({O:"6g",1a:d,L:b,1W:a,1O:c})},aA:H(a){D.1l(D.60,a)},60:{1a:5Z.5Q,26:M,O:"2P",2T:0,7z:"4R/x-ax-3V-aw",7x:M,31:M,L:U,5Y:U,3Q:U,4Q:{2N:"4R/2N, 1r/2N",2K:"1r/2K",1m:"1r/4t, 4R/4t",3z:"4R/3z, 1r/4t",1r:"1r/as",4w:"*/*"}},4z:{},3Y:H(s){s=D.1l(M,s,D.1l(M,{},D.60,s));J g,2Z=/=\\?(&|$)/g,1u,L,O=s.O.2r();G(s.L&&s.7x&&1j s.L!="23")s.L=D.3n(s.L);G(s.1O=="4P"){G(O=="2P"){G(!s.1a.1I(2Z))s.1a+=(s.1a.1I(/\\?/)?"&":"?")+(s.4P||"7u")+"=?"}N G(!s.L||!s.L.1I(2Z))s.L=(s.L?s.L+"&":"")+(s.4P||"7u")+"=?";s.1O="3z"}G(s.1O=="3z"&&(s.L&&s.L.1I(2Z)||s.1a.1I(2Z))){g="4P"+B++;G(s.L)s.L=(s.L+"").1o(2Z,"="+g+"$1");s.1a=s.1a.1o(2Z,"="+g+"$1");s.1O="1m";1b[g]=H(a){L=a;1W();1J();1b[g]=12;1U{2U 1b[g]}1V(e){}G(i)i.37(h)}}G(s.1O=="1m"&&s.1Y==U)s.1Y=Q;G(s.1Y===Q&&O=="2P"){J j=1z();J k=s.1a.1o(/(\\?|&)3m=.*?(&|$)/,"$ap="+j+"$2");s.1a=k+((k==s.1a)?(s.1a.1I(/\\?/)?"&":"?")+"3m="+j:"")}G(s.L&&O=="2P"){s.1a+=(s.1a.1I(/\\?/)?"&":"?")+s.L;s.L=U}G(s.26&&!D.4O++)D.W.1P("7H");J n=/^(?:\\w+:)?\\/\\/([^\\/?#]+)/;G(s.1O=="1m"&&O=="2P"&&n.11(s.1a)&&n.2D(s.1a)[1]!=5Z.al){J i=S.3H("6w")[0];J h=S.3h("1m");h.4d=s.1a;G(s.7t)h.aj=s.7t;G(!g){J l=Q;h.ah=h.ag=H(){G(!l&&(!7.3f||7.3f=="68"||7.3f=="1J")){l=M;1W();1J();i.37(h)}}}i.3U(h);I 12}J m=Q;J c=1b.7s?2B 7s("ae.ac"):2B 7r();G(s.5Y)c.6R(O,s.1a,s.31,s.5Y,s.3Q);N c.6R(O,s.1a,s.31);1U{G(s.L)c.4B("ab-aa",s.7z);G(s.5S)c.4B("a9-5R-a8",D.4z[s.1a]||"a7, a6 a5 a4 5N:5N:5N a2");c.4B("X-9Z-9Y","7r");c.4B("9W",s.1O&&s.4Q[s.1O]?s.4Q[s.1O]+", */*":s.4Q.4w)}1V(e){}G(s.7m&&s.7m(c,s)===Q){s.26&&D.4O--;c.7l();I Q}G(s.26)D.W.1P("7B",[c,s]);J d=H(a){G(!m&&c&&(c.3f==4||a=="2T")){m=M;G(f){7k(f);f=U}1u=a=="2T"&&"2T"||!D.7j(c)&&"3e"||s.5S&&D.7h(c,s.1a)&&"7J"||"1W";G(1u=="1W"){1U{L=D.6X(c,s.1O,s.9S)}1V(e){1u="5J"}}G(1u=="1W"){J b;1U{b=c.5I("7g-5R")}1V(e){}G(s.5S&&b)D.4z[s.1a]=b;G(!g)1W()}N D.5H(s,c,1u);1J();G(s.31)c=U}};G(s.31){J f=4I(d,13);G(s.2T>0)3B(H(){G(c){c.7l();G(!m)d("2T")}},s.2T)}1U{c.9P(s.L)}1V(e){D.5H(s,c,U,e)}G(!s.31)d();H 1W(){G(s.1W)s.1W(L,1u);G(s.26)D.W.1P("7C",[c,s])}H 1J(){G(s.1J)s.1J(c,1u);G(s.26)D.W.1P("7F",[c,s]);G(s.26&&!--D.4O)D.W.1P("7G")}I c},5H:H(s,a,b,e){G(s.3e)s.3e(a,b,e);G(s.26)D.W.1P("7D",[a,s,e])},4O:0,7j:H(a){1U{I!a.1u&&5Z.9O=="5p:"||(a.1u>=7e&&a.1u<9N)||a.1u==7c||a.1u==9K||D.14.2k&&a.1u==12}1V(e){}I Q},7h:H(a,c){1U{J b=a.5I("7g-5R");I a.1u==7c||b==D.4z[c]||D.14.2k&&a.1u==12}1V(e){}I Q},6X:H(a,c,b){J d=a.5I("9J-O"),2N=c=="2N"||!c&&d&&d.1h("2N")>=0,L=2N?a.9I:a.4U;G(2N&&L.1C.2j=="5J")7p"5J";G(b)L=b(L,c);G(c=="1m")D.5u(L);G(c=="3z")L=6u("("+L+")");I L},3n:H(a){J s=[];G(a.1q==2p||a.5w)D.P(a,H(){s.1p(3u(7.34)+"="+3u(7.2x))});N R(J j 1n a)G(a[j]&&a[j].1q==2p)D.P(a[j],H(){s.1p(3u(j)+"="+3u(7))});N s.1p(3u(j)+"="+3u(D.1D(a[j])?a[j]():a[j]));I s.6s("&").1o(/%20/g,"+")}});D.17.1l({1N:H(c,b){I c?7.2g({1Z:"1N",2h:"1N",1y:"1N"},c,b):7.1E(":1G").P(H(){7.V.18=7.5D||"";G(D.1g(7,"18")=="2F"){J a=D("<"+7.2j+" />").6P("1c");7.V.18=a.1g("18");G(7.V.18=="2F")7.V.18="3I";a.21()}}).3l()},1M:H(b,a){I b?7.2g({1Z:"1M",2h:"1M",1y:"1M"},b,a):7.1E(":4j").P(H(){7.5D=7.5D||D.1g(7,"18");7.V.18="2F"}).3l()},78:D.17.2m,2m:H(a,b){I D.1D(a)&&D.1D(b)?7.78.1w(7,19):a?7.2g({1Z:"2m",2h:"2m",1y:"2m"},a,b):7.P(H(){D(7)[D(7).3F(":1G")?"1N":"1M"]()})},9G:H(b,a){I 7.2g({1Z:"1N"},b,a)},9F:H(b,a){I 7.2g({1Z:"1M"},b,a)},9E:H(b,a){I 7.2g({1Z:"2m"},b,a)},9D:H(b,a){I 7.2g({1y:"1N"},b,a)},9M:H(b,a){I 7.2g({1y:"1M"},b,a)},9C:H(c,a,b){I 7.2g({1y:a},c,b)},2g:H(k,j,i,g){J h=D.77(j,i,g);I 7[h.36===Q?"P":"36"](H(){G(7.16!=1)I Q;J f=D.1l({},h),p,1G=D(7).3F(":1G"),46=7;R(p 1n k){G(k[p]=="1M"&&1G||k[p]=="1N"&&!1G)I f.1J.1k(7);G(p=="1Z"||p=="2h"){f.18=D.1g(7,"18");f.33=7.V.33}}G(f.33!=U)7.V.33="1G";f.45=D.1l({},k);D.P(k,H(c,a){J e=2B D.28(46,f,c);G(/2m|1N|1M/.11(a))e[a=="2m"?1G?"1N":"1M":a](k);N{J b=a.6r().1I(/^([+-]=)?([\\d+-.]+)(.*)$/),2b=e.1t(M)||0;G(b){J d=3d(b[2]),2M=b[3]||"2X";G(2M!="2X"){46.V[c]=(d||1)+2M;2b=((d||1)/e.1t(M))*2b;46.V[c]=2b+2M}G(b[1])d=((b[1]=="-="?-1:1)*d)+2b;e.3G(2b,d,2M)}N e.3G(2b,a,"")}});I M})},36:H(a,b){G(D.1D(a)||(a&&a.1q==2p)){b=a;a="28"}G(!a||(1j a=="23"&&!b))I A(7[0],a);I 7.P(H(){G(b.1q==2p)A(7,a,b);N{A(7,a).1p(b);G(A(7,a).K==1)b.1k(7)}})},9X:H(b,c){J a=D.3O;G(b)7.36([]);7.P(H(){R(J i=a.K-1;i>=0;i--)G(a[i].T==7){G(c)a[i](M);a.7n(i,1)}});G(!c)7.5A();I 7}});J A=H(b,c,a){G(b){c=c||"28";J q=D.L(b,c+"36");G(!q||a)q=D.L(b,c+"36",D.2d(a))}I q};D.17.5A=H(a){a=a||"28";I 7.P(H(){J q=A(7,a);q.4s();G(q.K)q[0].1k(7)})};D.1l({77:H(b,a,c){J d=b&&b.1q==a0?b:{1J:c||!c&&a||D.1D(b)&&b,2u:b,41:c&&a||a&&a.1q!=9t&&a};d.2u=(d.2u&&d.2u.1q==4L?d.2u:D.28.5K[d.2u])||D.28.5K.74;d.5M=d.1J;d.1J=H(){G(d.36!==Q)D(7).5A();G(D.1D(d.5M))d.5M.1k(7)};I d},41:{73:H(p,n,b,a){I b+a*p},5P:H(p,n,b,a){I((-29.9r(p*29.9q)/2)+0.5)*a+b}},3O:[],48:U,28:H(b,c,a){7.15=c;7.T=b;7.1i=a;G(!c.3Z)c.3Z={}}});D.28.44={4D:H(){G(7.15.2Y)7.15.2Y.1k(7.T,7.1z,7);(D.28.2Y[7.1i]||D.28.2Y.4w)(7);G(7.1i=="1Z"||7.1i=="2h")7.T.V.18="3I"},1t:H(a){G(7.T[7.1i]!=U&&7.T.V[7.1i]==U)I 7.T[7.1i];J r=3d(D.1g(7.T,7.1i,a));I r&&r>-9p?r:3d(D.2a(7.T,7.1i))||0},3G:H(c,b,d){7.5V=1z();7.2b=c;7.3l=b;7.2M=d||7.2M||"2X";7.1z=7.2b;7.2S=7.4N=0;7.4D();J e=7;H t(a){I e.2Y(a)}t.T=7.T;D.3O.1p(t);G(D.48==U){D.48=4I(H(){J a=D.3O;R(J i=0;i<a.K;i++)G(!a[i]())a.7n(i--,1);G(!a.K){7k(D.48);D.48=U}},13)}},1N:H(){7.15.3Z[7.1i]=D.1K(7.T.V,7.1i);7.15.1N=M;7.3G(0,7.1t());G(7.1i=="2h"||7.1i=="1Z")7.T.V[7.1i]="9m";D(7.T).1N()},1M:H(){7.15.3Z[7.1i]=D.1K(7.T.V,7.1i);7.15.1M=M;7.3G(7.1t(),0)},2Y:H(a){J t=1z();G(a||t>7.15.2u+7.5V){7.1z=7.3l;7.2S=7.4N=1;7.4D();7.15.45[7.1i]=M;J b=M;R(J i 1n 7.15.45)G(7.15.45[i]!==M)b=Q;G(b){G(7.15.18!=U){7.T.V.33=7.15.33;7.T.V.18=7.15.18;G(D.1g(7.T,"18")=="2F")7.T.V.18="3I"}G(7.15.1M)7.T.V.18="2F";G(7.15.1M||7.15.1N)R(J p 1n 7.15.45)D.1K(7.T.V,p,7.15.3Z[p])}G(b)7.15.1J.1k(7.T);I Q}N{J n=t-7.5V;7.4N=n/7.15.2u;7.2S=D.41[7.15.41||(D.41.5P?"5P":"73")](7.4N,n,0,1,7.15.2u);7.1z=7.2b+((7.3l-7.2b)*7.2S);7.4D()}I M}};D.1l(D.28,{5K:{9l:9j,9i:7e,74:9g},2Y:{2e:H(a){a.T.2e=a.1z},2c:H(a){a.T.2c=a.1z},1y:H(a){D.1K(a.T.V,"1y",a.1z)},4w:H(a){a.T.V[a.1i]=a.1z+a.2M}}});D.17.2i=H(){J b=0,1S=0,T=7[0],3q;G(T)ao(D.14){J d=T.1d,4a=T,1s=T.1s,1Q=T.2z,5U=2k&&3r(5B)<9c&&!/9a/i.11(v),1g=D.2a,3c=1g(T,"30")=="3c";G(T.7y){J c=T.7y();1e(c.1A+29.2f(1Q.1C.2e,1Q.1c.2e),c.1S+29.2f(1Q.1C.2c,1Q.1c.2c));1e(-1Q.1C.6b,-1Q.1C.6a)}N{1e(T.5X,T.5W);1B(1s){1e(1s.5X,1s.5W);G(42&&!/^t(98|d|h)$/i.11(1s.2j)||2k&&!5U)2C(1s);G(!3c&&1g(1s,"30")=="3c")3c=M;4a=/^1c$/i.11(1s.2j)?4a:1s;1s=1s.1s}1B(d&&d.2j&&!/^1c|2K$/i.11(d.2j)){G(!/^96|1T.*$/i.11(1g(d,"18")))1e(-d.2e,-d.2c);G(42&&1g(d,"33")!="4j")2C(d);d=d.1d}G((5U&&(3c||1g(4a,"30")=="5x"))||(42&&1g(4a,"30")!="5x"))1e(-1Q.1c.5X,-1Q.1c.5W);G(3c)1e(29.2f(1Q.1C.2e,1Q.1c.2e),29.2f(1Q.1C.2c,1Q.1c.2c))}3q={1S:1S,1A:b}}H 2C(a){1e(D.2a(a,"6V",M),D.2a(a,"6U",M))}H 1e(l,t){b+=3r(l,10)||0;1S+=3r(t,10)||0}I 3q};D.17.1l({30:H(){J a=0,1S=0,3q;G(7[0]){J b=7.1s(),2i=7.2i(),4c=/^1c|2K$/i.11(b[0].2j)?{1S:0,1A:0}:b.2i();2i.1S-=25(7,\'94\');2i.1A-=25(7,\'aF\');4c.1S+=25(b,\'6U\');4c.1A+=25(b,\'6V\');3q={1S:2i.1S-4c.1S,1A:2i.1A-4c.1A}}I 3q},1s:H(){J a=7[0].1s;1B(a&&(!/^1c|2K$/i.11(a.2j)&&D.1g(a,\'30\')==\'93\'))a=a.1s;I D(a)}});D.P([\'5e\',\'5G\'],H(i,b){J c=\'4y\'+b;D.17[c]=H(a){G(!7[0])I;I a!=12?7.P(H(){7==1b||7==S?1b.92(!i?a:D(1b).2e(),i?a:D(1b).2c()):7[c]=a}):7[0]==1b||7[0]==S?46[i?\'aI\':\'aJ\']||D.71&&S.1C[c]||S.1c[c]:7[0][c]}});D.P(["6N","4b"],H(i,b){J c=i?"5e":"5G",4f=i?"6k":"6i";D.17["5s"+b]=H(){I 7[b.3y()]()+25(7,"57"+c)+25(7,"57"+4f)};D.17["90"+b]=H(a){I 7["5s"+b]()+25(7,"2C"+c+"4b")+25(7,"2C"+4f+"4b")+(a?25(7,"6S"+c)+25(7,"6S"+4f):0)}})})();',62,669,'|||||||this|||||||||||||||||||||||||||||||||||if|function|return|var|length|data|true|else|type|each|false|for|document|elem|null|style|event||nodeName|||test|undefined||browser|options|nodeType|fn|display|arguments|url|window|body|parentNode|add|msie|css|indexOf|prop|typeof|call|extend|script|in|replace|push|constructor|text|offsetParent|cur|status|div|apply|firstChild|opacity|now|left|while|documentElement|isFunction|filter|className|hidden|handle|match|complete|attr|ret|hide|show|dataType|trigger|doc|split|top|table|try|catch|success|break|cache|height||remove|tbody|string|guid|num|global|ready|fx|Math|curCSS|start|scrollTop|makeArray|scrollLeft|max|animate|width|offset|tagName|safari|map|toggle||done|Array|find|toUpperCase|button|special|duration|id|copy|value|handler|ownerDocument|select|new|border|exec|stack|none|opera|nextSibling|pushStack|target|html|inArray|unit|xml|bind|GET|isReady|merge|pos|timeout|delete|one|selected|px|step|jsre|position|async|preventDefault|overflow|name|which|queue|removeChild|namespace|insertBefore|nth|removeData|fixed|parseFloat|error|readyState|multiFilter|createElement|rl|re|trim|end|_|param|first|get|results|parseInt|slice|childNodes|encodeURIComponent|append|events|elems|toLowerCase|json|readyList|setTimeout|grep|mouseenter|color|is|custom|getElementsByTagName|block|stopPropagation|addEventListener|callee|proxy|mouseleave|timers|defaultView|password|disabled|last|has|appendChild|form|domManip|props|ajax|orig|set|easing|mozilla|load|prototype|curAnim|self|charCode|timerId|object|offsetChild|Width|parentOffset|src|unbind|br|currentStyle|clean|float|visible|relatedTarget|previousSibling|handlers|isXMLDoc|on|setup|nodeIndex|unique|shift|javascript|child|RegExp|_default|deep|scroll|lastModified|teardown|setRequestHeader|timeStamp|update|empty|tr|getAttribute|innerHTML|setInterval|checked|fromElement|Number|jQuery|state|active|jsonp|accepts|application|dir|input|responseText|click|styleSheets|unload|not|lastToggle|outline|mouseout|getPropertyValue|mouseover|getComputedStyle|bindReady|String|padding|pageX|metaKey|keyCode|getWH|andSelf|clientX|Left|all|visibility|container|index|init|triggered|removeAttribute|classFilter|prevObject|submit|file|after|windowData|inner|client|globalEval|sibling|jquery|absolute|clone|wrapAll|dequeue|version|triggerHandler|oldblock|ctrlKey|createTextNode|Top|handleError|getResponseHeader|parsererror|speeds|checkbox|old|00|radio|swing|href|Modified|ifModified|lastChild|safari2|startTime|offsetTop|offsetLeft|username|location|ajaxSettings|getElementById|isSimple|values|selectedIndex|runtimeStyle|rsLeft|_load|loaded|DOMContentLoaded|clientTop|clientLeft|toElement|srcElement|val|pageY|POST|unshift|Bottom|clientY|Right|fix|exclusive|detachEvent|cloneNode|removeEventListener|swap|toString|join|attachEvent|eval|substr|head|parse|textarea|reset|image|zoom|odd|even|before|prepend|exclude|expr|quickClass|quickID|uuid|quickChild|continue|Height|textContent|appendTo|contents|open|margin|evalScript|borderTopWidth|borderLeftWidth|parent|httpData|setArray|CSS1Compat|compatMode|boxModel|cssFloat|linear|def|webkit|nodeValue|speed|_toggle|eq|100|replaceWith|304|concat|200|alpha|Last|httpNotModified|getAttributeNode|httpSuccess|clearInterval|abort|beforeSend|splice|styleFloat|throw|colgroup|XMLHttpRequest|ActiveXObject|scriptCharset|callback|fieldset|multiple|processData|getBoundingClientRect|contentType|link|ajaxSend|ajaxSuccess|ajaxError|col|ajaxComplete|ajaxStop|ajaxStart|serializeArray|notmodified|keypress|keydown|change|mouseup|mousedown|dblclick|focus|blur|stylesheet|hasClass|rel|doScroll|black|hover|solid|cancelBubble|returnValue|wheelDelta|view|round|shiftKey|resize|screenY|screenX|relatedNode|mousemove|prevValue|originalTarget|offsetHeight|keyup|newValue|offsetWidth|eventPhase|detail|currentTarget|cancelable|bubbles|attrName|attrChange|altKey|originalEvent|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|font|gt|lt|uFFFF|u0128|size|417|Boolean|Date|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|wrap|contentWindow|contentDocument|iframe|children|siblings|prevAll|wrapInner|nextAll|outer|prev|scrollTo|static|marginTop|next|inline|parents|able|cellSpacing|adobeair|cellspacing|522|maxLength|maxlength|readOnly|400|readonly|fast|600|class|slow|1px|htmlFor|reverse|10000|PI|cos|compatible|Function|setData|ie|ra|it|rv|getData|userAgent|navigator|fadeTo|fadeIn|slideToggle|slideUp|slideDown|ig|responseXML|content|1223|NaN|fadeOut|300|protocol|send|setAttribute|option|dataFilter|cssText|changed|be|Accept|stop|With|Requested|Object|can|GMT|property|1970|Jan|01|Thu|Since|If|Type|Content|XMLHTTP|th|Microsoft|td|onreadystatechange|onload|cap|charset|colg|host|tfoot|specified|with|1_|thead|leg|plain|attributes|opt|embed|urlencoded|www|area|hr|ajaxSetup|meta|post|getJSON|getScript|marginLeft|img|elements|pageYOffset|pageXOffset|abbr|serialize|pixelLeft'.split('|'),0,{}))
Index: branches/0.11-stable/trac/htdocs/css/admin.css
===================================================================
--- branches/0.11-stable/trac/htdocs/css/admin.css (revision 5413)
+++ branches/0.11-stable/trac/htdocs/css/admin.css (revision 7320)
@@ -63,4 +63,6 @@
 
 /* Perm Panel */
-#permlist div { width: 13em; float: left; }
+#permlist div { float: left; min-width: 13em; max-width: 33%;
+  padding: 0 2em 0 0;
+}
 fieldset tr.field th { text-align: right; }
Index: branches/0.11-stable/trac/htdocs/css/report.css
===================================================================
--- branches/0.11-stable/trac/htdocs/css/report.css (revision 6621)
+++ branches/0.11-stable/trac/htdocs/css/report.css (revision 7294)
@@ -7,5 +7,5 @@
  font-weight: normal; 
 }
-h2 {
+h2.report-result {
  background: #f7f7f7;
  border-bottom: 1px solid #d7d7d7;
@@ -87,5 +87,5 @@
 .tickets .fullrow hr { display: none }
 
-fieldset legend :link, fieldset legend :visited { 
+fieldset legend.foldable :link, fieldset legend.foldable :visited { 
  background: url(../expanded.png) 0 50% no-repeat;
  border: none;
@@ -94,9 +94,9 @@
  padding-left: 16px;
 }
-fieldset legend :link:hover, fieldset legend :visited:hover {
+fieldset legend.foldable :link:hover, fieldset legend.foldable :visited:hover {
   background-color: transparent;
 }
 
-fieldset.collapsed legend :link, fieldset.collapsed legend :visited { 
+fieldset.collapsed legend.foldable :link, fieldset.collapsed legend.foldable :visited { 
  background-image: url(../collapsed.png);  
 }
Index: branches/0.11-stable/trac/htdocs/css/roadmap.css
===================================================================
--- branches/0.11-stable/trac/htdocs/css/roadmap.css (revision 6011)
+++ branches/0.11-stable/trac/htdocs/css/roadmap.css (revision 7291)
@@ -23,5 +23,10 @@
 table.progress td.closed { background: #bae0ba }
 table.progress td :hover { background: none }
-p.percent { font-size: 10px; line-height: 2.4em; margin: 0.9em 0 0 }
+p.percent { 
+ font-size: 10px; 
+ line-height: 2.4em; 
+ margin: 0.9em 0 .1em 1.2em; 
+ float: left; 
+}
 
 /* Styles for the roadmap view */
@@ -49,5 +54,5 @@
  margin: 0;
 }
-.milestone .info .progress { margin: 1em 1em 0; width: 40em; max-width: 70% }
+.milestone .info .progress { margin: 1em 0 0 1em; width: 40em; max-width: 70% }
 .milestone .info dl {
  font-size: 10px;
@@ -55,4 +60,5 @@
  margin: 0 1em 2em;
  white-space: nowrap;
+ clear: left;
 }
 .milestone .info dt { display: inline; margin-left: .5em }
Index: branches/0.11-stable/trac/db/pool.py
===================================================================
--- branches/0.11-stable/trac/db/pool.py (revision 4680)
+++ branches/0.11-stable/trac/db/pool.py (revision 7317)
@@ -20,4 +20,5 @@
     import dummy_threading as threading
     threading._get_ident = lambda: 0
+import os
 import time
 
@@ -35,12 +36,13 @@
     """
 
-    def __init__(self, pool, cnx, tid):
+    def __init__(self, pool, cnx, key, tid):
         ConnectionWrapper.__init__(self, cnx)
         self._pool = pool
+        self._key = key
         self._tid = tid
 
     def close(self):
         if self.cnx:
-            self._pool._return_cnx(self.cnx, self._tid)
+            self._pool._return_cnx(self.cnx, self._key, self._tid)
             self.cnx = None
 
@@ -62,103 +64,107 @@
         return False
 
+
+class ConnectionPoolBackend(object):
+    """A process-wide LRU-based connection pool.
+    """
+    def __init__(self, maxsize):
+        self._available = threading.Condition(threading.RLock())
+        self._maxsize = maxsize
+        self._active = {}
+        self._pool = []
+        self._pool_key = []
+        self._pool_time = []
+
+    def get_cnx(self, connector, kwargs, timeout=None):
+        num = 1
+        cnx = None
+        key = unicode(kwargs)
+        start = time.time()
+        tid = threading._get_ident()
+        self._available.acquire()
+        try:
+            while True:
+                # First choice: Return the same cnx already used by the thread
+                if (tid, key) in self._active:
+                    cnx, num = self._active[(tid, key)]
+                    num += 1
+                # Second best option: Reuse a live pooled connection
+                elif key in self._pool_key:
+                    idx = self._pool_key.index(key)
+                    self._pool_key.pop(idx)
+                    self._pool_time.pop(idx)
+                    cnx = self._pool.pop(idx)
+                # Third best option: Create a new connection
+                elif len(self._active) + len(self._pool) < self._maxsize:
+                    cnx = connector.get_connection(**kwargs)
+                # Forth best option: Replace a pooled connection with a new one
+                elif len(self._active)  < self._maxsize:
+                    # Remove the LRU connection in the pool
+                    self._pool.pop(0).close()
+                    self._pool_key.pop(0)
+                    self._pool_time.pop(0)
+                    cnx = connector.get_connection(**kwargs)
+                if cnx:
+                    self._active[(tid, key)] = (cnx, num)
+                    return PooledConnection(self, cnx, key, tid)
+                # Worst option: wait until a connection pool slot is available
+                if timeout and (time.time() - start) > timeout:
+                    raise TimeoutError(_('Unable to get database '
+                                         'connection within %(time)d '
+                                         'seconds', time=timeout))
+                elif timeout:
+                    self._available.wait(timeout)
+                else:
+                    self._available.wait()
+        finally:
+            self._available.release()
+
+    def _return_cnx(self, cnx, key, tid):
+        self._available.acquire()
+        try:
+            assert (tid, key) in self._active
+            cnx, num = self._active[(tid, key)]
+            if num == 1 and cnx.poolable and try_rollback(cnx):
+                del self._active[(tid, key)]
+                self._pool.append(cnx)
+                self._pool_key.append(key)
+                self._pool_time.append(time.time())
+            elif num == 1:
+                del self._active[(tid, key)]
+            else:
+                self._active[(tid, key)] = (cnx, num - 1)
+        finally:
+            self._available.release()
+
+    def shutdown(self, tid=None):
+        """Close pooled connections not used in a while"""
+        delay = 120
+        if tid is None:
+            delay = 0
+        when = time.time() - delay
+        self._available.acquire()
+        try:
+            while self._pool_time and self._pool_time[0] <= when:
+                self._pool.pop(0)
+                self._pool_key.pop(0)
+                self._pool_time.pop(0)
+        finally:
+            self._available.release()
+
+
+_pool_size = int(os.environ.get('TRAC_DB_POOL_SIZE', 10))
+_backend = ConnectionPoolBackend(_pool_size)
+
+
 class ConnectionPool(object):
-    """A very simple connection pool implementation."""
-
     def __init__(self, maxsize, connector, **kwargs):
-        self._dormant = {} # inactive connections in pool
-        self._active = {} # active connections by thread ID
-        self._available = threading.Condition(threading.RLock())
-        self._maxsize = maxsize # maximum pool size
-        self._cursize = 0 # current pool size, includes active connections
+        # maxsize not used right now but kept for api compatibility
         self._connector = connector
         self._kwargs = kwargs
 
     def get_cnx(self, timeout=None):
-        start = time.time()
-        self._available.acquire()
-        try:
-            tid = threading._get_ident()
-            if tid in self._active:
-                num, cnx = self._active.get(tid)
-                if num == 0: # was pushed back (see _cleanup)
-                    if not try_rollback(cnx):
-                        del self._active[tid]
-                        cnx = None
-                if cnx:
-                    self._active[tid][0] = num + 1
-                    return PooledConnection(self, cnx, tid)
-            while True:
-                if self._dormant:
-                    if tid in self._dormant: # prefer same thread
-                        cnx = self._dormant.pop(tid)
-                    else: # pick a random one
-                        cnx = self._dormant.pop(self._dormant.keys()[0])
-                    if try_rollback(cnx):
-                        break
-                    else:
-                        self._cursize -= 1
-                elif self._maxsize and self._cursize < self._maxsize:
-                    cnx = self._connector.get_connection(**self._kwargs)
-                    self._cursize += 1
-                    break
-                else:
-                    if timeout:
-                        if (time.time() - start) >= timeout:
-                            raise TimeoutError('Unable to get database '
-                                               'connection within %d seconds'
-                                                % timeout)
-                        self._available.wait(timeout)
-                    else: # Warning: without timeout, Trac *might* hang
-                        self._available.wait()
-            self._active[tid] = [1, cnx]
-            return PooledConnection(self, cnx, tid)
-        finally:
-            self._available.release()
-
-    def _return_cnx(self, cnx, tid):
-        self._available.acquire()
-        try:
-            if tid in self._active:
-                num, cnx_ = self._active.get(tid)
-                if cnx is cnx_:
-                    if num > 1:
-                        self._active[tid][0] = num - 1
-                    else:
-                        self._cleanup(tid)
-                # otherwise, cnx was already cleaned up during a shutdown(tid),
-                # and in the meantime, `tid` has been reused (#3504)
-        finally:
-            self._available.release()
-
-    def _cleanup(self, tid):
-        """Note: self._available *must* be acquired when calling this one."""
-        if tid in self._active:
-            cnx = self._active.pop(tid)[1]
-            assert tid not in self._dormant # hm, how could that happen?
-            if cnx.poolable: # i.e. we can manipulate it from other threads
-                if try_rollback(cnx):
-                    self._dormant[tid] = cnx
-                else:
-                    self._cursize -= 1
-            elif tid == threading._get_ident():
-                if try_rollback(cnx): # non-poolable but same thread: close
-                    cnx.close()
-                self._cursize -= 1
-            else: # non-poolable, different thread: push it back
-                self._active[tid] = [0, cnx]
-            self._available.notify()
+        return _backend.get_cnx(self._connector, self._kwargs, timeout)
 
     def shutdown(self, tid=None):
-        self._available.acquire()
-        try:
-            if tid:
-                cleanup_list = [tid]
-            else:
-                cleanup_list = self._active.keys()
-            for tid in cleanup_list:
-                self._cleanup(tid)
-            if not tid:
-                for _, cnx in self._dormant.iteritems():
-                    cnx.close()
-        finally:
-            self._available.release()
+        _backend.shutdown(tid)
+
Index: branches/0.11-stable/trac/db/mysql_backend.py
===================================================================
--- branches/0.11-stable/trac/db/mysql_backend.py (revision 7185)
+++ branches/0.11-stable/trac/db/mysql_backend.py (revision 7286)
@@ -26,5 +26,22 @@
 try:
     import MySQLdb
+    import MySQLdb.cursors
     has_mysqldb = True
+    
+    class MySQLUnicodeCursor(MySQLdb.cursors.Cursor):
+        def _convert_row(self, row):
+            return tuple([(isinstance(v, str) and [v.decode('utf-8')] or [v])[0]
+                          for v in row])
+        def fetchone(self):
+            row = super(MySQLUnicodeCursor, self).fetchone()
+            return row and self._convert_row(row) or None
+        def fetchmany(self, num):
+            rows = super(MySQLUnicodeCursor, self).fetchmany(num)
+            return rows != None and [self._convert_row(row)
+                                     for row in rows] or []
+        def fetchall(self):
+            rows = super(MySQLUnicodeCursor, self).fetchall()
+            return rows != None and [self._convert_row(row)
+                                     for row in rows] or []
 except ImportError:
     has_mysqldb = False
@@ -131,25 +148,4 @@
     poolable = True
 
-    def _mysqldb_gt_or_eq(self, v):
-        """This function checks whether the version of python-mysqldb
-        is greater than or equal to the version that's passed to it.
-        Note that the tuple only checks the major, minor, and sub versions;
-        the sub-sub version is weird, so we only check for 'final' versions.
-        """
-        ver = MySQLdb.version_info
-        if ver[0] < v[0] or ver[1] < v[1] or ver[2] < v[2]:
-            return False
-        if ver[3] != 'final':
-            return False
-        return True
-
-    def _set_character_set(self, cnx, charset):
-        vers = tuple([ int(n) for n in cnx.get_server_info().split('.')[:2] ])
-        if vers < (4, 1):
-            raise TracError, 'MySQL servers older than 4.1 are not supported!'
-        cnx.query('SET NAMES %s' % charset)
-        cnx.store_result()
-        cnx.charset = charset
-
     def __init__(self, path, user=None, password=None, host=None,
                  port=None, params={}):
@@ -160,16 +156,6 @@
         if port == None:
             port = 3306
-
-        # python-mysqldb 1.2.1 added a 'charset' arg that is required for
-        # unicode stuff.  We hack around that here for older versions; at
-        # some point, this hack should be removed, and a strict requirement
-        # on 1.2.1 made.  -dilinger
-        if (self._mysqldb_gt_or_eq((1, 2, 1))):
-            cnx = MySQLdb.connect(db=path, user=user, passwd=password,
-                                  host=host, port=port, charset='utf8')
-        else:
-            cnx = MySQLdb.connect(db=path, user=user, passwd=password,
-                                  host=host, port=port, use_unicode=True)
-            self._set_character_set(cnx, 'utf8')
+        cnx = MySQLdb.connect(db=path, user=user, passwd=password,
+                              host=host, port=port, charset='utf8')
         ConnectionWrapper.__init__(self, cnx)
         self._is_closed = False
@@ -196,5 +182,4 @@
     def rollback(self):
         self.cnx.ping()
-        self._set_character_set(self.cnx, 'utf8')
         try:
             self.cnx.rollback()
@@ -209,2 +194,6 @@
                 pass # this error would mean it's already closed.  So, ignore
             self._is_closed = True
+
+    def cursor(self):
+        return MySQLUnicodeCursor(self.cnx)
+        
Index: branches/0.11-stable/trac/versioncontrol/api.py
===================================================================
--- branches/0.11-stable/trac/versioncontrol/api.py (revision 6899)
+++ branches/0.11-stable/trac/versioncontrol/api.py (revision 7435)
@@ -35,4 +35,6 @@
     """Provide support for a specific version control system."""
 
+    error = None # place holder for storing relevant error message
+
     def get_supported_types():
         """Return the types of version control systems that are supported.
@@ -43,4 +45,9 @@
         If multiple provider match a given type, the `priority` is used to
         choose between them (highest number is highest priority).
+
+        If the `priority` returned is negative, this indicates that the 
+        connector for the given `repotype` indeed exists but can't be
+        used for some reason. The `error` property can then be used to 
+        store an error message or exception relevant to the problem detected.
         """
 
@@ -80,5 +87,7 @@
             except TracError, e:
                 add_warning(req, _("Can't synchronize with the repository "
-                              "(%(error)s)", error=e.message))
+                              "(%(error)s). Look in the Trac log for more "
+                              "information.", error=e.message))
+                          
         return handler
 
@@ -126,10 +135,16 @@
                 ]
                 if candidates:
-                    self._connector = max(candidates)[1]
+                    prio, connector = max(candidates)
+                    if prio < 0: # error condition
+                        raise TracError(
+                            _('Unsupported version control system "%(name)s"'
+                              ': "%(error)s" ', name=self.repository_type, 
+                              error=connector.error))
+                    self._connector = connector
                 else:
                     raise TracError(
-                        _('Unsupported version control system "%(name)s". '
-                          'Check that the Python support libraries for '
-                          '"%(name)s" are correctly installed.',
+                        _('Unsupported version control system "%(name)s": '
+                          'Can\'t find an appropriate component, maybe the '
+                          'corresponding plugin was not enabled? ',
                           name=self.repository_type))
             tid = threading._get_ident()
Index: branches/0.11-stable/trac/versioncontrol/svn_fs.py
===================================================================
--- branches/0.11-stable/trac/versioncontrol/svn_fs.py (revision 7157)
+++ branches/0.11-stable/trac/versioncontrol/svn_fs.py (revision 7435)
@@ -245,4 +245,6 @@
         """)
 
+    error = None
+
     def __init__(self):
         self._version = None
@@ -251,16 +253,17 @@
             _import_svn()
             self.log.debug('Subversion bindings imported')
-        except ImportError:
+        except ImportError, e:
+            self.error = e
             self.log.info('Failed to load Subversion bindings', exc_info=True)
-            self.has_subversion = False
         else:
-            self.has_subversion = True
             Pool()
 
     def get_supported_types(self):
-        if self.has_subversion:
-            yield ("direct-svnfs", 4)
-            yield ("svnfs", 4)
-            yield ("svn", 2)
+        prio = 1
+        if self.error:
+            prio = -1
+        yield ("direct-svnfs", prio*4)
+        yield ("svnfs", prio*4)
+        yield ("svn", prio*2)
 
     def get_repository(self, type, dir, authname):
@@ -279,5 +282,5 @@
             repos = fs_repos
         else:
-            repos = CachedRepository(self.env.get_db_cnx(), fs_repos, None,
+            repos = CachedRepository(self.env.get_db_cnx, fs_repos, None,
                                      self.log)
             repos.has_linear_changesets = True
Index: branches/0.11-stable/trac/versioncontrol/cache.py
===================================================================
--- branches/0.11-stable/trac/versioncontrol/cache.py (revision 6906)
+++ branches/0.11-stable/trac/versioncontrol/cache.py (revision 7375)
@@ -40,7 +40,10 @@
     has_linear_changesets = False
 
-    def __init__(self, db, repos, authz, log):
+    def __init__(self, getdb, repos, authz, log):
         Repository.__init__(self, repos.name, authz, log)
-        self.db = db
+        if callable(getdb):
+            self.getdb = getdb
+        else:
+            self.getdb = lambda: getdb
         self.repos = repos
 
@@ -54,8 +57,9 @@
     def get_changeset(self, rev):
         return CachedChangeset(self.repos, self.repos.normalize_rev(rev),
-                               self.db, self.authz)
+                               self.getdb, self.authz)
 
     def get_changesets(self, start, stop):
-        cursor = self.db.cursor()
+        db = self.getdb()
+        cursor = db.cursor()
         cursor.execute("SELECT rev FROM revision "
                        "WHERE time >= %s AND time < %s "
@@ -71,14 +75,15 @@
     def sync_changeset(self, rev):
         cset = self.repos.get_changeset(rev)
-        cursor = self.db.cursor()
+        db = self.getdb()
+        cursor = db.cursor()
         cursor.execute("UPDATE revision SET time=%s, author=%s, message=%s "
                        "WHERE rev=%s", (to_timestamp(cset.date),
                                         cset.author, cset.message,
                                         (str(cset.rev))))
-        self.db.commit()
+        db.commit()
         
     def sync(self, feedback=None):
-        cursor = self.db.cursor()
-
+        db = self.getdb()
+        cursor = db.cursor()
         cursor.execute("SELECT name, value FROM system WHERE name IN (%s)" %
                        ','.join(["'%s'" % key for key in CACHE_METADATA_KEYS]))
@@ -104,5 +109,5 @@
                            (self.name, CACHE_REPOSITORY_DIR))
 
-        self.db.commit() # save metadata changes made up to now
+        db.commit() # save metadata changes made up to now
 
         # -- retrieve the youngest revision in the repository
@@ -187,5 +192,5 @@
                         # notion of 'youngest'
                         self.repos.clear(youngest_rev=self.youngest)
-                        self.db.rollback()
+                        db.rollback()
                         return
 
@@ -214,5 +219,5 @@
                     cursor.execute("UPDATE system SET value=%s WHERE name=%s",
                                    (str(self.youngest), CACHE_YOUNGEST_REV))
-                    self.db.commit()
+                    db.commit()
 
                     # 1.5. provide some feedback
@@ -238,36 +243,45 @@
 
     def previous_rev(self, rev, path=''):
-        if not self.has_linear_changesets:
+        if self.has_linear_changesets:
+            return self._next_prev_rev('<', rev, path)
+        else:
             return self.repos.previous_rev(rev, path)
-        else:
-            return self._next_prev_rev('<', rev, path)
 
     def next_rev(self, rev, path=''):
-        if not self.has_linear_changesets:
+        if self.has_linear_changesets:
+            return self._next_prev_rev('>', rev, path)
+        else:
             return self.repos.next_rev(rev, path)
-        else:
-            return self._next_prev_rev('>', rev, path)
 
     def _next_prev_rev(self, direction, rev, path=''):
+        db = self.getdb()
         # the changeset revs are sequence of ints:
         sql = "SELECT rev FROM node_change WHERE " + \
-              self.db.cast('rev', 'int') + " " + direction + " %s"
+              db.cast('rev', 'int') + " " + direction + " %s"
         args = [rev]
 
         if path:
-            # Child changes
-            sql += " AND (path %s OR " % self.db.like()
-            args.append(self.db.like_escape(path.lstrip('/')) + '%')
-            # Parent deletion
+            path = path.lstrip('/')
+            sql += " AND ("
+            # changes on path itself
+            sql += "path=%s "
+            args.append(path)
+            sql += " OR "
+            # changes on path children
+            sql += "path "+db.like()
+            args.append(db.like_escape(path+'/') + '%')
+            sql += " OR "
+            # deletion of path ancestors
             components = path.lstrip('/').split('/')
             for i in range(1, len(components)+1):
                 args.append('/'.join(components[:i]))
             parent_insert = ','.join(('%s',) * len(components))
-            sql += " (path in (" + parent_insert + ") and change_type='D') )"
-
-        sql += " ORDER BY " + self.db.cast('rev', 'int') + \
+            sql += " (path in (" + parent_insert + ") and change_type='D')"
+            sql += ")"
+
+        sql += " ORDER BY " + db.cast('rev', 'int') + \
                 (direction == '<' and " DESC" or "") + " LIMIT 1"
         
-        cursor = self.db.cursor()
+        cursor = db.cursor()
         cursor.execute(sql, args)
         for rev, in cursor:
@@ -294,9 +308,10 @@
 class CachedChangeset(Changeset):
 
-    def __init__(self, repos, rev, db, authz):
+    def __init__(self, repos, rev, getdb, authz):
         self.repos = repos
-        self.db = db
+        self.getdb = getdb
         self.authz = authz
-        cursor = self.db.cursor()
+        db = self.getdb()
+        cursor = db.cursor()
         cursor.execute("SELECT time,author,message FROM revision "
                        "WHERE rev=%s", (str(rev),))
@@ -311,5 +326,6 @@
 
     def get_changes(self):
-        cursor = self.db.cursor()
+        db = self.getdb()
+        cursor = db.cursor()
         cursor.execute("SELECT path,node_type,change_type,base_path,base_rev "
                        "FROM node_change WHERE rev=%s "
Index: branches/0.11-stable/trac/versioncontrol/web_ui/changeset.py
===================================================================
--- branches/0.11-stable/trac/versioncontrol/web_ui/changeset.py (revision 6904)
+++ branches/0.11-stable/trac/versioncontrol/web_ui/changeset.py (revision 7258)
@@ -615,5 +615,6 @@
         data.update({'has_diffs': has_diffs, 'changes': changes, 'xhr': xhr,
                      'filestats': filestats, 'annotated': annotated,
-                     'files': files, 'location': self._get_location(files),
+                     'files': files, 
+                     'location': self._get_parent_location(files),
                      'longcol': 'Revision', 'shortcol': 'r'})
 
@@ -753,5 +754,21 @@
 
     def _get_location(self, files):
-        return '/'.join(os.path.commonprefix([f.split('/') for f in files]))
+        """Return the deepest common path for the given files.
+           If all the files are actually the same, return that location."""
+        if len(files) == 1:
+            return files[0]
+        else:
+            return '/'.join(os.path.commonprefix([f.split('/') 
+                                                  for f in files]))
+    def _get_parent_location(self, files):
+        """Only get a location when there are different files,
+           otherwise return the empty string."""
+        if files: 
+            files.sort()
+            prev = files[0]
+            for f in files[1:]:
+                if f != prev:
+                    return self._get_location(files)
+        return ''
 
     def _prepare_filestats(self):
@@ -832,5 +849,5 @@
                     markup = tag.ul(
                         tag.li(stats, ' in ',
-                               tag.strong(self._get_location(files))),
+                               tag.strong(self._get_location(files) or '/')),
                         markup, class_="changes")
                 elif show_files:
Index: branches/0.11-stable/trac/versioncontrol/templates/changeset.html
===================================================================
--- branches/0.11-stable/trac/versioncontrol/templates/changeset.html (revision 6600)
+++ branches/0.11-stable/trac/versioncontrol/templates/changeset.html (revision 7258)
@@ -56,5 +56,5 @@
                        is_removal = cl == 'rem';
                        path = is_removal and item.old.get('path') or item.new.get('path');
-                       path = len(files) == 1 and path or (path and path[len(location):].strip('/'))">
+                       path = path and path[len(location):].strip('/')">
           <div class="$cl"> </div>
           <py:choose>
@@ -118,5 +118,5 @@
           </dd>
         </py:if>
-        <py:if test="location and len(files) &gt; 1">
+        <py:if test="location">
           <dt class="property location">Location:</dt>
           <dd class="searchable"><a href="${req.href.browser(location, rev=new_rev)}">$location</a></dd>
Index: branches/0.11-stable/trac/admin/web_ui.py
===================================================================
--- branches/0.11-stable/trac/admin/web_ui.py (revision 6904)
+++ branches/0.11-stable/trac/admin/web_ui.py (revision 7378)
@@ -99,5 +99,9 @@
         path_info = req.args.get('path_info')
         if not panel_id:
-            panel_id = filter(lambda panel: panel[0] == cat_id, panels)[0][2]
+            try:
+                panel_id = filter(
+                            lambda panel: panel[0] == cat_id, panels)[0][2]
+            except IndexError:
+                raise HTTPNotFound(_('Unknown administration panel'))
 
         provider = providers.get((cat_id, panel_id), None)
@@ -299,4 +303,5 @@
         perm = PermissionSystem(self.env)
         all_permissions = perm.get_all_permissions()
+        all_actions = perm.get_actions()
 
         if req.method == 'POST':
@@ -305,6 +310,6 @@
             group = req.args.get('group', '')
 
-            if subject and subject == subject.upper() or \
-                   group and group == group.upper():
+            if subject and subject.isupper() or \
+                   group and group.isupper():
                 raise TracError(_('All upper-cased tokens are reserved for '
                                   'permission names'))
@@ -313,5 +318,5 @@
             if req.args.get('add') and subject and action:
                 req.perm.require('PERMISSION_GRANT')
-                if action not in perm.get_actions():
+                if action not in all_actions:
                     raise TracError(_('Unknown action'))
                 req.perm.require(action)
@@ -329,5 +334,10 @@
                 req.perm.require('PERMISSION_GRANT')
                 for action in perm.get_user_permissions(group):
-                    req.perm.require(action)
+                    if not action in all_actions: # plugin disabled?
+                        self.env.log.warn("Adding %s to group %s: " \
+                            "Permission %s unavailable, skipping perm check." \
+                            % (subject, group, action))
+                    else:
+                        req.perm.require(action)
                 if (subject,group) not in all_permissions:
                     perm.grant_permission(subject, group)
@@ -350,5 +360,5 @@
 
         return 'admin_perms.html', {
-            'actions': perm.get_actions(),
+            'actions': all_actions,
             'perms': all_permissions
         }
@@ -420,5 +430,5 @@
             # OS_BINARY not available on every platform
             pass
-        target_file = os.fdopen(os.open(target_path, flags), 'w')
+        target_file = os.fdopen(os.open(target_path, flags, 0666), 'w')
         try:
             shutil.copyfileobj(upload.file, target_file)
Index: branches/0.11-stable/trac/admin/tests/console.py
===================================================================
--- branches/0.11-stable/trac/admin/tests/console.py (revision 6904)
+++ branches/0.11-stable/trac/admin/tests/console.py (revision 7394)
@@ -981,5 +981,8 @@
     def test_backslash_use_ok(self):
         test_name = sys._getframe().f_code.co_name
-        self._execute('version add \\')
+        if self._admin.interactive:
+            self._execute('version add \\')
+        else:
+            self._execute(r"version add '\'")
         rv, output = self._execute('version list')
         self.assertEqual(0, rv)
Index: branches/0.11-stable/trac/admin/console.py
===================================================================
--- branches/0.11-stable/trac/admin/console.py (revision 6916)
+++ branches/0.11-stable/trac/admin/console.py (revision 7423)
@@ -37,6 +37,6 @@
 from trac.util.html import html
 from trac.util.text import to_unicode, wrap, unicode_quote, unicode_unquote, \
-                           print_table
-from trac.util.translation import _
+                           print_table, console_print
+from trac.util.translation import _, ngettext
 from trac.wiki import WikiPage
 from trac.wiki.api import WikiSystem
@@ -45,4 +45,10 @@
 TRAC_VERSION = pkg_resources.get_distribution('Trac').version
 
+def printout(*args):
+    console_print(sys.stdout, *args)
+
+def printerr(*args):
+    console_print(sys.stderr, *args)
+
 def copytree(src, dst, symlinks=False, skip=[]):
     """Recursively copy a directory tree using copy2() (from shutil.copytree.)
@@ -51,25 +57,33 @@
     which we don't want to copy.
     """
-    names = os.listdir(src)
-    os.mkdir(dst)
-    errors = []
-    for name in names:
-        srcname = os.path.join(src, name)
-        if srcname in skip:
-            continue
-        dstname = os.path.join(dst, name)
-        try:
-            if symlinks and os.path.islink(srcname):
-                linkto = os.readlink(srcname)
-                os.symlink(linkto, dstname)
-            elif os.path.isdir(srcname):
-                copytree(srcname, dstname, symlinks, skip)
-            else:
-                shutil.copy2(srcname, dstname)
-            # XXX What about devices, sockets etc.?
-        except (IOError, os.error), why:
-            errors.append((srcname, dstname, why))
-    if errors:
-        raise shutil.Error, errors
+    def str_path(path):
+        if isinstance(path, unicode):
+            path = path.encode(sys.getfilesystemencoding() or
+                               locale.getpreferredencoding())
+        return path
+    skip = [str_path(f) for f in skip]
+    def copytree_rec(src, dst):
+        names = os.listdir(src)
+        os.mkdir(dst)
+        errors = []
+        for name in names:
+            srcname = os.path.join(src, name)
+            if srcname in skip:
+                continue
+            dstname = os.path.join(dst, name)
+            try:
+                if symlinks and os.path.islink(srcname):
+                    linkto = os.readlink(srcname)
+                    os.symlink(linkto, dstname)
+                elif os.path.isdir(srcname):
+                    copytree_rec(srcname, dstname)
+                else:
+                    shutil.copy2(srcname, dstname)
+                # XXX What about devices, sockets etc.?
+            except (IOError, os.error), why:
+                errors.append((srcname, dstname, why))
+        if errors:
+            raise shutil.Error, errors
+    copytree_rec(str_path(src), str_path(dst))
 
 
@@ -100,11 +114,16 @@
         try:
             if isinstance(line, str):
-                line = to_unicode(line, sys.stdin.encoding)
-            line = line.replace('\\', '\\\\')
+                if self.interactive:
+                    encoding = sys.stdin.encoding
+                else:
+                    encoding = locale.getpreferredencoding() # sys.argv
+                line = to_unicode(line, encoding)
+            if self.interactive:
+                line = line.replace('\\', '\\\\')
             rv = cmd.Cmd.onecmd(self, line) or 0
         except SystemExit:
             raise
         except TracError, e:
-            print>>sys.stderr, 'Command failed: %s' % e
+            printerr(_("Command failed:"), e)
             rv = 2
         if not self.interactive:
@@ -113,10 +132,10 @@
     def run(self):
         self.interactive = True
-        print """Welcome to trac-admin %(version)s
+        printout(_("""Welcome to trac-admin %(version)s
 Interactive Trac administration console.
 Copyright (c) 2003-2008 Edgewall Software
 
 Type:  '?' or 'help' for help on commands.
-        """ % {'version': TRAC_VERSION}
+        """, version=TRAC_VERSION))
         self.cmdloop()
 
@@ -144,5 +163,5 @@
             return self.__env
         except Exception, e:
-            print 'Failed to open environment.', e
+            printerr(_("Failed to open environment."), e)
             traceback.print_exc()
             sys.exit(1)
@@ -195,6 +214,6 @@
         if not docs: return
         for cmd, doc in docs:
-            print>>stream, cmd
-            print>>stream, '\t-- %s\n' % doc
+            console_print(stream, cmd)
+            console_print(stream, '\t-- %s\n' % doc)
     print_doc = classmethod(print_doc)
 
@@ -271,13 +290,15 @@
                 self.print_doc(doc)
             except AttributeError:
-                print "No documentation found for '%s'" % arg[0]
-        else:
-            print 'trac-admin - The Trac Administration Console %s' \
-                  % TRAC_VERSION
+                printerr(_("No documentation found for '%(cmd)s'", cmd=arg[0]))
+        else:
+            printout(_("trac-admin - The Trac Administration Console "
+                       "%(version)s", version=TRAC_VERSION))
             if not self.interactive:
                 print
-                print "Usage: trac-admin </path/to/projenv> [command [subcommand] [option ...]]\n"
-                print "Invoking trac-admin without command starts "\
-                      "interactive mode."
+                printout(_("Usage: trac-admin </path/to/projenv> "
+                           "[command [subcommand] [option ...]]\n")
+                    )
+                printout(_("Invoking trac-admin without command starts "
+                           "interactive mode."))
             self.print_doc(self.all_docs())
 
@@ -415,10 +436,10 @@
         print_table(rows, ['User', 'Action'])
         print
-        print 'Available actions:'
+        printout(_("Available actions:"))
         actions = self._permsys.get_actions()
         actions.sort()
         text = ', '.join(actions)
-        print wrap(text, initial_indent=' ', subsequent_indent=' ',
-                   linesep='\n')
+        printout(wrap(text, initial_indent=' ', subsequent_indent=' ', 
+                      linesep='\n'))
         print
 
@@ -427,5 +448,6 @@
             self._permsys = PermissionSystem(self.env_open())
         if not action.islower() and not action.isupper():
-            print 'Group names must be in lower case and actions in upper case'
+            printout(_("Group names must be in lower case and actions in "
+                       "upper case"))
             return
         self._permsys.grant_permission(user, action)
@@ -459,41 +481,43 @@
     def get_initenv_args(self):
         returnvals = []
-        print 'Creating a new Trac environment at %s' % self.envname
-        print
-        print 'Trac will first ask a few questions about your environment '
-        print 'in order to initalize and prepare the project database.'
-        print
-        print " Please enter the name of your project."
-        print " This name will be used in page titles and descriptions."
-        print
+        printout(_("Creating a new Trac environment at %(envname)s",
+                   envname=self.envname))
+        printout(_("""
+Trac will first ask a few questions about your environment 
+in order to initialize and prepare the project database.
+
+ Please enter the name of your project.
+ This name will be used in page titles and descriptions.
+"""))
         dp = 'My Project'
-        returnvals.append(raw_input('Project Name [%s]> ' % dp).strip() or dp)
-        print
-        print ' Please specify the connection string for the database to use.'
-        print ' By default, a local SQLite database is created in the environment '
-        print ' directory. It is also possible to use an already existing '
-        print ' PostgreSQL database (check the Trac documentation for the exact '
-        print ' connection string syntax).'
-        print
+        returnvals.append(raw_input(_("Project Name [%(default)s]> ",
+                                      default=dp)).strip() or dp)
+        printout(_(""" 
+ Please specify the connection string for the database to use.
+ By default, a local SQLite database is created in the environment
+ directory. It is also possible to use an already existing
+ PostgreSQL database (check the Trac documentation for the exact
+ connection string syntax).
+"""))
         ddb = 'sqlite:db/trac.db'
-        prompt = 'Database connection string [%s]> ' % ddb
+        prompt = _("Database connection string [%(default)s]> ", default=ddb)
         returnvals.append(raw_input(prompt).strip() or ddb)
-        print
-        print ' Please specify the type of version control system,'
-        print ' By default, it will be svn.'
-        print
-        print ' If you don\'t want to use Trac with version control integration, '
-        print ' choose the default here and don\'t specify a repository directory. '
-        print ' in the next question.'
-        print 
+        printout(_(""" 
+ Please specify the type of version control system,
+ By default, it will be svn.
+
+ If you don't want to use Trac with version control integration,
+ choose the default here and don\'t specify a repository directory.
+ in the next question.
+"""))
         drpt = 'svn'
-        prompt = 'Repository type [%s]> ' % drpt
+        prompt = _("Repository type [%(default)s]> ", default=drpt)
         returnvals.append(raw_input(prompt).strip() or drpt)
-        print
-        print ' Please specify the absolute path to the version control '
-        print ' repository, or leave it blank to use Trac without a repository.'
-        print ' You can also set the repository location later.'
-        print 
-        prompt = 'Path to repository [/path/to/repos]> '
+        printout(_("""
+ Please specify the absolute path to the version control
+ repository, or leave it blank to use Trac without a repository.
+ You can also set the repository location later.
+"""))
+        prompt = _("Path to repository [/path/to/repos]> ")
         returnvals.append(raw_input(prompt).strip())
         print
@@ -501,12 +525,13 @@
 
     def do_initenv(self, line):
+        def initenv_error(msg):
+            printerr(_("Initenv for '%(env)s' failed.", env=self.envname),
+                     "\n", msg)
         if self.env_check():
-            print "Initenv for '%s' failed." % self.envname
-            print "Does an environment already exist?"
+            initenv_error("Does an environment already exist?")
             return 2
 
         if os.path.exists(self.envname) and os.listdir(self.envname):
-            print "Initenv for '%s' failed." % self.envname
-            print "Directory exists and is not empty."
+            initenv_error("Directory exists and is not empty.")
             return 2
 
@@ -524,5 +549,5 @@
             project_name, db_str, repository_type, repository_dir = returnvals
         elif len(arg) != 4:
-            print 'Wrong number of arguments to initenv: %d' % len(arg)
+            initenv_error('Wrong number of arguments: %d' % len(arg))
             return 2
         else:
@@ -530,5 +555,5 @@
 
         try:
-            print 'Creating and Initializing Project'
+            printout(_("Creating and Initializing Project"))
             options = [
                 ('trac', 'database', db_str),
@@ -543,10 +568,11 @@
                                          options=options)
             except Exception, e:
-                print 'Failed to create environment.', e
+                initenv_error('Failed to create environment.')
+                printerr(e)
                 traceback.print_exc()
                 sys.exit(1)
 
             # Add a few default wiki pages
-            print ' Installing default wiki pages'
+            printout(_(" Installing default wiki pages"))
             cnx = self.__env.get_db_cnx()
             cursor = cnx.cursor()
@@ -560,19 +586,26 @@
                     repos = self.__env.get_repository()
                     if repos:
-                        print ' Indexing repository'
+                        printout(_(" Indexing repository"))
                         repos.sync(self._resync_feedback)
                 except TracError, e:
-                    print>>sys.stderr, "\nWarning:\n"
-                    if repository_type == "svn":
-                        print>>sys.stderr, "You should install the SVN bindings"
-                    else:
-                        print>>sys.stderr, "Repository type %s not supported" \
-                                           % repository_type
+                    printerr(_("""
+---------------------------------------------------------------------
+Warning: couldn't index the repository.
+
+This can happen for a variety of reasons: wrong repository type, 
+no appropriate third party library for this repository type,
+no actual repository at the specified repository path...
+
+You can nevertheless start using your Trac environment, but 
+you'll need to check again your trac.ini file and the [trac] 
+repository_type and repository_path settings in order to enable
+the Trac repository browser.
+"""))
         except Exception, e:
-            print 'Failed to initialize environment.', e
+            initenv_error(to_unicode(e))
             traceback.print_exc()
             return 2
 
-        print """
+        printout(_("""
 ---------------------------------------------------------------------
 Project environment for '%(project_name)s' created.
@@ -598,7 +631,7 @@
 
 Congratulations!
-""" % dict(project_name=project_name, project_path=self.envname,
+""", project_name=project_name, project_path=self.envname,
            project_dir=os.path.basename(self.envname),
-           config_path=os.path.join(self.envname, 'conf', 'trac.ini'))
+           config_path=os.path.join(self.envname, 'conf', 'trac.ini')))
 
     _help_resync = [('resync', 'Re-synchronize trac with the repository'),
@@ -617,8 +650,8 @@
             if rev:
                 env.get_repository().sync_changeset(rev)
-                print '%s resynced.' % rev
+                printout(_("%(rev)s resynced.", rev=rev))
                 return
         from trac.versioncontrol.cache import CACHE_METADATA_KEYS
-        print 'Resyncing repository history... '
+        printout(_("Resyncing repository history... "))
         cnx = self.db_open()
         cursor = cnx.cursor()
@@ -633,6 +666,7 @@
         cursor.execute("SELECT count(rev) FROM revision")
         for cnt, in cursor:
-            print cnt, 'revisions cached.',
-        print 'Done.'
+            printout(ngettext("%(num)s revision cached.",
+                              "%(num)s revisions cached.", num=cnt))
+        printout(_("Done."))
 
     ## Wiki
@@ -732,10 +766,9 @@
                              params=(title,))
         old = list(rows)
-        cons_charset = getattr(sys.stdout, 'encoding', None) or 'utf-8'        
         if old and title in create_only:
-            print '  %s already exists.' % title.encode(cons_charset)
+            printout('  %s already exists.' % title)
             return False
         if old and data == old[0][0]:
-            print '  %s already up to date.' % title.encode(cons_charset)
+            printout('  %s already up to date.' % title)
             return False
         f.close()
@@ -753,5 +786,5 @@
         text = data.next()[0]
         if not filename:
-            print text
+            printout(text)
         else:
             if os.path.isfile(filename):
@@ -763,8 +796,12 @@
     def _do_wiki_dump(self, dir):
         pages = self.get_wiki_list()
-        cons_charset = getattr(sys.stdout, 'encoding', None) or 'utf-8'
+        if not os.path.isdir(dir):
+            if not os.path.exists(dir):
+                os.mkdir(dir)
+            else:
+                raise TracError("%s is not a directory" % dir)
         for p in pages:
             dst = os.path.join(dir, unicode_quote(p, ''))
-            print (" %s => %s" % (p, dst)).encode(cons_charset)
+            printout(_(" %(src)s => %(dst)s", src=p, dst=dst))
             self._do_wiki_export(p, dst)
 
@@ -778,6 +815,6 @@
             if os.path.isfile(filename):
                 if self._do_wiki_import(filename, page, cursor, create_only):
-                    print (" %s imported from %s" %
-                           (filename, page)).encode(cons_charset)
+                    printout(_(" %(page)s imported from %(filename)s",
+                               filename=filename, page=page))
 
     ## Ticket
@@ -800,5 +837,5 @@
                 number = int(arg[1])
             except ValueError:
-                print>>sys.stderr, "<number> must be a number"
+                printerr(_("<number> must be a number"))
                 return
             self._do_ticket_remove(number)
@@ -806,8 +843,8 @@
             self.do_help ('ticket')
 
-    def _do_ticket_remove(self, number):
-        ticket = Ticket(self.env_open(), number)
+    def _do_ticket_remove(self, num):
+        ticket = Ticket(self.env_open(), num)
         ticket.delete()
-        print "Ticket %d and all associated data removed." % number
+        printout(_("Ticket %(num)s and all associated data removed.", num=num))
 
 
@@ -1102,5 +1139,5 @@
 
         if not self.__env.needs_upgrade():
-            print "Database is up to date, no upgrade necessary."
+            printout(_("Database is up to date, no upgrade necessary."))
             return
 
@@ -1114,5 +1151,5 @@
             else:
                 raise
-        print 'Upgrade done.'
+        printout(_("Upgrade done."))
 
     _help_hotcopy = [('hotcopy <backupdir>',
@@ -1136,5 +1173,6 @@
 
         try:
-            print 'Hotcopying %s to %s ...' % (self.__env.path, dest),
+            printout(_('Hotcopying %(src)s to %(dst)s ...', 
+                       src=self.__env.path, dst=dest))
             db_str = self.__env.config.get('trac', 'database')
             prefix, db_path = db_str.split(':', 1)
@@ -1150,5 +1188,5 @@
             cnx.rollback()
 
-        print 'Hotcopy done.'
+        printout(_("Hotcopy done."))
 
     _help_deploy = [('deploy <directory>',
@@ -1171,13 +1209,14 @@
         os.makedirs(chrome_target)
         from trac.web.chrome import Chrome
-        print 'Copying resources from:'
+        printout(_("Copying resources from:"))
         for provider in Chrome(self.env_open()).template_providers:
             paths = list(provider.get_htdocs_dirs())
             if not len(paths):
                 continue
-            print '  %s.%s' % (provider.__module__, provider.__class__.__name__)
+            printout('  %s.%s' % (provider.__module__, 
+                                  provider.__class__.__name__))
             for key, root in paths:
                 source = os.path.normpath(root)
-                print '   ', source
+                printout('   ', source)
                 if os.path.exists(source):
                     dest = os.path.join(chrome_target, key)
@@ -1186,6 +1225,6 @@
         # Create and copy scripts
         os.makedirs(script_target)
-        print 'Creating scripts.'
-        data = {'env': self.env_open()}
+        printout(_("Creating scripts."))
+        data = {'env': self.env_open(), 'executable': sys.executable}
         for script in ('cgi', 'fcgi', 'wsgi'):
             dest = os.path.join(script_target, 'trac.'+script)
@@ -1241,7 +1280,14 @@
             return admin.onecmd('help')
         elif args[0] in ('-v','--version'):
-            print '%s %s' % (os.path.basename(sys.argv[0]), TRAC_VERSION)
-        else:
-            admin.env_set(os.path.abspath(args[0]))
+            printout(os.path.basename(sys.argv[0]), TRAC_VERSION)
+        else:
+            env_path = os.path.abspath(args[0])
+            try:
+                unicode(env_path, 'ascii')
+            except UnicodeDecodeError:
+                printerr(_("non-ascii environment path '%(path)s' not "
+                           "supported.", path=env_path))
+                sys.exit(2)
+            admin.env_set(env_path)
             if len(args) > 1:
                 s_args = ' '.join(["'%s'" % c for c in args[2:]])
Index: branches/0.11-stable/trac/admin/templates/admin_basics.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_basics.html (revision 6324)
+++ branches/0.11-stable/trac/admin/templates/admin_basics.html (revision 7388)
@@ -13,5 +13,5 @@
     <h2>Basic Settings</h2>
 
-    <form class="mod" id="modbasic" method="post">
+    <form class="mod" id="modbasic" method="post" action="">
       <fieldset>
         <legend>Project</legend>
Index: branches/0.11-stable/trac/admin/templates/admin_components.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_components.html (revision 7166)
+++ branches/0.11-stable/trac/admin/templates/admin_components.html (revision 7388)
@@ -30,5 +30,5 @@
 
     <py:choose test="view">
-      <form py:when="'detail'" class="mod" id="modcomp" method="post">
+      <form py:when="'detail'" class="mod" id="modcomp" method="post" action="">
         <fieldset>
           <legend>Modify Component:</legend>
@@ -59,5 +59,5 @@
 
       <py:otherwise>
-        <form class="addnew" id="addcomponent" method="post">
+        <form class="addnew" id="addcomponent" method="post" action="">
           <fieldset>
             <legend>Add Component:</legend>
@@ -73,5 +73,5 @@
 
         <py:choose>
-          <form py:when="components" id="component_table" method="POST">
+          <form py:when="components" id="component_table" method="post" action="">
             <table class="listing" id="complist">
               <thead>
Index: branches/0.11-stable/trac/admin/templates/admin_logging.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_logging.html (revision 6572)
+++ branches/0.11-stable/trac/admin/templates/admin_logging.html (revision 7388)
@@ -21,5 +21,5 @@
     <h2>Logging</h2>
 
-    <form class="mod" id="modlog" method="post">
+    <form class="mod" id="modlog" method="post" action="">
       <fieldset>
         <legend>Configuration</legend>
Index: branches/0.11-stable/trac/admin/templates/admin_perms.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_perms.html (revision 6324)
+++ branches/0.11-stable/trac/admin/templates/admin_perms.html (revision 7320)
@@ -12,10 +12,4 @@
   <body>
     <h2>Manage Permissions</h2>
-
-    <p class="help">
-      Note that <em>Subject</em> or <em>Group</em> names can't be all upper cased, <br />
-      as this is reserved for permission names.
-    </p>
-
 
     <py:if test="'PERMISSION_GRANT' in perm">
@@ -94,4 +88,9 @@
       </div>
     </form>
+
+    <p class="help">
+      Note that <em>Subject</em> or <em>Group</em> names can't be all upper-case,
+      as that is reserved for permission names.
+    </p>
   </body>
 
Index: branches/0.11-stable/trac/admin/templates/admin_enums.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_enums.html (revision 7166)
+++ branches/0.11-stable/trac/admin/templates/admin_enums.html (revision 7388)
@@ -14,5 +14,5 @@
 
     <py:choose test="view">
-      <form py:when="'detail'" class="mod" id="modenum" method="post">
+      <form py:when="'detail'" class="mod" id="modenum" method="post" action="">
         <fieldset>
           <legend>Modify $label_singular</legend>
@@ -28,5 +28,5 @@
 
       <py:otherwise>
-        <form class="addnew" id="addenum" method="post">
+        <form class="addnew" id="addenum" method="post" action="">
           <fieldset>
             <legend>Add $label_singular</legend>
@@ -41,5 +41,5 @@
 
         <py:choose>
-          <form py:when="enums" id="enumtable" method="POST">
+          <form py:when="enums" id="enumtable" method="post" action="">
             <table class="listing" id="enumlist">
               <thead>
Index: branches/0.11-stable/trac/admin/templates/admin_versions.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_versions.html (revision 7166)
+++ branches/0.11-stable/trac/admin/templates/admin_versions.html (revision 7388)
@@ -14,5 +14,5 @@
 
     <py:choose test="view">
-      <form py:when="'detail'" class="mod" id="modifyversion" method="post">
+      <form py:when="'detail'" class="mod" id="modifyversion" method="post" action="">
         <fieldset>
           <legend>Modify Version:</legend>
@@ -49,5 +49,5 @@
 
       <py:otherwise>
-        <form class="addnew" id="addversion" method="post">
+        <form class="addnew" id="addversion" method="post" action="">
           <fieldset>
             <legend>Add Version:</legend>
@@ -70,5 +70,5 @@
 
         <py:choose>
-          <form py:when="versions" id="version_table" method="POST">
+          <form py:when="versions" id="version_table" method="post" action="">
             <table class="listing" id="verlist">
               <thead>
Index: branches/0.11-stable/trac/admin/templates/deploy_trac.cgi
===================================================================
--- branches/0.11-stable/trac/admin/templates/deploy_trac.cgi (revision 7069)
+++ branches/0.11-stable/trac/admin/templates/deploy_trac.cgi (revision 7443)
@@ -1,3 +1,3 @@
-#!/usr/bin/python
+#!${executable}
 # -*- coding: utf-8 -*-
 #
@@ -18,10 +18,15 @@
 try:
     import os
-    import tempfile
+    import pkg_resources
     if 'TRAC_ENV' not in os.environ and \
        'TRAC_ENV_PARENT_DIR' not in os.environ:
         os.environ['TRAC_ENV'] = '${env.path}'
     if 'PYTHON_EGG_CACHE' not in os.environ:
-        os.environ['PYTHON_EGG_CACHE'] = tempfile.gettempdir()
+        if 'TRAC_ENV' in os.environ:
+            egg_cache = os.path.join(os.environ['TRAC_ENV'], '.egg-cache')
+        elif 'TRAC_ENV_PARENT_DIR' in os.environ:
+            egg_cache = os.path.join(os.environ['TRAC_ENV_PARENT_DIR'], 
+                                     '.egg-cache')
+        pkg_resources.set_extraction_path(egg_cache)
     from trac.web import cgi_frontend
     cgi_frontend.run()
Index: branches/0.11-stable/trac/admin/templates/admin_plugins.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_plugins.html (revision 6572)
+++ branches/0.11-stable/trac/admin/templates/admin_plugins.html (revision 7388)
@@ -17,5 +17,5 @@
     <h2>Manage Plugins</h2>
 
-    <form id="addplug" class="addnew" method="post" enctype="multipart/form-data">
+    <form id="addplug" class="addnew" method="post" enctype="multipart/form-data" action="">
       <fieldset>
         <legend>Install Plugin:</legend>
@@ -41,5 +41,5 @@
     </form>
 
-    <form py:for="idx, plugin in enumerate(plugins)" method="post">
+    <form py:for="idx, plugin in enumerate(plugins)" method="post" action="">
       <div class="plugin">
         <h3>${plugin.name} ${plugin.version}</h3>
Index: branches/0.11-stable/trac/admin/templates/deploy_trac.fcgi
===================================================================
--- branches/0.11-stable/trac/admin/templates/deploy_trac.fcgi (revision 7069)
+++ branches/0.11-stable/trac/admin/templates/deploy_trac.fcgi (revision 7443)
@@ -1,3 +1,3 @@
-#!/usr/bin/python
+#!${executable}
 # -*- coding: utf-8 -*-
 #
@@ -18,10 +18,15 @@
 try:
     import os
-    import tempfile
+    import pkg_resources
     if 'TRAC_ENV' not in os.environ and \
        'TRAC_ENV_PARENT_DIR' not in os.environ:
         os.environ['TRAC_ENV'] = '${env.path}'
     if 'PYTHON_EGG_CACHE' not in os.environ:
-        os.environ['PYTHON_EGG_CACHE'] = tempfile.gettempdir()
+        if 'TRAC_ENV' in os.environ:
+            egg_cache = os.path.join(os.environ['TRAC_ENV'], '.egg-cache')
+        elif 'TRAC_ENV_PARENT_DIR' in os.environ:
+            egg_cache = os.path.join(os.environ['TRAC_ENV_PARENT_DIR'], 
+                                     '.egg-cache')
+        pkg_resources.set_extraction_path(egg_cache)
     from trac.web import fcgi_frontend
     fcgi_frontend.run()
Index: branches/0.11-stable/trac/admin/templates/admin_milestones.html
===================================================================
--- branches/0.11-stable/trac/admin/templates/admin_milestones.html (revision 7166)
+++ branches/0.11-stable/trac/admin/templates/admin_milestones.html (revision 7388)
@@ -14,5 +14,5 @@
 
     <py:choose test="view">
-      <form py:when="'detail'" class="mod" method="post" id="modifymilestone">
+      <form py:when="'detail'" class="mod" method="post" id="modifymilestone" action="">
         <fieldset>
           <legend>Modify Milestone:</legend>
@@ -70,5 +70,5 @@
       <py:otherwise>
 
-        <form class="addnew" id="addmilestone" method="post">
+        <form class="addnew" id="addmilestone" method="post" action="">
           <fieldset>
             <legend>Add Milestone:</legend>
@@ -93,5 +93,5 @@
 
         <py:choose>
-          <form py:when="milestones" id="milestone_table" method="POST">
+          <form py:when="milestones" id="milestone_table" method="post" action="">
             <table class="listing" id="millist">
               <thead>
Index: branches/0.11-stable/trac/admin/templates/deploy_trac.wsgi
===================================================================
--- branches/0.11-stable/trac/admin/templates/deploy_trac.wsgi (revision 7065)
+++ branches/0.11-stable/trac/admin/templates/deploy_trac.wsgi (revision 7443)
@@ -1,3 +1,3 @@
-#!/usr/bin/python
+#!${executable}
 # -*- coding: utf-8 -*-
 #
@@ -16,12 +16,16 @@
 # Author: Noah Kantrowitz <noah@coderanger.net>
 import os
-import tempfile
-
-from trac.web.main import dispatch_request
-import pkg_resources
 
 def application(environ, start_request):
-    environ['trac.env_path'] = '${env.path}'
-    if 'PYTHON_EGG_CACHE' not in os.environ:
-        pkg_resources.set_extraction_path(tempfile.gettempdir())
+    if not 'trac.env_path_parent_dir' in environ:
+        environ.setdefault('trac.env_path', '${env.path}')
+    if 'PYTHON_EGG_CACHE' in environ:                                           
+        os.environ['PYTHON_EGG_CACHE'] = environ['PYTHON_EGG_CACHE']
+    elif 'trac.env_path' in environ:
+        os.environ['PYTHON_EGG_CACHE'] = os.path.join(environ['trac.env_path'],
+                                                      '.egg-cache')
+    elif 'trac.env_path_parent_dir' in environ:
+        os.environ['PYTHON_EGG_CACHE'] = os.path.join(environ['trac.env_path_parent_dir'],
+                                                      '.egg-cache')
+    from trac.web.main import dispatch_request
     return dispatch_request(environ, start_request)
Index: branches/0.11-stable/trac/loader.py
===================================================================
--- branches/0.11-stable/trac/loader.py (revision 7182)
+++ branches/0.11-stable/trac/loader.py (revision 7363)
@@ -36,4 +36,5 @@
     """Loader that loads any eggs on the search path and `sys.path`."""
     def _load_eggs(env, search_path, auto_enable=None):
+        # Note that the following doesn't seem to support unicode search_path
         distributions, errors = working_set.find_plugins(
             pkg_resources.Environment(search_path)
Index: branches/0.11-stable/trac/templates/macros.html
===================================================================
--- branches/0.11-stable/trac/templates/macros.html (revision 7166)
+++ branches/0.11-stable/trac/templates/macros.html (revision 7356)
@@ -135,4 +135,7 @@
     ${preview.rendered}
     <py:choose>
+      <p py:when="preview.size == 0">
+        <strong>(The file is empty)</strong>
+      </p>
       <p py:when="not preview.rendered">
         <strong>HTML preview not available</strong>,
Index: branches/0.11-stable/trac/templates/history_view.html
===================================================================
--- branches/0.11-stable/trac/templates/history_view.html (revision 6357)
+++ branches/0.11-stable/trac/templates/history_view.html (revision 7388)
@@ -16,6 +16,6 @@
 
       <form py:if="history" class="printableform" method="get" action="">
-        <input type="hidden" name="action" value="diff" />
         <div class="buttons">
+          <input type="hidden" name="action" value="diff" />
           <input type="submit" value="View changes" />
         </div>
Index: branches/0.11-stable/trac/templates/theme.html
===================================================================
--- branches/0.11-stable/trac/templates/theme.html (revision 7187)
+++ branches/0.11-stable/trac/templates/theme.html (revision 7388)
@@ -36,5 +36,5 @@
       <div id="ctxtnav" class="nav">
         <h2>Context Navigation</h2>
-          <ul>
+          <ul py:if="chrome.ctxtnav">
             <li py:for="i, elm in enumerate(chrome.ctxtnav)" class="${i == 0 and 'first ' or None}${i+1 == len(chrome.ctxtnav) and 'last' or None}">$elm</li>
           </ul>
Index: branches/0.11-stable/trac/templates/about.html
===================================================================
--- branches/0.11-stable/trac/templates/about.html (revision 6904)
+++ branches/0.11-stable/trac/templates/about.html (revision 7388)
@@ -10,7 +10,9 @@
     <link rel="stylesheet" type="text/css" href="${chrome.htdocs_location}css/about.css" />
     <script type="text/javascript">
+      //<![CDATA[
       jQuery(document).ready(function ($) {
         $("#systeminfo table").append("<tr><th>jQuery:</th><td>"+$().jquery+"</td></tr>");
       });
+      //]]>
     </script>
   </head>
Index: branches/0.11-stable/trac/tests/functional/tester.py
===================================================================
--- branches/0.11-stable/trac/tests/functional/tester.py (revision 7187)
+++ branches/0.11-stable/trac/tests/functional/tester.py (revision 7388)
@@ -73,9 +73,9 @@
         if summary == None:
             summary = random_sentence(4)
-        tc.formvalue('propform', 'field_summary', summary)
-        tc.formvalue('propform', 'field_description', random_page())
+        tc.formvalue('propertyform', 'field_summary', summary)
+        tc.formvalue('propertyform', 'field_description', random_page())
         if info:
             for field, value in info.items():
-                tc.formvalue('propform', 'field_%s' % field, value)
+                tc.formvalue('propertyform', 'field_%s' % field, value)
         tc.submit('submit')
         # we should be looking at the newly created ticket
@@ -149,5 +149,5 @@
         if comment is None:
             comment = random_sentence()
-        tc.formvalue('propform', 'comment', comment)
+        tc.formvalue('propertyform', 'comment', comment)
         tc.submit("submit")
         # Verify we're where we're supposed to be.
@@ -352,5 +352,5 @@
         """Set the milestone on a given ticket"""
         self.go_to_ticket(ticketid)
-        tc.formvalue('propform', 'milestone', milestone)
+        tc.formvalue('propertyform', 'milestone', milestone)
         tc.submit('submit')
         # TODO: verify the change occurred.
Index: branches/0.11-stable/trac/wiki/default-pages/TracModPython
===================================================================
--- branches/0.11-stable/trac/wiki/default-pages/TracModPython (revision 6915)
+++ branches/0.11-stable/trac/wiki/default-pages/TracModPython (revision 7439)
@@ -64,4 +64,6 @@
     # See description above        
     PythonOption TracUriRoot /projects/myproject
+    # Override default python egg cache location
+    PythonOption PYTHON_EGG_CACHE /var/trac/myprojects/egg-cache
 }}}
 
Index: branches/0.11-stable/trac/wiki/default-pages/TracCgi
===================================================================
--- branches/0.11-stable/trac/wiki/default-pages/TracCgi (revision 6867)
+++ branches/0.11-stable/trac/wiki/default-pages/TracCgi (revision 7405)
@@ -93,6 +93,6 @@
 }}}
 
-Note that in order to get this `htdocs` directory, you need first to extract the relevant Trac resources using the `copystatic` command of TracAdmin:
-[[TracAdminHelp(copystatic)]]
+Note that in order to get this `htdocs` directory, you need first to extract the relevant Trac resources using the `deploy` command of TracAdmin:
+[[TracAdminHelp(deploy)]]
 
 
Index: branches/0.11-stable/trac/wiki/default-pages/WikiStart
===================================================================
--- branches/0.11-stable/trac/wiki/default-pages/WikiStart (revision 7237)
+++ branches/0.11-stable/trac/wiki/default-pages/WikiStart (revision 7452)
@@ -1,3 +1,3 @@
-= Welcome to Trac 0.11dev =
+= Welcome to Trac 0.11-stable =
 
 Trac is a '''minimalistic''' approach to '''web-based''' management of
Index: branches/0.11-stable/trac/wiki/web_ui.py
===================================================================
--- branches/0.11-stable/trac/wiki/web_ui.py (revision 7034)
+++ branches/0.11-stable/trac/wiki/web_ui.py (revision 7396)
@@ -458,13 +458,14 @@
 
         # Add registered converters
-        for conversion in Mimeview(self.env).get_supported_conversions(
-                                             'text/x-trac-wiki'):
-            conversion_href = req.href.wiki(page.name, version=version,
-                                            format=conversion[0])
-            # or...
-            conversion_href = get_resource_url(self.env, page.resource,
-                                               req.href, format=conversion[0])
-            add_link(req, 'alternate', conversion_href, conversion[1],
-                     conversion[3])
+        if page.exists:
+            for conversion in Mimeview(self.env).get_supported_conversions(
+                                                 'text/x-trac-wiki'):
+                conversion_href = req.href.wiki(page.name, version=version,
+                                                format=conversion[0])
+                # or...
+                conversion_href = get_resource_url(self.env, page.resource,
+                                                req.href, format=conversion[0])
+                add_link(req, 'alternate', conversion_href, conversion[1],
+                         conversion[3])
 
         data = self._page_data(req, page)
@@ -618,2 +619,7 @@
                        datetime.fromtimestamp(ts, utc), author,
                        shorten_result(text, terms))
+        
+        # Attachments
+        for result in AttachmentModule(self.env).get_search_results(
+            req, wiki_realm, terms):
+            yield result
Index: branches/0.11-stable/trac/wiki/intertrac.py
===================================================================
--- branches/0.11-stable/trac/wiki/intertrac.py (revision 6904)
+++ branches/0.11-stable/trac/wiki/intertrac.py (revision 7312)
@@ -51,5 +51,5 @@
                 raise PermissionError(_("Can't view %(link)s:", link=link))
         else:
-            href = req.href(link)
+            href = req.href(link.rstrip(':'))
         req.redirect(href)
 
Index: branches/0.11-stable/trac/wiki/tests/wiki-tests.txt
===================================================================
--- branches/0.11-stable/trac/wiki/tests/wiki-tests.txt (revision 7206)
+++ branches/0.11-stable/trac/wiki/tests/wiki-tests.txt (revision 7400)
@@ -325,4 +325,6 @@
 trac+devel@another-site.fr,
 T_r=a-c1.23@yet_another-site.edu.au
+!not@an.email.com
+someone@louvre.museum-
 ------------------------------
 <p>
@@ -334,4 +336,6 @@
 <a class="mail-link" href="mailto:trac+devel@another-site.fr";><span class="icon">trac+devel@another-site.fr</span></a>,
 <a class="mail-link" href="mailto:T_r=a-c1.23@yet_another-site.edu.au";><span class="icon">T_r=a-c1.23@yet_another-site.edu.au</span></a>
+not@an.email.com
+<a class="mail-link" href="mailto:someone@louvre.museum";><span class="icon">someone@louvre.museum</span></a>-
 </p>
 ------------------------------
Index: branches/0.11-stable/trac/wiki/tests/formatter.py
===================================================================
--- branches/0.11-stable/trac/wiki/tests/formatter.py (revision 6181)
+++ branches/0.11-stable/trac/wiki/tests/formatter.py (revision 7313)
@@ -141,16 +141,21 @@
             match = re.match(r"u?'(.*)' != u?'(.*)'", msg)
             if match:
-                sep = '-' * 15
                 g1 = ["%s\n" % x for x in match.group(1).split(r'\n')]
                 g2 = ["%s\n" % x for x in match.group(2).split(r'\n')]
-                diff = ''.join(list(difflib.unified_diff(g1, g2)))
-                msg = '\n%s expected:\n%s\n%s actual:\n%s\n%s' \
-                      ' wiki text:\n%s\ndiff:\n%s' \
-                      % (sep, ''.join(g1), sep, ''.join(g2), sep,
-# Tip: sometimes, 'expected' and 'actual' differ only by whitespace.
-#      If so, replace the above lines by those two:
-#                      % (sep, match.group(1).replace(' ', '.'), sep
-#                         sep, match.group(2).replace(' ', '.'), sep,
-                         self.input, diff)
+                expected = ''.join(g1)
+                actual = ''.join(g2)
+                wiki = repr(self.input).replace(r'\n', '\n')
+                diff = ''.join(list(difflib.unified_diff(g1, g2, 'expected',
+                                                         'actual')))
+                # Tip: sometimes, 'expected' and 'actual' differ only by 
+                #      whitespace, so it can be useful to visualize them, e.g.
+                # expected = expected.replace(' ', '.')
+                # actual = actual.replace(' ', '.')
+                def info(*args):
+                    return '\n========== %s: ==========\n%s' % args
+                msg = info('expected', expected)
+                msg += info('actual', actual)
+                msg += info('wiki', ''.join(wiki))
+                msg += info('diff', diff)
             raise AssertionError( # See below for details
                 '%s\n\n%s:%s: "%s" (%s flavor)' \
Index: branches/0.11-stable/trac/wiki/parser.py
===================================================================
--- branches/0.11-stable/trac/wiki/parser.py (revision 7027)
+++ branches/0.11-stable/trac/wiki/parser.py (revision 7290)
@@ -75,5 +75,5 @@
     _post_rules = [
         # e-mails
-        r"(?P<email>%s)" % EMAIL_LOOKALIKE_PATTERN,
+        r"(?P<email>!?%s)" % EMAIL_LOOKALIKE_PATTERN,
         # > ...
         r"(?P<citation>^(?P<cdepth>>(?: *>)*))",
Index: branches/0.11-stable/trac/wiki/formatter.py
===================================================================
--- branches/0.11-stable/trac/wiki/formatter.py (revision 7205)
+++ branches/0.11-stable/trac/wiki/formatter.py (revision 7399)
@@ -342,5 +342,5 @@
         ns = fullmatch.group('sns')
         target = self._unquote(fullmatch.group('stgt'))
-        return self._make_link(ns, target, match, match)
+        return self._make_link(ns, target, match, match, fullmatch)
 
     def _lhref_formatter(self, match, fullmatch):
@@ -372,7 +372,7 @@
             return tag.a(label or rel, href=path + query + fragment)
         else:
-            return self._make_link(ns, target, match, label)
-
-    def _make_link(self, ns, target, match, label):
+            return self._make_link(ns, target, match, label, fullmatch)
+
+    def _make_link(self, ns, target, match, label, fullmatch):
         # first check for an alias defined in trac.ini
         ns = self.env.config['intertrac'].get(ns, ns)
@@ -391,5 +391,5 @@
                 return olabel or otarget
         else:
-            if label == target:
+            if label == target and not fullmatch.group('label'):
                 # add ns for Inter* links when nothing is set
                 label = ns+':'+label
@@ -855,6 +855,4 @@
                 self._tabstops = []
 
-            if escape_newlines:
-                line += ' [[BR]]'
             self.in_list_item = False
             self.in_quote = False
@@ -871,11 +869,14 @@
                 self.close_def_list()
 
-            if self.in_table and line.strip()[0:2] != '||':
+            if self.in_table and not line.lstrip().startswith('||'):
                 self.close_table()
 
-            if len(result) and not self.in_list_item and not self.in_def_list \
-                    and not self.in_table:
-                self.open_paragraph()
-            self.out.write(result + os.linesep)
+            sep = os.linesep
+            if not(self.in_list_item or self.in_def_list or self.in_table):
+                if len(result):
+                    self.open_paragraph()
+                if escape_newlines and not result.rstrip().endswith('<br />'):
+                    sep = '<br />' + sep
+            self.out.write(result + sep)
             self.close_table_row()
 
Index: branches/0.11-stable/trac/wiki/templates/wiki_delete.html
===================================================================
--- branches/0.11-stable/trac/wiki/templates/wiki_delete.html (revision 6419)
+++ branches/0.11-stable/trac/wiki/templates/wiki_delete.html (revision 7388)
@@ -22,6 +22,6 @@
       <h1>Delete $range <a href="$current_href">$page.name</a></h1>
       <form action="$current_href" method="post">
-        <input type="hidden" name="action" value="delete" />
         <p>
+          <input type="hidden" name="action" value="delete" />
           <strong>Are you sure you want to ${not range and 'completely' or ''} delete $range this page?</strong>
           <br />
Index: branches/0.11-stable/trac/wiki/templates/wiki_diff.html
===================================================================
--- branches/0.11-stable/trac/wiki/templates/wiki_diff.html (revision 6139)
+++ branches/0.11-stable/trac/wiki/templates/wiki_diff.html (revision 7388)
@@ -10,10 +10,12 @@
                  (not changes[0].diffs or new_version == latest_version)"
       method="get" action="${href.wiki(page.name)}">
-      <input type="hidden" name="action" value="delete" />
-      <input type="hidden" name="version" value="$new_version" />
-      <input type="hidden" name="old_version" value="$old_version" />
-      <input type="submit" name="delete_version" value="Delete ${
-        new_version - old_version &gt; 1 and 'version %d to ' % (old_version+1) or ''
-        }version $new_version" />
+      <div>
+        <input type="hidden" name="action" value="delete" />
+        <input type="hidden" name="version" value="$new_version" />
+        <input type="hidden" name="old_version" value="$old_version" />
+        <input type="submit" name="delete_version" value="Delete ${
+          new_version - old_version &gt; 1 and 'version %d to ' % (old_version+1) or ''
+          }version $new_version" />
+      </div>
     </form>
   </div></py:match>
Index: branches/0.11-stable/trac/search/templates/search.html
===================================================================
--- branches/0.11-stable/trac/search/templates/search.html (revision 7149)
+++ branches/0.11-stable/trac/search/templates/search.html (revision 7352)
@@ -54,5 +54,5 @@
               <dd class="searchable">${result.excerpt}</dd>
               <dd>
-                <span class="author">By ${authorinfo(result.author)}</span> &mdash;
+                <py:if test="result.author"><span class="author">By ${format_author(result.author)}</span> &mdash;</py:if>
                 <span class="date">${result.date}</span>
               </dd>
Index: branches/0.11-stable/trac/notification.py
===================================================================
--- branches/0.11-stable/trac/notification.py (revision 6924)
+++ branches/0.11-stable/trac/notification.py (revision 7400)
@@ -27,6 +27,11 @@
 
 MAXHEADERLEN = 76
-EMAIL_LOOKALIKE_PATTERN = (r"[a-zA-Z0-9.'=+_-]+" '@'
-                            '(?:[a-zA-Z0-9_-]+\.)+[a-zA-Z]{2,4}')
+EMAIL_LOOKALIKE_PATTERN = (
+        # the local part
+        r"[a-zA-Z0-9.'=+_-]+" '@'
+        # the domain name part (RFC:1035)
+        '(?:[a-zA-Z0-9_-]+\.)+' # labels (but also allow '_')
+        '[a-zA-Z](?:[-a-zA-Z\d]*[a-zA-Z\d])?' # TLD
+        )
 
 class NotificationSystem(Component):
@@ -404,5 +409,10 @@
         recrlf = re.compile("\r?\n")
         msgtext = CRLF.join(recrlf.split(msgtext))
+        start = time.time()
         self.server.sendmail(msg['From'], recipients, msgtext)
+        t = time.time() - start
+        if t > 5:
+            self.env.log.warning('Slow mail submission (%.2f s), '
+                                 'check your mail setup' % t)
 
     def finish_send(self):
Index: branches/0.11-stable/trac/util/translation.py
===================================================================
--- branches/0.11-stable/trac/util/translation.py (revision 6904)
+++ branches/0.11-stable/trac/util/translation.py (revision 7423)
@@ -33,6 +33,5 @@
     else:
         retval = plural
-    if kwargs:
-        retval %= kwargs
-    return retval
+    kwargs.setdefault('num', num)
+    return retval % kwargs
 ngettext = ngettext_noop
Index: branches/0.11-stable/trac/util/__init__.py
===================================================================
--- branches/0.11-stable/trac/util/__init__.py (revision 7192)
+++ branches/0.11-stable/trac/util/__init__.py (revision 7384)
@@ -19,5 +19,4 @@
 
 import locale
-import md5
 import os
 import re
@@ -30,5 +29,5 @@
 # Imports for backward compatibility
 from trac.core import TracError
-from trac.util.compat import reversed, sorted, tee
+from trac.util.compat import reversed, sorted, tee, md5
 from trac.util.html import escape, unescape, Markup, Deuglifier
 from trac.util.text import CRLF, to_utf8, to_unicode, shorten_line, \
@@ -78,5 +77,5 @@
             if hasattr(os, 'O_BINARY'):
                 flags += os.O_BINARY
-            return path, os.fdopen(os.open(path, flags), 'w')
+            return path, os.fdopen(os.open(path, flags, 0666), 'w')
         except OSError:
             idx += 1
@@ -272,9 +271,8 @@
     # /* Then our magic string */
     # /* Then the raw salt */
-    m = md5.new()
-    m.update(password + magic + salt)
+    m = md5(password + magic + salt)
 
     # /* Then just as many characters of the MD5(pw,salt,pw) */
-    mixin = md5.md5(password + salt + password).digest()
+    mixin = md5(password + salt + password).digest()
     for i in range(0, len(password)):
         m.update(mixin[i % 16])
@@ -294,5 +292,5 @@
     # /* and now, just to make sure things don't run too fast */
     for i in range(1000):
-        m2 = md5.md5()
+        m2 = md5()
         if i & 1:
             m2.update(password)
Index: branches/0.11-stable/trac/util/compat.py
===================================================================
--- branches/0.11-stable/trac/util/compat.py (revision 7134)
+++ branches/0.11-stable/trac/util/compat.py (revision 7384)
@@ -140,2 +140,9 @@
             pass
         return newfunc
+
+
+# The md5 module is deprecated in Python 2.5
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import md5
Index: branches/0.11-stable/trac/util/daemon.py
===================================================================
--- branches/0.11-stable/trac/util/daemon.py (revision 5902)
+++ branches/0.11-stable/trac/util/daemon.py (revision 7358)
@@ -18,5 +18,5 @@
 
 def daemonize(pidfile=None, progname=None, stdin='/dev/null',
-              stdout='/dev/null', stderr='/dev/null'):
+              stdout='/dev/null', stderr='/dev/null', umask=022):
     """Fork a daemon process."""
 
@@ -51,5 +51,5 @@
     # Decouple from parent environment
     os.chdir('/')
-    os.umask(0)
+    os.umask(umask)
     os.setsid()
 
Index: branches/0.11-stable/trac/util/datefmt.py
===================================================================
--- branches/0.11-stable/trac/util/datefmt.py (revision 6904)
+++ branches/0.11-stable/trac/util/datefmt.py (revision 7263)
@@ -36,11 +36,12 @@
      - If `t` is already a `datetime` object, it is simply returned.
      - If `t` is None, the current time will be used.
-     - If `t` is a number, it is interpreted as a timestamp. If no `tzinfo`
-       is given, the local timezone will be used for the conversion.
+     - If `t` is a number, it is interpreted as a timestamp.
+     
+    If no `tzinfo` is given, the local timezone will be used.
 
     Any other input will trigger a `TypeError`.
     """
     if t is None:
-        return datetime.now(localtz)
+        return datetime.now(tzinfo or localtz)
     elif isinstance(t, datetime):
         return t
Index: branches/0.11-stable/trac/util/text.py
===================================================================
--- branches/0.11-stable/trac/util/text.py (revision 6904)
+++ branches/0.11-stable/trac/util/text.py (revision 7441)
@@ -111,4 +111,11 @@
         return '*******'
 
+def console_print(out, *args):
+    cons_charset = getattr(out, 'encoding', None)
+    # Windows returns 'cp0' to indicate no encoding
+    if cons_charset in (None, 'cp0'):
+        cons_charset = 'utf-8'
+    out.write(' '.join([to_unicode(a).encode(cons_charset, 'replace') 
+                        for a in args])+ '\n')
 
 # -- Plain text formatting
Index: branches/0.11-stable/trac/web/standalone.py
===================================================================
--- branches/0.11-stable/trac/web/standalone.py (revision 6904)
+++ branches/0.11-stable/trac/web/standalone.py (revision 7380)
@@ -170,7 +170,11 @@
                           dest='pidfile',
                           help='When daemonizing, file to which to write pid')
+        parser.add_option('--umask', action='store', type='int', dest='umask',
+                          metavar='MASK',
+                          help='When daemonizing, file mode creation mask '
+                          'to use (default 022)')
 
     parser.set_defaults(port=None, hostname='', base_path='', daemonize=False,
-                        protocol='http')
+                        protocol='http', umask=022)
     options, args = parser.parse_args()
 
@@ -185,4 +189,7 @@
             parser.error('the --single-env option cannot be used with '
                          'more than one enviroment')
+    if options.daemonize and options.autoreload:
+        parser.error('the --auto-reload option cannot be used with '
+                     '--daemonize')
 
     if options.port is None:
@@ -193,13 +200,4 @@
         }[options.protocol]
     server_address = (options.hostname, options.port)
-
-    # autoreload doesn't work when daemonized and using relative paths
-    if options.daemonize and options.autoreload:
-        for path in args + [options.env_parent_dir, options.pidfile]:
-            if path and not os.path.isabs(path):
-                parser.error('"%s" is not an absolute path.\n\n'
-                             'when using both --auto-reload and --daemonize '
-                             'all path arguments must be absolute'
-                             % path)
 
     # relative paths don't work when daemonized
@@ -244,5 +242,6 @@
     try:
         if options.daemonize:
-            daemon.daemonize(pidfile=options.pidfile, progname='tracd')
+            daemon.daemonize(pidfile=options.pidfile, progname='tracd',
+                             umask=options.umask)
 
         if options.autoreload:
Index: branches/0.11-stable/trac/web/api.py
===================================================================
--- branches/0.11-stable/trac/web/api.py (revision 7003)
+++ branches/0.11-stable/trac/web/api.py (revision 7384)
@@ -27,7 +27,8 @@
 
 from trac.core import Interface, TracError
-from trac.util import get_last_traceback
+from trac.util import get_last_traceback, md5
 from trac.util.datefmt import http_date, localtz
 from trac.web.href import Href
+from trac.web.wsgi import _FileWrapper
 
 HTTP_STATUS = dict([(code, reason.title()) for code, (reason, description)
@@ -244,6 +245,5 @@
         """
         if isinstance(extra, list):
-            import md5
-            m = md5.new()
+            m = md5()
             for elt in extra:
                 m.update(repr(elt))
@@ -393,8 +393,7 @@
 
         if self.method != 'HEAD':
-            self._response = file(path, 'rb')
-            file_wrapper = self.environ.get('wsgi.file_wrapper')
-            if file_wrapper:
-                self._response = file_wrapper(self._response, 4096)
+            fileobj = file(path, 'rb')
+            file_wrapper = self.environ.get('wsgi.file_wrapper', _FileWrapper)
+            self._response = file_wrapper(fileobj, 4096)
         raise RequestDone
 
Index: branches/0.11-stable/trac/web/wsgi.py
===================================================================
--- branches/0.11-stable/trac/web/wsgi.py (revision 6904)
+++ branches/0.11-stable/trac/web/wsgi.py (revision 7376)
@@ -87,5 +87,6 @@
         response = application(self.environ, self._start_response)
         try:
-            if isinstance(response, self.wsgi_file_wrapper) \
+            if self.wsgi_file_wrapper is not None \
+                    and isinstance(response, self.wsgi_file_wrapper) \
                     and hasattr(self, '_sendfile'):
                 self._sendfile(response.fileobj)
Index: branches/0.11-stable/trac/web/tests/auth.py
===================================================================
--- branches/0.11-stable/trac/web/tests/auth.py (revision 4176)
+++ branches/0.11-stable/trac/web/tests/auth.py (revision 7386)
@@ -17,5 +17,6 @@
     def test_anonymous_access(self):
         req = Mock(incookie=Cookie(), href=Href('/trac.cgi'),
-                   remote_addr='127.0.0.1', remote_user=None)
+                   remote_addr='127.0.0.1', remote_user=None,
+                   base_path='/trac.cgi')
         self.assertEqual(None, self.module.authenticate(req))
 
@@ -25,5 +26,6 @@
         req = Mock(cgi_location='/trac', href=Href('/trac.cgi'),
                    incookie=incookie, outcookie=Cookie(),
-                   remote_addr='127.0.0.1', remote_user=None)
+                   remote_addr='127.0.0.1', remote_user=None,
+                   base_path='/trac.cgi')
         self.assertEqual(None, self.module.authenticate(req))
 
@@ -36,5 +38,5 @@
         outcookie = Cookie()
         req = Mock(incookie=incookie, outcookie=outcookie,
-                   href=Href('/trac.cgi'),
+                   href=Href('/trac.cgi'), base_path='/trac.cgi',
                    remote_addr='127.0.0.1', remote_user=None)
         self.assertEqual('john', self.module.authenticate(req))
@@ -50,5 +52,6 @@
         req = Mock(cgi_location='/trac', href=Href('/trac.cgi'),
                    incookie=incookie, outcookie=outcookie,
-                   remote_addr='192.168.0.100', remote_user=None)
+                   remote_addr='192.168.0.100', remote_user=None,
+                   base_path='/trac.cgi')
         self.assertEqual(None, self.module.authenticate(req))
         self.failIf('trac_auth' not in req.outcookie)
@@ -63,5 +66,5 @@
         outcookie = Cookie()
         req = Mock(incookie=incookie, outcookie=outcookie,
-                   href=Href('/trac.cgi'),
+                   href=Href('/trac.cgi'), base_path='/trac.cgi',
                    remote_addr='192.168.0.100', remote_user=None)
         self.assertEqual('john', self.module.authenticate(req))
@@ -73,6 +76,7 @@
         # preserved.
         req = Mock(cgi_location='/trac', href=Href('/trac.cgi'),
-                   incookie=Cookie(), outcookie=outcookie,
-                   remote_addr='127.0.0.1', remote_user='john', authname='john')
+                   incookie=Cookie(), outcookie=outcookie, 
+                   remote_addr='127.0.0.1', remote_user='john', 
+                   authname='john', base_path='/trac.cgi')
         self.module._do_login(req)
 
@@ -95,7 +99,7 @@
         outcookie = Cookie()
         req = Mock(cgi_location='/trac', href=Href('/trac.cgi'),
-                   incookie=Cookie(), outcookie=outcookie,
+                   incookie=Cookie(), outcookie=outcookie, 
                    remote_addr='127.0.0.1', remote_user='John',
-                   authname='anonymous')
+                   authname='anonymous', base_path='/trac.cgi')
         self.module._do_login(req)
 
@@ -111,5 +115,6 @@
     def test_login_no_username(self):
         req = Mock(incookie=Cookie(), href=Href('/trac.cgi'),
-                   remote_addr='127.0.0.1', remote_user=None)
+                   remote_addr='127.0.0.1', remote_user=None,
+                   base_path='/trac.cgi')
         self.assertRaises(TracError, self.module._do_login, req)
 
@@ -121,5 +126,5 @@
         incookie['trac_auth'] = '123'
         req = Mock(incookie=incookie, outcookie=Cookie(),
-                   href=Href('/trac.cgi'),
+                   href=Href('/trac.cgi'), base_path='/trac.cgi',
                    remote_addr='127.0.0.1', remote_user='john', authname='john')
         self.module._do_login(req) # this shouldn't raise an error
@@ -132,5 +137,5 @@
         incookie['trac_auth'] = '123'
         req = Mock(incookie=incookie, authname='john',
-                   href=Href('/trac.cgi'),
+                   href=Href('/trac.cgi'), base_path='/trac.cgi',
                    remote_addr='127.0.0.1', remote_user='tom')
         self.assertRaises(AssertionError, self.module._do_login, req)
@@ -144,6 +149,7 @@
         outcookie = Cookie()
         req = Mock(cgi_location='/trac', href=Href('/trac.cgi'),
-                   incookie=incookie, outcookie=outcookie,
-                   remote_addr='127.0.0.1', remote_user=None, authname='john')
+                   incookie=incookie, outcookie=outcookie, 
+                   remote_addr='127.0.0.1', remote_user=None, authname='john',
+                   base_path='/trac.cgi')
         self.module._do_logout(req)
         self.failIf('trac_auth' not in outcookie)
@@ -155,5 +161,5 @@
                    incookie=Cookie(), outcookie=Cookie(),
                    remote_addr='127.0.0.1', remote_user=None,
-                   authname='anonymous')
+                   authname='anonymous', base_path='/trac.cgi')
         self.module._do_logout(req) # this shouldn't raise an error
 
Index: branches/0.11-stable/trac/web/tests/session.py
===================================================================
--- branches/0.11-stable/trac/web/tests/session.py (revision 6708)
+++ branches/0.11-stable/trac/web/tests/session.py (revision 7303)
@@ -163,4 +163,7 @@
         cursor = self.db.cursor()
         cursor.execute("INSERT INTO session "
+                       "VALUES ('123456', 0, %s)",
+                       (0,))
+        cursor.execute("INSERT INTO session "
                        "VALUES ('987654', 0, %s)",
                        (time.time() - PURGE_AGE - 3600,))
Index: branches/0.11-stable/trac/web/chrome.py
===================================================================
--- branches/0.11-stable/trac/web/chrome.py (revision 6904)
+++ branches/0.11-stable/trac/web/chrome.py (revision 7295)
@@ -694,11 +694,5 @@
 
         if method == 'text':
-            if arity(stream.render) == 3:
-                # TODO: remove this when we depend on Genshi >= 0.5
-                return stream.render('text')
-            else:
-                buffer = cStringIO()
-                stream.render('text', out=buffer)
-                return buffer.getvalue()
+            return stream.render('text')
 
         doctype = {'text/html': DocType.XHTML_STRICT}.get(content_type)
@@ -719,11 +713,5 @@
 
         try:
-            if arity(stream.render) == 3:
-                # TODO: remove this when we depend on Genshi >= 0.5
-                return stream.render(method, doctype=doctype)
-            else:
-                buffer = cStringIO()
-                stream.render(method, doctype=doctype, out=buffer)
-                return buffer.getvalue()
+            return stream.render(method, doctype=doctype)
         except:
             # restore what may be needed by the error template
Index: branches/0.11-stable/trac/web/__init__.py
===================================================================
--- branches/0.11-stable/trac/web/__init__.py (revision 2078)
+++ branches/0.11-stable/trac/web/__init__.py (revision 7439)
@@ -1,1 +1,13 @@
-from trac.web.api import *
+# With mod_python we'll have to delay importing trac.web.api until
+# modpython_frontend.handler() has been called since the
+# PYTHON_EGG_CACHE variable is set from there
+#
+# TODO: Remove this once the Genshi zip_safe issue has been resolved.
+try:
+    import mod_python.apache
+    import sys
+    if 'trac.web.modpython_frontend' in sys.modules:
+        from trac.web.api import *
+except ImportError:
+    from trac.web.api import *
+
Index: branches/0.11-stable/trac/web/modpython_frontend.py
===================================================================
--- branches/0.11-stable/trac/web/modpython_frontend.py (revision 6904)
+++ branches/0.11-stable/trac/web/modpython_frontend.py (revision 7439)
@@ -19,5 +19,10 @@
 import os
 import pkg_resources
+import sys
 import urllib
+try:
+    import threading
+except ImportError:
+    import dummy_threading as threading
 
 from mod_python import apache
@@ -83,8 +88,4 @@
             environ['PATH_INFO'] = urllib.unquote(request_uri[len(root_uri):])
 
-        egg_cache = req.subprocess_env.get('PYTHON_EGG_CACHE')
-        if egg_cache:
-            os.environ['PYTHON_EGG_CACHE'] = egg_cache
-
         WSGIGateway.__init__(self, environ, InputWrapper(req),
                              _ErrorsWrapper(lambda x: req.log_error(x)))
@@ -121,6 +122,26 @@
                 raise
 
-
+_first = True
+_first_lock = threading.Lock()
+            
 def handler(req):
+    global _first, _first_lock
+    try:
+        _first_lock.acquire()
+        if _first: 
+            _first = False
+            options = req.get_options()
+            egg_cache = options.get('PYTHON_EGG_CACHE')
+            if not egg_cache and options.get('TracEnv'):
+                egg_cache = os.path.join(options.get('TracEnv'), '.egg-cache')
+            if not egg_cache and options.get('TracEnvParentDir'):
+                egg_cache = os.path.join(options.get('TracEnvParentDir'), '.egg-cache')
+            if not egg_cache and req.subprocess_env.get('PYTHON_EGG_CACHE'):
+                egg_cache = req.subprocess_env.get('PYTHON_EGG_CACHE')
+            if egg_cache:
+                pkg_resources.set_extraction_path(egg_cache)
+            reload(sys.modules['trac.web'])
+    finally:
+        _first_lock.release()
     pkg_resources.require('Trac==%s' % VERSION)
     gateway = ModPythonGateway(req, req.get_options())
Index: branches/0.11-stable/trac/web/auth.py
===================================================================
--- branches/0.11-stable/trac/web/auth.py (revision 6904)
+++ branches/0.11-stable/trac/web/auth.py (revision 7386)
@@ -23,5 +23,4 @@
 except ImportError:
     import dummy_threading as threading
-import md5
 import os
 import re
@@ -36,5 +35,5 @@
 from trac.web.api import IAuthenticator, IRequestHandler
 from trac.web.chrome import INavigationContributor
-from trac.util import hex_entropy, md5crypt
+from trac.util import hex_entropy, md5, md5crypt
 
 
@@ -145,5 +144,5 @@
         req.authname = remote_user
         req.outcookie['trac_auth'] = cookie
-        req.outcookie['trac_auth']['path'] = req.href()
+        req.outcookie['trac_auth']['path'] = req.base_path or '/'
 
     def _do_logout(self, req):
@@ -175,5 +174,5 @@
         """
         req.outcookie['trac_auth'] = ''
-        req.outcookie['trac_auth']['path'] = req.href()
+        req.outcookie['trac_auth']['path'] = req.base_path or '/'
         req.outcookie['trac_auth']['expires'] = -10000
 
@@ -368,5 +367,5 @@
             return None
 
-        kd = lambda x: md5.md5(':'.join(x)).hexdigest()
+        kd = lambda x: md5(':'.join(x)).hexdigest()
         a1 = self.hash[auth['username']]
         a2 = kd([environ['REQUEST_METHOD'], auth['uri']])
Index: branches/0.11-stable/trac/web/session.py
===================================================================
--- branches/0.11-stable/trac/web/session.py (revision 6814)
+++ branches/0.11-stable/trac/web/session.py (revision 7386)
@@ -74,13 +74,22 @@
             return
 
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
         authenticated = int(self.authenticated)
+        now = int(time.time())
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
 
         if self._new:
+            self.last_visit = now
             self._new = False
-            cursor.execute("INSERT INTO session (sid,last_visit,authenticated)"
-                           " VALUES(%s,%s,%s)",
-                           (self.sid, self.last_visit, authenticated))
+            # The session might already exist even if _new is True since
+            # it could have been created by a concurrent request (#3563).
+            try:
+                cursor.execute("INSERT INTO session (sid,last_visit,authenticated)"
+                               " VALUES(%s,%s,%s)",
+                               (self.sid, self.last_visit, authenticated))
+            except Exception, e:
+                db.rollback()
+                self.env.log.warning('Session %s already exists: %s' % 
+                                     (self.sid, e))
         if self._old != self:
             attrs = [(self.sid, authenticated, k, v) for k, v in self.items()]
@@ -99,5 +108,4 @@
                 return
 
-        now = int(time.time())
         # Update the session last visit time if it is over an hour old,
         # so that session doesn't get purged
@@ -145,5 +153,5 @@
         assert self.sid, 'Session ID not set'
         self.req.outcookie[COOKIE_KEY] = self.sid
-        self.req.outcookie[COOKIE_KEY]['path'] = self.req.base_path
+        self.req.outcookie[COOKIE_KEY]['path'] = self.req.base_path or '/'
         self.req.outcookie[COOKIE_KEY]['expires'] = expires
 
Index: branches/0.11-stable/trac/web/main.py
===================================================================
--- branches/0.11-stable/trac/web/main.py (revision 7003)
+++ branches/0.11-stable/trac/web/main.py (revision 7386)
@@ -279,5 +279,5 @@
         else:
             req.outcookie['trac_form_token'] = hex_entropy(24)
-            req.outcookie['trac_form_token']['path'] = req.base_path
+            req.outcookie['trac_form_token']['path'] = req.base_path or '/'
             return req.outcookie['trac_form_token'].value
 
Index: branches/0.11-stable/setup.cfg
===================================================================
--- branches/0.11-stable/setup.cfg (revision 7237)
+++ branches/0.11-stable/setup.cfg (revision 7452)
@@ -1,4 +1,4 @@
 [egg_info]
-tag_build = dev
+tag_build = stable
 tag_svn_revision = true
 
Index: branches/0.11-stable/contrib/trac-post-commit-hook
===================================================================
--- branches/0.11-stable/contrib/trac-post-commit-hook (revision 5308)
+++ branches/0.11-stable/contrib/trac-post-commit-hook (revision 7438)
@@ -76,14 +76,4 @@
 import sys
 from datetime import datetime 
-
-from trac.env import open_environment
-from trac.ticket.notification import TicketNotifyEmail
-from trac.ticket import Ticket
-from trac.ticket.web_ui import TicketModule
-# TODO: move grouped_changelog_entries to model.py
-from trac.util.text import to_unicode
-from trac.util.datefmt import utc
-from trac.versioncontrol.api import NoSuchChangeset
-
 from optparse import OptionParser
 
@@ -110,4 +100,15 @@
 (options, args) = parser.parse_args(sys.argv[1:])
 
+if not 'PYTHON_EGG_CACHE' in os.environ:
+    os.environ['PYTHON_EGG_CACHE'] = os.path.join(options.project, '.egg-cache')
+
+from trac.env import open_environment
+from trac.ticket.notification import TicketNotifyEmail
+from trac.ticket import Ticket
+from trac.ticket.web_ui import TicketModule
+# TODO: move grouped_changelog_entries to model.py
+from trac.util.text import to_unicode
+from trac.util.datefmt import utc
+from trac.versioncontrol.api import NoSuchChangeset
 
 ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)'
Index: branches/0.11-stable/contrib/trac-pre-commit-hook
===================================================================
--- branches/0.11-stable/contrib/trac-pre-commit-hook (revision 4953)
+++ branches/0.11-stable/contrib/trac-pre-commit-hook (revision 7438)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
-# -*- coding: iso8859-1 -*-
+# -*- coding: utf-8 -*-
 #
-# Author: Jonas Borgstr�jonas@edgewall.com>
+# Author: Jonas Borgström <jonas@edgewall.com>
 #
 # This script will enforce the following policy:
@@ -19,4 +19,7 @@
 import re
 import sys
+
+if not 'PYTHON_EGG_CACHE' in os.environ:
+    os.environ['PYTHON_EGG_CACHE'] = os.path.join(sys.argv[1], '.egg-cache') 
 
 from trac.env import open_environment
Index: branches/0.11-stable/contrib/htdigest.py
===================================================================
--- branches/0.11-stable/contrib/htdigest.py (revision 6805)
+++ branches/0.11-stable/contrib/htdigest.py (revision 7384)
@@ -18,8 +18,13 @@
 import errno
 import fileinput
-import md5
 import sys
 from optparse import OptionParser
 from getpass import getpass
+
+# The md5 module is deprecated in Python 2.5
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import md5
 
 def ask_pass():
@@ -37,5 +42,5 @@
 
 def make_digest(userprefix, password):
-    return userprefix + md5.new(userprefix + password).hexdigest()
+    return userprefix + md5(userprefix + password).hexdigest()
 
 usage = "%prog [-c] [-b] passwordfile realm username"

Reply to: