[pypy-commit] benchmarks default: merge

fijal noreply at buildbot.pypy.org
Tue Jan 24 12:10:15 CET 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: 
Changeset: r163:f4a31718810d
Date: 2012-01-24 13:09 +0200
http://bitbucket.org/pypy/benchmarks/changeset/f4a31718810d/

Log:	merge

diff too long, truncating to 10000 out of 32654 lines

diff --git a/benchmarks.py b/benchmarks.py
--- a/benchmarks.py
+++ b/benchmarks.py
@@ -52,6 +52,11 @@
                      extra_args=['--benchmark=' + name],
                      iteration_scaling=0.1)
 
+for name in ['xml', 'text']:
+    _register_new_bm('bm_genshi', 'genshi_' + name,
+                     globals(), bm_env={'PYTHONPATH': relative('lib/genshi')},
+                     extra_args=['--benchmark=' + name])
+
 for name in ['float', 'nbody_modified', 'meteor-contest', 'fannkuch',
              'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast',
              'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon',
diff --git a/lib/genshi/COPYING b/lib/genshi/COPYING
new file mode 100644
--- /dev/null
+++ b/lib/genshi/COPYING
@@ -0,0 +1,28 @@
+Copyright (C) 2006-2010 Edgewall Software
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+ 3. The name of the author may not be used to endorse or promote
+    products derived from this software without specific prior
+    written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/genshi/ChangeLog b/lib/genshi/ChangeLog
new file mode 100644
--- /dev/null
+++ b/lib/genshi/ChangeLog
@@ -0,0 +1,472 @@
+Version 0.6.1
+http://svn.edgewall.org/repos/genshi/tags/0.6.1/
+(???, from branches/stable/0.6.x)
+
+ * Fix for error in how `HTMLFormFiller` would handle `textarea` elements if
+   no value was not supplied form them.
+ * The `HTMLFormFiller` now correctly handles check boxes and radio buttons
+   with an empty `value` attribute.
+
+
+Version 0.6
+http://svn.edgewall.org/repos/genshi/tags/0.6.0/
+(Apr 22 2010, from branches/stable/0.6.x)
+
+ * Support for Python 2.3 has been dropped.
+ * Rewrite of the XPath evaluation engine for better performance and improved
+   correctness. This is the result of integrating work done by Marcin Kurczych
+   during GSoC 2008.
+ * Updated the Python AST processing for template code evaluation to use the
+   `_ast` module instead of the deprecated `compiler` package, including an
+   adapter layer for Python 2.4. This, too, is the result of integrating work
+   done by  Marcin Kurczych during GSoC 2008.
+ * Added caching in the serialization stage for improved performance in some
+   cases.
+ * Various improvements to the HTML sanitization filter.
+ * Fix problem with I18n filter that would get confused by expressions in
+   attribute values when inside an `i18n:msg` block (ticket #250).
+ * Fix problem with the transformation filter dropping events after the
+   selection (ticket #290).
+ * `for` loops in template code blocks no longer establish their own locals
+   scope, meaning you can now access variables assigned in the loop outside
+   of the loop, just as you can in regular Python code (ticket #259).
+ * Import statements inside function definitions in template code blocks no 
+   longer result in an UndefinedError when the imported name is accessed 
+   (ticket #276).
+ * Fixed handling of relative URLs with fragment identifiers containing colons
+   in the `HTMLSanitizer` (ticket #274).
+ * Added an option to the `HTMLFiller` to also populate password fields.
+ * Match template processing no longer produces unwanted duplicate output in
+   some cases (ticket #254).
+ * Templates instantiated without a loader now get an implicit loader based on
+   their file path, or the current directory as a fallback (ticket #320).
+ * Added documentation for the `TemplateLoader`.
+ * Enhanced documentation for internationalization.
+
+
+Version 0.5.1
+http://svn.edgewall.org/repos/genshi/tags/0.5.1/
+(Jul 9 2008, from branches/stable/0.5.x)
+
+ * Fix problem with nested match templates not being applied when buffering
+   on the outer `py:match` is disabled. Thanks to Erik Bray for reporting the
+   problem and providing a test case!
+ * Fix problem in `Translator` filter that would cause the translation of
+   text nodes to fail if the translation function returned an object that was
+   not directly a string, but rather something like an instance of the
+   `LazyProxy` class in Babel (ticket #145).
+ * Fix problem with match templates incorrectly being applied multiple times.
+ * Includes from templates loaded via an absolute path now include the correct
+   file in nested directories as long if no search path has been configured
+   (ticket #240).
+ * Unbuffered match templates could result in parts of the matched content
+   being included in the output if the match template didn't actually consume
+   it via one or more calls to the `select()` function (ticket #243).
+
+
+Version 0.5
+http://svn.edgewall.org/repos/genshi/tags/0.5.0/
+(Jun 9 2008, from branches/stable/0.5.x)
+
+ * Added #include directive for text templates (ticket #115).
+ * Added new markup transformation filter contributed by Alec Thomas. This
+   provides gorgeous jQuery-inspired stream transformation capabilities based
+   on XPath expressions.
+ * When using HTML or XHTML serialization, the `xml:lang` attribute is
+   automatically translated to the `lang` attribute which HTML user agents
+   understand.
+ * Added support for the XPath 2 `matches()` function in XPath expressions,
+   which allow matching against regular expressions.
+ * Support for Python code blocks in templates can now be disabled
+   (ticket #123).
+ * Includes are now processed when the template is parsed if possible, but
+   only if the template loader is not set to do automatic reloading. Included
+   templates are basically inlined into the including template, which can
+   speed up rendering of that template a bit.
+ * Added new syntax for text templates, which is more powerful and flexible
+   with respect to white-space and line breaks. It also supports Python code
+   blocks. The old syntax is still available and the default for now, but in a
+   future release the new syntax will become the default, and some time after
+   that the old syntax will be removed.
+ * Added support for passing optimization hints to `<py:match>` directives,
+   which can speed up match templates in many cases, for example when a match
+   template should only be applied once to a stream, or when it should not be
+   applied recursively.
+ * Text templates now default to rendering as plain text; it is no longer
+   necessary to explicitly specify the "text" method to the `render()` or
+   `serialize()` method of the generated markup stream.
+ * XInclude elements in markup templates now support the `parse` attribute;
+   when set to "xml" (the default), the include is processed as before, but
+   when set to "text", the included template is parsed as a text template using
+   the new syntax (ticket #101).
+ * Python code blocks inside match templates are now executed (ticket #155).
+ * The template engine plugin no longer adds the `default_doctype` when the
+   `fragment` parameter is `True`.
+ * The `striptags` function now also removes HTML/XML-style comments (ticket
+   #150).
+ * The `py:replace` directive can now also be used as an element, with an
+   attribute named `value` (ticket #144).
+ * The `TextSerializer` class no longer strips all markup in text by default,
+   so that it is still possible to use the Genshi `escape` function even with
+   text templates. The old behavior is available via the `strip_markup` option
+   of the serializer (ticket #146).
+ * Assigning to a variable named `data` in a Python code block no longer
+   breaks context lookup.
+ * The `Stream.render` now accepts an optional `out` parameter that can be
+   used to pass in a writable file-like object to use for assembling the
+   output, instead of building a big string and returning it.
+ * The XHTML serializer now strips `xml:space` attributes as they are only
+   allowed on very few tags.
+ * Match templates are now applied in a more controlled fashion: in the order
+   they are declared in the template source, all match templates up to (and
+   including) the matching template itself are applied to the matched content,
+   whereas the match templates declared after the matching template are only
+   applied to the generated content (ticket #186).
+ * The `TemplateLoader` class now provides an `_instantiate()` method that can
+   be overridden by subclasses to implement advanced template instantiation
+   logic (ticket #204).
+ * The search path of the `TemplateLoader` class can now contain ''load
+   functions'' in addition to path strings. A load function is passed the
+   name of the requested template file, and should return a file-like object
+   and some metadata. New load functions are supplied for loading from egg
+   package data, and loading from different loaders depending on the path
+   prefix of the requested filename (ticket #182).
+ * Match templates can now be processed without keeping the complete matched
+   content in memory, which could cause excessive memory use on long pages.
+   The buffering can be disabled using the new `buffer` optimization hint on
+   the `<py:match>` directive.
+ * Improve error reporting when accessing an attribute in a Python expression
+   raises an `AttributeError` (ticket #191).
+ * The `Markup` class now supports mappings for right hand of the `%` (modulo)
+   operator in the same way the Python string classes do, except that the
+   substituted values are escape. Also, the special constructor which took
+   positional arguments that would be substituted was removed. Thus the
+   `Markup` class now supports the same arguments as that of its `unicode`
+   base class (ticket #211).
+ * The `Template` class and its subclasses, as well as the interpolation API,
+   now take an `filepath` parameter instead of `basedir` (ticket #207).
+ * The `XHTMLSerializer` now has a `drop_xml_decl` option that defaults to
+   `True`. Setting it to `False` will cause any XML decl in the serialized
+   stream to be included in the output as it would for XML serialization.
+ * Add support for a protocol that would allow interoperability of different
+   Python packages that generate and/or consume markup, based on the special
+   `__html__()` method (ticket #202).
+
+
+Version 0.4.4
+http://svn.edgewall.org/repos/genshi/tags/0.4.4/
+(Aug 14, 2007, from branches/stable/0.4.x)
+
+ * Fixed augmented assignment to local variables in Python code blocks.
+ * Fixed handling of nested function and class definitions in Python code
+   blocks.
+ * Includes were not raising `TemplateNotFound` exceptions even when no
+   fallback has been specified. That has been corrected.
+ * The template loader now raises a `TemplateNotFound` error when a previously
+   cached template is removed or renamed, where it previously was passing up
+   an `OSError`.
+ * The Genshi I18n filter can be configured to only extract messages found in
+   `gettext` function calls, ignoring any text nodes and attribute values
+   (ticket #138).
+
+
+Version 0.4.3
+http://svn.edgewall.org/repos/genshi/tags/0.4.3/
+(Jul 17 2007, from branches/stable/0.4.x)
+
+ * The I18n filter no longer extracts or translates literal strings in
+   attribute values that also contain expressions.
+ * Added `loader_callback` option to plugin interface, which allows specifying
+   a callback function that the template loader should invoke whenever a new
+   template is loaded (ticket #130). Note that the value for this option can
+   not be specified as a string, only as an actual function object, which means
+   it is not available for use through configuration files.
+ * The I18n filter now extracts messages from gettext functions even inside
+   ignored tags (ticket #132).
+ * The HTML sanitizer now strips any CSS comments in style attributes, which
+   could previously be used to hide malicious property values.
+ * The HTML sanitizer now also removes any HTML comments encountered, as those
+   may be used to hide malicious payloads targetting a certain "innovative"
+   browser that goes and interprets the content of specially prepared comments.
+ * Attribute access in template expressions no longer silently ignores
+   exceptions other than `AttributeError` raised in the attribute accessor.
+
+
+Version 0.4.2
+http://svn.edgewall.org/repos/genshi/tags/0.4.2/
+(Jun 20 2007, from branches/stable/0.4.x)
+
+ * The `doctype` parameter of the markup serializers now also accepts the "name"
+   of the doctype as string, in addition to the `(name, pubid, sysid)` tuple.
+ * The I18n filter was not replacing the original attributes with the
+   translation, but instead adding a second attribute with the same name.
+ * `TextTemplate` can now handle unicode source (ticket #125).
+ * A `<?python ?>` processing instruction containing trailing whitespace no
+   longer causes a syntax error (ticket #127).
+ * The I18n filter now skips the content of elements that have an `xml:lang`
+   attribute with a fixed string value. Basically, `xml:lang` can now be used
+   as a flag to mark specific sections as not needing localization.
+ * Added plugin for message extraction via Babel (http://babel.edgewall.org/).
+
+
+Version 0.4.1
+http://svn.edgewall.org/repos/genshi/tags/0.4.1/
+(May 21 2007, from branches/stable/0.4.x)
+
+ * Fix incorrect reference to translation function in the I18N filter.
+ * The `ET()` function now correctly handles attributes with a namespace.
+ * XML declarations are now processed internally, as well as written to the
+   output when XML serialization is used (ticket #111).
+ * Added the functions `encode()` and `get_serializer()` to the `genshi.output`
+   module, which provide a lower-level API to the functionality previously only
+   available through `Stream.render()` and `Stream.serialize()`.
+ * The `DocType` class now has a `get(name)` function that returns a `DOCTYPE`
+   tuple for a given string.
+ * Added frameset variants to the `DocType` constants for HTML 4.01 and XHTML
+   1.0.
+ * Improved I18n extraction for pluralizable messages: for any translation
+   function with multiple string arguments (such as ``ngettext``), a single
+   item with a tuple of strings is yielded, instead an item for each string
+   argument.
+ * The `HTMLFormFiller` stream filter no longer alters form elements for which
+   the data element contains no corresponding item.
+ * Code in `<?python ?>` processing instructions no longer gets the special
+   treatment as Python code in template expressions, i.e. item and attribute
+   access are no longer interchangeable (which was broken in a number of ways
+   anyway, see ticket #113). This change does not affect expressions.
+ * Numerous fixes for the execution of Python code in `<?python ?>` processing
+   instructions (tickets #113 and #114).
+ * The `py:def` (and `#def`) directive now supports "star args" (i.e. `*args`
+   and `**kwargs`) in the function declaration (ticket #116).
+
+
+Version 0.4
+http://svn.edgewall.org/repos/genshi/tags/0.4.0/
+(Apr 16 2007, from branches/stable/0.4.x)
+
+ * New example applications for CherryPy and web.py.
+ * The template loader now uses a LRU cache to limit the number of cached
+   templates to a configurable maximum. Also, a race condition in the template
+   loader was fixed by adding locking.
+ * A new filter (genshi.filters.HTMLFormFiller) was added, which can populate 
+   HTML forms based on a dictionary of values.
+ * The set of permitted tag and attribute names for the HTMLSanitizer can now
+   be configured per instance.
+ * The template engine plugin now supports a range of options for
+   configuration, for example to set the default serialization method, the
+   default output encoding, or the default DOCTYPE.
+ * The ElementTree adaptation function `ET()` has moved into the `genshi.input`
+   module.
+ * Allow `when` directives to omit the test expression as long as the
+   associated choose directive does have one. In that case, the when branch is
+   followed if the expression of the choose directive evaluates to a truth
+   value.
+ * Unsuccessful attribute or item lookups now return `Undefined` objects for
+   nicer error messages.
+ * Split up the `genshi.template` module into multiple modules inside the new
+   `genshi.template` package.
+ * Results of expression evaluation are no longer implicitly called if they
+   are callable.
+ * Instances of the `genshi.core.Attrs` class are now immutable (they are
+   subclasses of `tuple` instead of `list`).
+ * `MarkupTemplate`s can now be instantiated from markup streams, in addition
+   to strings and file-like objects (ticket #69).
+ * Improve handling of incorrectly nested tags in the HTML parser.
+ * Template includes can now be nested inside fallback content.
+ * Expressions can now contain dict literals (ticket #37).
+ * It is now possible to have one or more escaped dollar signs in front of a 
+   full expression (ticket #92).
+ * The `Markup` class is now available by default in template expressions
+   (ticket #67).
+ * The handling of namespace declarations in XML/XHTML output has been improved.
+ * The `Attrs` class no longer automatically wraps all attribute names in
+   `QName` objects. This is now the responsibility of whoever is instantiating
+   `Attrs` objects (for example, stream filters and generators).
+ * Python code blocks are now supported using the `<?python ?>` processing
+   instruction (ticket #84).
+ * The way errors in template expressions are handled can now be configured. The
+   option `LenientLookup` provides the same forgiving mode used in previous
+   Genshi versions, while `StrictLookup` raises exceptions when undefined
+   variables or members are accessed. The lenient mode is still the default in
+   this version, but that may change in the future. (ticket #88)
+ * If a variable is not necessarily defined at the top level of the template
+   data, the new built-in functions `defined(key)` and `value_of(key, default)`
+   can be used so that the template also works in strict lookup mode. These
+   functions were previously only available when using Genshi via the template
+   engine plugin (for compatibility with Kid).
+ * `style` attributes are no longer allowed by the `HTMLSanitizer` by default.
+   If they are explicitly added to the set of safe attributes, any unicode
+   escapes in the attribute value are now handled properly.
+ * Namespace declarations on conditional elements (for example using a `py:if`
+   directive`) are no longer moved to the following element when the element
+   originally carrying the declaration is removed from the stream (ticket #107).
+ * Added basic built-in support for internationalizing templates by providing
+   a new `Translator` class that can both extract localizable strings from a
+   stream, and replace those strings with their localizations at render time.
+   The code for this was largely taken from previous work done by Matt Good
+   and David Fraser.
+
+
+Version 0.3.6
+http://svn.edgewall.org/repos/genshi/tags/0.3.6/
+(Dec 11 2006, from branches/stable/0.3.x)
+
+ * The builder API now accepts streams as children of elements and fragments.
+
+
+Version 0.3.5
+http://svn.edgewall.org/repos/genshi/tags/0.3.5/
+(Nov 22 2006, from branches/stable/0.3.x)
+
+ * Fix XPath traversal in match templates. Previously, `div/p` would be treated 
+   the same as `div//p`, i.e. it would match all descendants and not just the
+   immediate children.
+ * Preserve whitespace in HTML `<pre>` elements also when they contain child
+   elements.
+ * Match templates no longer match their own output (ticket #77).
+ * Blank lines before directives in text templates are now preserved as
+   expected (ticket #62).
+
+
+Version 0.3.4
+http://svn.edgewall.org/repos/genshi/tags/0.3.4/
+(Nov 2 2006, from branches/stable/0.3.x)
+
+ * The encoding of HTML and XML files, as well as markup and text templates,
+   can now be specified. Also, the encoding specified in XML declarations is
+   now respected unless an expiclit encoding is requested.
+ * Expressions used as arguments for `py:with`, `py:def`, and `py:for`
+   directives can now contain non-ASCII strings.
+
+
+Version 0.3.3
+http://svn.edgewall.org/repos/genshi/tags/0.3.3/
+(Oct 16 2006, from branches/stable/0.3.x)
+
+ * Fixed bug introduced in 0.3.2 that broke the parsing of templates which
+   declare the same namespace more than once in a nested fashion.
+ * Fixed the parsing of HTML entity references inside attribute values, both
+   in the `XMLParser` and the `HTMLParser` classes.
+ * Some changes to usage of absolute vs. relative template paths to ensure that
+   the filenamed-keyed cache employed by the TemplateLoader doesn't mix up
+   templates with the same name, but from different subdirectories.
+
+
+Version 0.3.2
+http://svn.edgewall.org/repos/genshi/tags/0.3.2/
+(Oct 12 2006, from branches/stable/0.3.x)
+
+ * Exceptions from templates now contain the absolute path to the template file
+   when a search path is used. This enables tracebacks to display the line in
+   question.
+ * The template engine plugin now provides three different types: "genshi" and
+   "genshi-markup" map to markup templates, while "genshi-text" maps to text
+   templates.
+ * Fixed the namespace context used by XPath patterns in py:match templates.
+   The were erroneously using the namespace context of the elements being
+   matched, where they should rather use the context in which they were
+   defined.
+ * The contents of `<script>` and `<style>` elements are no longer escaped when
+   serializing to HTML but declaring the XHTML namespace in the template.
+ * Improved error message raised when using the `py:for` directive on an object
+   that is not iterable (ticket #60).
+ * Fixed the XPath function `starts-with()` which was always returning true
+   (ticket #61).
+
+
+Version 0.3.1
+http://svn.edgewall.org/repos/genshi/tags/0.3.1/
+(Sep 22 2006, from branches/stable/0.3.x)
+
+ * Includes and user-defined filters were not getting the correct context data
+   when used inside a match template (ticket #56).
+ * XPath patterns using the union operator (`|`) were returning only partial
+   results in some cases.
+
+
+Version 0.3
+http://svn.edgewall.org/repos/genshi/tags/0.3.0/
+(Sep 17 2006, from branches/stable/0.3.x)
+
+ * The project name was changed from "Markup" to "Genshi". See UPGRADE.txt
+   for upgrade instructions.
+ * Expression evaluation now differentiates between undefined variables and
+   variables that are defined but set to `None`. This also means that local
+   variables can override built-ins even if the local variable are set to
+   `None` (ticket #36).
+ * The plugin implementation now makes more functions available for use inside
+   templates: XML(), HTML(), defined(), and value-of(). These are mostly for
+   migration from Kid.
+ * The parsing of `py:with` directives has been improved: you can now assign
+   to multiple names, and semicolons inside string literals are treated as
+   expected.
+ * Generator expressions can now be used in template expressions (ticket #16).
+ * Added serialization to plain text (ticket #41).
+ * Calling functions from template expressions with *args and/or **kwargs
+   now works correctly (ticket #42).
+ * The `TemplateLoader` class and the `Template` instances that it manages are
+   now thread-safe, as they no longer keep any state related to the current
+   processing context.
+ * Stream filters and serializers can now be applied using the "pipe" (bitwise
+   or) operator "|".
+ * The execution of named template functions (`py:def`) no longer silently
+   swallows TypeError exceptions (ticket #44).
+ * The XML Parser now correctly handles unicode input (ticket #43).
+ * HTML entities can now be used in templates without having to declare an HTML
+   document type.
+ * Error reporting on undefined entities has been fixed.
+ * Fix traversal of substreams by XPath expressions. For example, the path
+   '*/*' no longer matches non-immediate child elements, and '@*' no longer
+   matches the attributes of descendants.
+ * Fixes for `py:match` which would get confused when it should be applied
+   to multiple elements (ticket #49).
+ * Using namespace prefixes in XPath expressions is now supported.
+ * Expressions now correctly handle slices (ticket #51).
+ * A simple text-based template language is now included for generating
+   plain text output (ticket #47).
+
+
+Version 0.2
+http://svn.edgewall.org/repos/genshi/tags/0.2.0/
+(Aug 22 2006, from branches/stable/0.2.x)
+
+ * XPath syntax errors now contain position info (ticket #20).
+ * Errors in expression evaluation now contain the correct line number in the
+   template (ticket #22).
+ * <script> and <style> element contents are no longer escaped when using HTML
+   serialization (ticket #24).
+ * In some cases expressions in templates did not get interpolated (ticket
+   #26).
+ * CDATA sections are now passed through the pipeline and serialized correctly.
+   That allows using <script> or <style> elements in XHTML output that is still
+   compatible with HTML user agents.
+ * The XHTML serializer now correctly handles elements in foreign namespaces
+   (such as SVG or MathML).
+ * Fixed relative includes in templates on Windows (ticket #27).
+ * Output can be encoded using legacy codecs such as ISO-8859-1. Any character
+   not representable in the chosen encoding gets replaced by the corresponding
+   XML character reference.
+ * String literals in XPath expressions that contain spaces are now parsed
+   as expected.
+ * Added support for the XPath functions boolean(), ceiling(), concat(),
+   contains(), false(), floor(), normalize-space(), number(), round(),
+   starts-with(), string-length(), substring(), substring-after(),
+   substring-before(), translate(), and true().
+ * Non-ASCII characters in expressions should now be handled correctly (ticket
+   #29).
+ * Default values for arguments of template functions now also work with
+   constants and complex expressions (they only worked for string or number
+   literals before).
+ * XPath expressions in now support XPath variables ($var) in predicates
+   (ticket #31).
+ * Expressions in templates can now span multiple lines if they are enclosed
+   in curly braces.
+ * py:def macros can now be invoked from within expressions inside attribute
+   values (ticket #34).
+
+
+Version 0.1
+http://svn.edgewall.org/repos/genshi/tags/0.1.0/
+(Aug 3 2006, from branches/stable/0.1.x)
+
+ * First public release
diff --git a/lib/genshi/MANIFEST.in b/lib/genshi/MANIFEST.in
new file mode 100644
--- /dev/null
+++ b/lib/genshi/MANIFEST.in
@@ -0,0 +1,5 @@
+exclude doc/2000ft.graffle
+recursive-exclude doc/logo.lineform *
+include doc/api/*.*
+include doc/*.html
+recursive-include genshi/template/tests/templates *.html *.txt
diff --git a/lib/genshi/README.txt b/lib/genshi/README.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/README.txt
@@ -0,0 +1,12 @@
+About Genshi
+============
+
+Genshi is a Python library that provides an integrated set of
+components for parsing, generating, and processing HTML, XML or other
+textual content for output generation on the web. The major feature is
+a template language, which is heavily inspired by Kid.
+
+For more information please see the documentation in the `doc`
+directory, and visit the Genshi web site:
+
+  <http://genshi.edgewall.org/>
diff --git a/lib/genshi/doc/2000ft.graffle b/lib/genshi/doc/2000ft.graffle
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/2000ft.graffle
@@ -0,0 +1,1333 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>AutoAdjust</key>
+	<false/>
+	<key>CanvasColor</key>
+	<dict>
+		<key>w</key>
+		<string>1</string>
+	</dict>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>CanvasScale</key>
+	<real>1</real>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2006-05-08 14:33:49 +0200</string>
+	<key>Creator</key>
+	<string>chris</string>
+	<key>DisplayScale</key>
+	<string>1 cm = 1 cm</string>
+	<key>GraphDocumentVersion</key>
+	<integer>5</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Bounds</key>
+			<string>{{58.1159, 157}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>54</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 Fragment}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{387.348, 157}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>53</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 TextTemplate}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{241.464, 376}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>52</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 Plain Text Serializer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{126, 376}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>51</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 XHTML Serializer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{241.464, 258}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>50</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 Transformer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>29</integer>
+			</dict>
+			<key>ID</key>
+			<integer>48</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{372, 148.88}</string>
+				<string>{317.768, 149.21}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>46</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{387.348, 119}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>47</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/wiki/Documentation/xml-templates.html</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 MarkupTemplate}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{372, 99}, {125.232, 99}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>1</string>
+					<key>g</key>
+					<string>1</string>
+					<key>r</key>
+					<string>1</string>
+				</dict>
+				<key>Font</key>
+				<string>Helvetica-Bold</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>46</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+					<key>GradientAngle</key>
+					<real>114</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>CornerRadius</key>
+					<real>5</real>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\i\b\fs24 \cf1 templating}</string>
+				<key>VerticalPad</key>
+				<integer>2</integer>
+			</dict>
+			<key>TextPlacement</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>29</integer>
+			</dict>
+			<key>ID</key>
+			<integer>45</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{168, 149.5}</string>
+				<string>{222.232, 149.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>44</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{58.1159, 119}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>43</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 Element}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>23</integer>
+			</dict>
+			<key>ID</key>
+			<integer>41</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{270, 299}</string>
+				<string>{270, 328}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>34</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>29</integer>
+			</dict>
+			<key>ID</key>
+			<integer>40</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{270, 83}</string>
+				<string>{270, 133.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>26</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>34</integer>
+			</dict>
+			<key>ID</key>
+			<integer>39</integer>
+			<key>OrthogonalBarAutomatic</key>
+			<true/>
+			<key>OrthogonalBarPosition</key>
+			<real>-1</real>
+			<key>Points</key>
+			<array>
+				<string>{270, 165.5}</string>
+				<string>{270, 210}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>LineType</key>
+					<integer>2</integer>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>29</integer>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{241.464, 220}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>37</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 HTML Sanitizer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{126, 220}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>36</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 HTML Form Filler}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{126, 258}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>35</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 I18N Translator}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{116, 210}, {308, 89}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>1</string>
+					<key>g</key>
+					<string>1</string>
+					<key>r</key>
+					<string>1</string>
+				</dict>
+				<key>Font</key>
+				<string>Helvetica-Bold</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>34</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/browser/trunk/markup/filters.py</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+					<key>GradientAngle</key>
+					<real>114</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>CornerRadius</key>
+					<real>5</real>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Align</key>
+				<integer>2</integer>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qr\pardirnatural
+
+\f0\i\b\fs24 \cf1 filtering}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{222.732, 134}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>11</real>
+			</dict>
+			<key>ID</key>
+			<integer>29</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/wiki/Documentation/streams.html</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 Stream}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{240.464, 42}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>28</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 XML Parser}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{126, 42}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>27</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 HTML Parser}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{116, 32}, {308, 51}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>1</string>
+					<key>g</key>
+					<string>1</string>
+					<key>r</key>
+					<string>1</string>
+				</dict>
+				<key>Font</key>
+				<string>Helvetica-Bold</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>26</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/browser/trunk/markup/input.py</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+					<key>GradientAngle</key>
+					<real>114</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>CornerRadius</key>
+					<real>5</real>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Align</key>
+				<integer>2</integer>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qr\pardirnatural
+
+\f0\i\b\fs24 \cf1 parsing}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{241.464, 338}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>25</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 XML Serializer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{126, 338}, {94.5364, 31}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>24</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs22 \cf0 HTML Serializer}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{116, 328}, {308, 89}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>1</string>
+					<key>g</key>
+					<string>1</string>
+					<key>r</key>
+					<string>1</string>
+				</dict>
+				<key>Font</key>
+				<string>Helvetica-Bold</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>23</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/browser/trunk/markup/output.py</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+					<key>GradientAngle</key>
+					<real>114</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>CornerRadius</key>
+					<real>5</real>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Align</key>
+				<integer>2</integer>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qr\pardirnatural
+
+\f0\i\b\fs24 \cf1 serialization}</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{42.7682, 100}, {125.232, 99}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Color</key>
+				<dict>
+					<key>b</key>
+					<string>1</string>
+					<key>g</key>
+					<string>1</string>
+					<key>r</key>
+					<string>1</string>
+				</dict>
+				<key>Font</key>
+				<string>Helvetica-Bold</string>
+				<key>Size</key>
+				<real>12</real>
+			</dict>
+			<key>ID</key>
+			<integer>44</integer>
+			<key>Link</key>
+			<dict>
+				<key>url</key>
+				<string>/wiki/Documentation/builder.html</string>
+			</dict>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+					<key>GradientAngle</key>
+					<real>114</real>
+					<key>GradientColor</key>
+					<dict>
+						<key>b</key>
+						<string>0.701961</string>
+						<key>g</key>
+						<string>0.701961</string>
+						<key>r</key>
+						<string>0.701961</string>
+					</dict>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>CornerRadius</key>
+					<real>5</real>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf420
+{\fonttbl\f0\fswiss\fcharset77 Helvetica-BoldOblique;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\i\b\fs24 \cf1 building}</string>
+				<key>VerticalPad</key>
+				<integer>2</integer>
+			</dict>
+			<key>TextPlacement</key>
+			<integer>0</integer>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict/>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>IsPalette</key>
+	<string>NO</string>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Ebene 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict/>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array>
+		<dict>
+			<key>ActiveLayerIndex</key>
+			<integer>0</integer>
+			<key>AutoAdjust</key>
+			<false/>
+			<key>CanvasColor</key>
+			<dict>
+				<key>w</key>
+				<string>1</string>
+			</dict>
+			<key>CanvasOrigin</key>
+			<string>{0, 0}</string>
+			<key>CanvasScale</key>
+			<real>1</real>
+			<key>ColumnAlign</key>
+			<integer>1</integer>
+			<key>ColumnSpacing</key>
+			<real>36</real>
+			<key>DisplayScale</key>
+			<string>1 cm = 1 cm</string>
+			<key>GraphicsList</key>
+			<array/>
+			<key>GridInfo</key>
+			<dict/>
+			<key>HPages</key>
+			<integer>1</integer>
+			<key>IsPalette</key>
+			<string>NO</string>
+			<key>KeepToScale</key>
+			<false/>
+			<key>Layers</key>
+			<array>
+				<dict>
+					<key>Lock</key>
+					<string>NO</string>
+					<key>Name</key>
+					<string>Ebene 1</string>
+					<key>Print</key>
+					<string>YES</string>
+					<key>View</key>
+					<string>YES</string>
+				</dict>
+			</array>
+			<key>LayoutInfo</key>
+			<dict/>
+			<key>Orientation</key>
+			<integer>2</integer>
+			<key>RowAlign</key>
+			<integer>1</integer>
+			<key>RowSpacing</key>
+			<real>36</real>
+			<key>SheetTitle</key>
+			<string>Master 1</string>
+			<key>UniqueID</key>
+			<integer>1</integer>
+			<key>VPages</key>
+			<integer>1</integer>
+		</dict>
+	</array>
+	<key>ModificationDate</key>
+	<string>2007-06-17 13:12:07 +0200</string>
+	<key>Modifier</key>
+	<string>Christopher Lenz</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>36</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>36</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{595, 842}</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>36</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>36</string>
+		</array>
+	</dict>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Arbeitsfl&#228;che 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>NO</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<false/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<string>0</string>
+		<key>DrawerOpen</key>
+		<false/>
+		<key>DrawerTab</key>
+		<string>Outline</string>
+		<key>DrawerWidth</key>
+		<real>209</real>
+		<key>FitInWindow</key>
+		<false/>
+		<key>Frame</key>
+		<string>{{64, 119}, {780, 560}}</string>
+		<key>ShowRuler</key>
+		<false/>
+		<key>ShowStatusBar</key>
+		<true/>
+		<key>VisibleRegion</key>
+		<string>{{-121, 0}, {765, 446}}</string>
+		<key>Zoom</key>
+		<string>1</string>
+	</dict>
+</dict>
+</plist>
diff --git a/lib/genshi/doc/2000ft.png b/lib/genshi/doc/2000ft.png
new file mode 100644
index 0000000000000000000000000000000000000000..b4ce041211763686822d58697d549d3a48137327
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/common/COPYING b/lib/genshi/doc/common/COPYING
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/COPYING
@@ -0,0 +1,28 @@
+Copyright (C) 2007 Edgewall Software
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+ 3. The name of the author may not be used to endorse or promote
+    products derived from this software without specific prior
+    written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/genshi/doc/common/README.txt b/lib/genshi/doc/common/README.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/README.txt
@@ -0,0 +1,7 @@
+Edgewall Documentation Utilities
+================================
+
+This repository contains distutils commands for generating offline documentation
+from reStructuredText files and Python source code. These tools are shared among
+a couple of different Edgewall projects to ensure common style and
+functionality.
diff --git a/lib/genshi/doc/common/conf/docutils.ini b/lib/genshi/doc/common/conf/docutils.ini
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/conf/docutils.ini
@@ -0,0 +1,9 @@
+[general]
+input_encoding = utf-8
+strip_comments = yes
+toc_backlinks = none
+
+[html4css1 writer]
+embed_stylesheet = no
+stylesheet = common/style/edgewall.css
+xml_declaration = no
diff --git a/lib/genshi/doc/common/conf/epydoc.ini b/lib/genshi/doc/common/conf/epydoc.ini
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/conf/epydoc.ini
@@ -0,0 +1,22 @@
+[epydoc]
+
+name: Documentation Index
+url: ../index.html
+verbosity: 1
+
+# Extraction
+docformat: restructuredtext
+parse: yes
+introspect: yes
+exclude: .*\.tests.*
+inheritance: listed
+private: no
+imports: no
+include-log: no
+
+# HTML output
+output: html
+target: doc/api/
+css: doc/common/style/epydoc.css
+frames: no
+sourcecode: no
diff --git a/lib/genshi/doc/common/doctools.py b/lib/genshi/doc/common/doctools.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/doctools.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+from distutils.cmd import Command
+import doctest
+from glob import glob
+import os
+import sys
+
+TOOLS_DIR = os.path.dirname(__file__)
+
+
+class build_doc(Command):
+    description = 'generate the documentation'
+    user_options = [
+        ('force', None,
+         "force regeneration even if no reStructuredText files have changed"),
+        ('without-apidocs', None,
+         "whether to skip the generation of API documentaton"),
+    ]
+    boolean_options = ['force', 'without-apidocs']
+
+    def initialize_options(self):
+        self.force = False
+        self.without_apidocs = False
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        from docutils.core import publish_cmdline
+        from docutils.nodes import raw
+        from docutils.parsers import rst
+        from genshi.input import HTMLParser
+        from genshi.template import TemplateLoader
+
+        docutils_conf = os.path.join(TOOLS_DIR, 'conf', 'docutils.ini')
+        epydoc_conf = os.path.join(TOOLS_DIR, 'conf', 'epydoc.ini')
+
+        try:
+            from pygments import highlight
+            from pygments.lexers import get_lexer_by_name
+            from pygments.formatters import HtmlFormatter
+
+            def code_block(name, arguments, options, content, lineno,
+                           content_offset, block_text, state, state_machine):
+                lexer = get_lexer_by_name(arguments[0])
+                html = highlight('\n'.join(content), lexer, HtmlFormatter())
+                return [raw('', html, format='html')]
+            code_block.arguments = (1, 0, 0)
+            code_block.options = {'language' : rst.directives.unchanged}
+            code_block.content = 1
+            rst.directives.register_directive('code-block', code_block)
+        except ImportError:
+            print('Pygments not installed, syntax highlighting disabled')
+
+        loader = TemplateLoader(['doc', 'doc/common'], variable_lookup='strict')
+        for source in glob('doc/*.txt'):
+            dest = os.path.splitext(source)[0] + '.html'
+            if self.force or not os.path.exists(dest) or \
+                    os.path.getmtime(dest) < os.path.getmtime(source):
+                print('building documentation file %s' % dest)
+                publish_cmdline(writer_name='html',
+                                argv=['--config=%s' % docutils_conf, source,
+                                      dest])
+                fileobj = open(dest)
+                try:
+                    html = HTMLParser(fileobj, encoding='utf-8')
+                    template = loader.load('template.html')
+                    output = template.generate(
+                        html=html,
+                        project=self.distribution
+                    ).render('html', encoding='utf-8')
+                finally:
+                    fileobj.close()
+                fileobj = open(dest, 'w')
+                try:
+                    fileobj.write(output)
+                finally:
+                    fileobj.close()
+
+        if not self.without_apidocs:
+            try:
+                from epydoc import cli
+                old_argv = sys.argv[1:]
+                sys.argv[1:] = [
+                    '--config=%s' % epydoc_conf,
+                    '--top=%s' % self.distribution.packages[0],
+                    '--no-private', # epydoc bug, not read from config
+                    '--simple-term',
+                    '--verbose'
+                ] + self.distribution.packages
+                cli.cli()
+                sys.argv[1:] = old_argv
+
+            except ImportError:
+                print('epydoc not installed, skipping API documentation.')
+
+
+class test_doc(Command):
+    description = 'test the code examples in the documentation'
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        for filename in glob('doc/*.txt'):
+            print('testing documentation file %s' % filename)
+            doctest.testfile(filename, False, optionflags=doctest.ELLIPSIS)
diff --git a/lib/genshi/doc/common/style/bkgnd_pattern.png b/lib/genshi/doc/common/style/bkgnd_pattern.png
new file mode 100644
index 0000000000000000000000000000000000000000..90e92682135d3f7213332f870f973bd06d6d57ee
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/common/style/docutils.css b/lib/genshi/doc/common/style/docutils.css
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/style/docutils.css
@@ -0,0 +1,277 @@
+/*
+:Author: David Goodger
+:Contact: goodger at users.sourceforge.net
+:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $
+:Revision: $Revision: 4224 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+dl.docutils dt {
+  font-weight: bold }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
diff --git a/lib/genshi/doc/common/style/edgewall.css b/lib/genshi/doc/common/style/edgewall.css
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/style/edgewall.css
@@ -0,0 +1,109 @@
+ at import url(docutils.css);
+ at import url(pygments.css);
+
+html, body { height: 100%; margin: 0; padding: 0; }
+body { background: #4b4d4d url(bkgnd_pattern.png); color: #000; }
+body, th, td {
+  font: normal small Verdana,Arial,'Bitstream Vera Sans',Helvetica,sans-serif;
+}
+pre, code, tt { font-size: medium; }
+h1, h2, h3, h4 {
+  border-bottom: 1px solid #ccc;
+  font-family: Arial,Verdana,'Bitstream Vera Sans',Helvetica,sans-serif;
+  font-weight: bold; letter-spacing: -0.018em;
+}
+h1 { font-size: 19px; margin: 2em 0 .5em; }
+h2 { font-size: 16px; margin: 1.5em 0 .5em; }
+h3 { color: #333; font-size: 14px; margin: 1.2em 0 .5em; }
+hr { border: none;  border-top: 1px solid #ccb; margin: 2em 0; }
+p { margin: 0 0 1em; }
+
+table { border: 1px solid #999; border-width: 0 1px 0 0;
+  border-collapse: separate; border-spacing: 0;
+}
+table thead th { background: #999; border: 1px solid #999;; color: #fff;
+  font-weight: bold;
+}
+table td { border: 1px solid #ccc; border-width: 0 0 1px 1px; padding: .3em; }
+
+:link, :visited { text-decoration: none; border-bottom: 1px dotted #bbb;
+  color: #b00;
+}
+:link:hover, :visited:hover { background-color: #eee; color: #555; }
+:link img, :visited img { border: none }
+h1 :link, h1 :visited ,h2 :link, h2 :visited, h3 :link, h3 :visited,
+h4 :link, h4 :visited, h5 :link, h5 :visited, h6 :link, h6 :visited {
+  color: #000;
+}
+
+#navigation { background: #b00; color: #fff; font-size: 90%; margin: 0 -20px;
+  padding: .2em .5em; text-align: right;
+}
+#navigation :link, #navigation :visited { border: none; color: #fff; }
+#navigation :link:hover, #navigation :visited:hover { background: #fff;
+  color: #b00;
+}
+#navigation span.projinfo { float: left; }
+#footer { border-top: 1px solid #d7d7d7; color: #666; font-size: 90%;
+  margin: 8em -20px 0; padding: .5em 0 2em; text-align: center;
+}
+#footer :link, #footer :visited { color: #666; }
+
+div.document { background: #fff url(shadow.gif) right top repeat-y;
+  border-left: 1px solid #000; margin: 0 auto 0 40px; min-height: 100%;
+  padding: 0 180px 1px 20px; width: 700px;
+}
+
+div.contents { font-size: 90%; position: absolute; position: fixed;
+  margin-left: 81px; left: 60em; top: 30px; right: 0; bottom: 0;
+  overflow: auto; overflow-x: hidden;
+}
+div.contents .topic-title { display: none; }
+div.contents ul { list-style: none; padding-left: 0; }
+div.contents .auto-toc :link, div.contents .auto-toc :visited {
+  color: #e9e9e9; border: none; display: block; font-weight: bold;
+  padding: 1px 5px 2px 10px;
+}
+div.contents .auto-toc :link:hover, div.contents .auto-toc :visited:hover {
+  background: #000; color: #fff;
+}
+div.contents .auto-toc .auto-toc :link,
+div.contents .auto-toc .auto-toc :visited { color: #c6c6c6;
+  font-weight: normal;
+}
+
+h1.title, div.document#preface h1 { border: none; color: #666;
+  font-size: x-large; margin: 0 -20px 1em; padding: 2em 20px 0;
+}
+h1.title { background: url(vertbars.png) repeat-x; }
+div.document#preface h1.title { text-indent: -4000px; }
+div.document#preface h1 { text-align: center; }
+pre.literal-block, div.highlight pre { background: #f4f4f4;
+  border: 1px solid #e6e6e6; color: #000; margin: 1em 1em; padding: .25em;
+  overflow: auto;
+}
+
+table.field-list { border-collapse: collapse; }
+table.field-list th.field-name { color: #333; font-weight: normal;
+  text-align: right;
+}
+table.field-list td { border-width: 1px; }
+
+div.admonition, div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+  border: none; color: #333; font-style: italic; margin: 1em 2em;
+}
+div.attention p.admonition-title, div.caution p.admonition-title, div.danger
+p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: #b00;
+}
+p.admonition-title { margin-bottom: 0; text-transform: uppercase; }
+tt.docutils { background-color: transparent; }
+span.pre { white-space: normal; }
+
+div.section { margin-left: 1.5em; }
+div.section h1 { margin-left: -1em; }
+div.section div.section { margin-left: 0; }
+div.section div.section { margin-bottom: 4em; } 
+div.section div.section div.section { margin-bottom: 0; }
diff --git a/lib/genshi/doc/common/style/epydoc.css b/lib/genshi/doc/common/style/epydoc.css
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/style/epydoc.css
@@ -0,0 +1,136 @@
+html { background: #4b4d4d url(../style/bkgnd_pattern.png); margin: 0;
+  padding: 1em 1em 3em;
+}
+body { background: #fff url(../style/vertbars.png) repeat-x;
+  border: 1px solid #000; color: #000; margin: 1em 0; padding: 0 1em 1em;
+}
+body, th, td {
+  font: normal small Verdana,Arial,'Bitstream Vera Sans',Helvetica,sans-serif;
+}
+h1, h2, h3, h4 {
+  font-family: Arial,Verdana,'Bitstream Vera Sans',Helvetica,sans-serif;
+  font-weight: bold; letter-spacing: -0.018em;
+}
+h1 { font-size: 19px; margin: 2em 0 .5em; }
+h2 { font-size: 16px; margin: 1.5em 0 .5em; }
+h3 { font-size: 14px; margin: 1.2em 0 .5em; }
+hr { border: none;  border-top: 1px solid #ccb; margin: 2em 0; }
+p { margin: 0 0 1em; }
+:link, :visited { text-decoration: none; border-bottom: 1px dotted #bbb;
+  color: #b00;
+}
+:link:hover, :visited:hover { background-color: #eee; color: #555; }
+
+table { border: none; border-collapse: collapse; }
+
+table.navbar { background: #000; color: #fff; margin: 2em 0 .33em; }
+table.navbar th { border: 1px solid #000; font-weight: bold; padding: 1px; }
+table.navbar :link, table.navbar :visited { border: none; color: #fff; }
+table.navbar :link:hover, table.navbar :visited:hover { background: none;
+  text-decoration: underline overline;
+}
+table.navbar th.navbar-select { background: #fff; color: #000; }
+span.breadcrumbs { color: #666; font-size: 95%; }
+h1.epydoc { border: none; color: #666;
+  font-size: x-large; margin: 1em 0 0; padding: 0;
+}
+pre.base-tree { color: #666; margin: 0; padding: 0; }
+pre.base-tree :link, pre.base-tree :visited { border: none; }
+pre.py-doctest, pre.variable, pre.rst-literal-block { background: #eee;
+  border: 1px solid #e6e6e6; color: #000; margin: 1em; padding: .25em;
+  overflow: auto;
+}
+pre.variable { margin: 0; }
+
+/* Summary tables */
+
+table.summary { margin: .5em 0; }
+table.summary tr.table-header { background: #f7f7f0; }
+table.summary td.table-header { color: #666; font-weight: bold; }
+table.summary th.group-header { background: #f7f7f0; color: #666;
+  font-size: 90%; font-weight: bold; text-align: left;
+}
+table.summary th, table.summary td { border: 1px solid #d7d7d7; }
+table.summary th th, table.summary td td { border: none; }
+table.summary td.summary table td { color: #666; font-size: 90%; }
+table.summary td.summary table br { display: none; }
+table.summary td.summary span.summary-type { font-family: monospace; 
+  font-size: 90%;
+}
+table.summary td.summary span.summary-type code { font-size: 110%; }
+p.indent-wrapped-lines { color: #999; font-size: 85%; margin: 0;
+  padding: 0 0 0 7em; text-indent: -7em;
+}
+p.indent-wrapped-lines code { color: #999; font-size: 115%; }
+p.indent-wrapped-lines :link, p.indent-wrapped-lines :visited { border: none; }
+.summary-sig { display: block; font-family: monospace; font-size: 120%;
+  margin-bottom: .5em;
+}
+.summary-sig-name { font-weight: bold; }
+.summary-sig-arg { color: #333; }
+.summary-sig :link, .summary-sig :visited { border: none; }
+.summary-name { font-family: monospace; font-weight: bold; }
+
+/* Details tables */
+
+table.details { margin: 2em 0 0; }
+div table.details { margin-top: 0; }
+table.details tr.table-header { background: transparent; }
+table.details td.table-header { border-bottom: 1px solid #ccc; padding: 2em 0 0; }
+table.details span.table-header {
+  font: bold 140% Arial,Verdana,'Bitstream Vera Sans',Helvetica,sans-serif;
+  letter-spacing: -0.018em;
+}
+table.details th, table.details td { border: none; }
+table.details th th, table.details td td { border: none; }
+table.details td { padding-left: 2em; }
+table.details td td { padding-left: 0; }
+table.details h3.epydoc { margin-left: -2em; }
+table.details h3.epydoc .sig { color: #999; font-family: monospace; }
+table.details h3.epydoc .sig-name { color: #000; }
+table.details h3.epydoc .sig-arg { color: #666; }
+table.details h3.epydoc .sig-default { font-size: 95%; font-weight: normal; }
+table.details h3.epydoc .sig-default code { font-weight: normal; }
+table.details h3.epydoc .fname { color: #999; font-size: 90%;
+  font-style: italic; font-weight: normal; line-height: 1.6em;
+}
+
+dl dt { color: #666; margin-top: 1em; }
+dl dd { margin: 0; padding-left: 2em; }
+dl.fields { margin: 1em 0; padding: 0; }
+dl.fields dt { color: #666; margin-top: 1em; }
+dl.fields dd ul { margin: 0; padding: 0; }
+div.fields { font-size: 90%; margin: 0 0 2em 2em; }
+div.fields p { margin-bottom: 0.5em; }
+
+table td.footer { color: #999; font-size: 85%; margin-top: 3em;
+  padding: 0 3em 1em; position: absolute; width: 80%; }
+table td.footer :link, table td.footer :visited { border: none; color: #999; }
+table td.footer :link:hover, table td.footer :visited:hover {
+  background: transparent; text-decoration: underline;
+}
+
+/* Syntax highlighting */
+
+.py-prompt, .py-more, .variable-ellipsis, .variable-op { color: #999; }
+.variable-group { color: #666; font-weight: bold; }
+.py-string, .variable-string, .variable-quote { color: #093; }
+.py-comment { color: #06f; font-style: italic; }
+.py-keyword { color: #00f; }
+.py-output { background: #f6f6f0; color: #666; font-weight: bold; }
+
+/* Index */
+
+table.link-index { background: #f6f6f0; border: none; margin-top: 1em; }
+table.link-index td.link-index { border: none; font-family: monospace;
+  font-weight: bold; padding: .5em 1em;
+}
+table.link-index td table, table.link-index td td { border: none; }
+table.link-index .index-where { color: #999;
+  font-family: Verdana,Arial,'Bitstream Vera Sans',Helvetica,sans-serif;
+  font-size: 90%; font-weight: normal; line-height: 1.6em;
+}
+table.link-index .index-where :link, table.link-index .index-where :visited {
+  border: none; color: #666;
+}
+h2.epydoc { color: #999; font-size: 200%; line-height: 10px; }
diff --git a/lib/genshi/doc/common/style/pygments.css b/lib/genshi/doc/common/style/pygments.css
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/style/pygments.css
@@ -0,0 +1,57 @@
+div.highlight { background: #ffffff; }
+div.highlight .c { color: #999988; font-style: italic }
+div.highlight .err { color: #a61717; background-color: #e3d2d2 }
+div.highlight .k { font-weight: bold }
+div.highlight .o { font-weight: bold }
+div.highlight .cm { color: #999988; font-style: italic }
+div.highlight .cp { color: #999999; font-weight: bold }
+div.highlight .c1 { color: #999988; font-style: italic }
+div.highlight .cs { color: #999999; font-weight: bold; font-style: italic }
+div.highlight .gd { color: #000000; background-color: #ffdddd }
+div.highlight .ge { font-style: italic }
+div.highlight .gr { color: #aa0000 }
+div.highlight .gh { color: #999999 }
+div.highlight .gi { color: #000000; background-color: #ddffdd }
+div.highlight .go { color: #888888 }
+div.highlight .gp { color: #555555 }
+div.highlight .gs { font-weight: bold }
+div.highlight .gu { color: #aaaaaa }
+div.highlight .gt { color: #aa0000 }
+div.highlight .kc { font-weight: bold }
+div.highlight .kd { font-weight: bold }
+div.highlight .kp { font-weight: bold }
+div.highlight .kr { font-weight: bold }
+div.highlight .kt { color: #445588; font-weight: bold }
+div.highlight .m { color: #009999 }
+div.highlight .s { color: #bb8844 }
+div.highlight .na { color: #008080 }
+div.highlight .nb { color: #999999 }
+div.highlight .nc { color: #445588; font-weight: bold }
+div.highlight .no { color: #008080 }
+div.highlight .ni { color: #800080 }
+div.highlight .ne { color: #990000; font-weight: bold }
+div.highlight .nf { color: #990000; font-weight: bold }
+div.highlight .nn { color: #555555 }
+div.highlight .nt { color: #000080 }
+div.highlight .nv { color: #008080 }
+div.highlight .ow { font-weight: bold }
+div.highlight .mf { color: #009999 }
+div.highlight .mh { color: #009999 }
+div.highlight .mi { color: #009999 }
+div.highlight .mo { color: #009999 }
+div.highlight .sb { color: #bb8844 }
+div.highlight .sc { color: #bb8844 }
+div.highlight .sd { color: #bb8844 }
+div.highlight .s2 { color: #bb8844 }
+div.highlight .se { color: #bb8844 }
+div.highlight .sh { color: #bb8844 }
+div.highlight .si { color: #bb8844 }
+div.highlight .sx { color: #bb8844 }
+div.highlight .sr { color: #808000 }
+div.highlight .s1 { color: #bb8844 }
+div.highlight .ss { color: #bb8844 }
+div.highlight .bp { color: #999999 }
+div.highlight .vc { color: #008080 }
+div.highlight .vg { color: #008080 }
+div.highlight .vi { color: #008080 }
+div.highlight .il { color: #009999 }
diff --git a/lib/genshi/doc/common/style/shadow.gif b/lib/genshi/doc/common/style/shadow.gif
new file mode 100644
index 0000000000000000000000000000000000000000..98d093f87be7d122f6baf4ab06aff856a8452ae1
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/common/style/vertbars.png b/lib/genshi/doc/common/style/vertbars.png
new file mode 100644
index 0000000000000000000000000000000000000000..42ae3f86d7f1513fd585ad02959afbb37ad476cb
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/common/template.html b/lib/genshi/doc/common/template.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/common/template.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html xmlns:py="http://genshi.edgewall.org/" py:strip="">
+
+  <title py:match="head/title">${project.get_name()}: ${select('text()')}</title>
+
+  <!--! Add navigation and footer around content -->
+  <div py:match="div[@class='document']" py:attrs="select('@*')">
+    <div id="navigation">
+      <span class="projinfo">${project.get_name()} ${project.get_version()}</span>
+      <a href="index.html">Documentation Index</a>
+    </div>
+    ${select('*|text()')}
+    <div id="footer">
+      Visit the ${project.get_name()} open source project at
+      <a href="${project.get_url()}">${project.get_url()}</a>
+    </div>
+  </div>
+
+  $html
+
+</html>
diff --git a/lib/genshi/doc/filters.txt b/lib/genshi/doc/filters.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/filters.txt
@@ -0,0 +1,243 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+==============
+Stream Filters
+==============
+
+`Markup Streams`_ showed how to write filters and how they are applied to
+markup streams. This page describes the features of the various filters that
+come with Genshi itself.
+
+.. _`Markup Streams`: streams.html
+
+.. contents:: Contents
+   :depth: 1
+.. sectnum::
+
+
+HTML Form Filler
+================
+
+The filter ``genshi.filters.html.HTMLFormFiller`` can automatically populate an
+HTML form from values provided as a simple dictionary. When using this filter,
+you can basically omit any ``value``, ``selected``, or ``checked`` attributes
+from form controls in your templates, and let the filter do all that work for
+you.
+
+``HTMLFormFiller`` takes a dictionary of data to populate the form with, where
+the keys should match the names of form elements, and the values determine the
+values of those controls. For example:
+
+.. code-block:: pycon
+
+  >>> from genshi.filters import HTMLFormFiller
+  >>> from genshi.template import MarkupTemplate
+  
+  >>> template = MarkupTemplate("""<form>
+  ...   <p>
+  ...     <label>User name:
+  ...       <input type="text" name="username" />
+  ...     </label><br />
+  ...     <label>Password:
+  ...       <input type="password" name="password" />
+  ...     </label><br />
+  ...     <label>
+  ...       <input type="checkbox" name="remember" /> Remember me
+  ...     </label>
+  ...   </p>
+  ... </form>""")
+  >>> filler = HTMLFormFiller(data=dict(username='john', remember=True))
+  >>> print(template.generate() | filler)
+  <form>
+    <p>
+      <label>User name:
+        <input type="text" name="username" value="john"/>
+      </label><br/>
+      <label>Password:
+        <input type="password" name="password"/>
+      </label><br/>
+      <label>
+        <input type="checkbox" name="remember" checked="checked"/> Remember me
+      </label>
+    </p>
+  </form>
+
+.. note:: This processing is done without in any way reparsing the template
+          output. As any stream filter it operates after the template output is
+          generated but *before* that output is actually serialized.
+
+The filter will of course also handle radio buttons as well as ``<select>`` and
+``<textarea>`` elements. For radio buttons to be marked as checked, the value in
+the data dictionary needs to match the ``value`` attribute of the ``<input>``
+element, or evaluate to a truth value if the element has no such attribute. For
+options in a ``<select>`` box to be marked as selected, the value in the data
+dictionary needs to match the ``value`` attribute of the ``<option>`` element,
+or the text content of the option if it has no ``value`` attribute. Password and
+file input fields are not populated, as most browsers would ignore that anyway
+for security reasons.
+
+You'll want to make sure that the values in the data dictionary have already
+been converted to strings. While the filter may be able to deal with non-string
+data in some cases (such as check boxes), in most cases it will either not
+attempt any conversion or not produce the desired results.
+
+You can restrict the form filler to operate only on a specific ``<form>`` by
+passing either the ``id`` or the ``name`` keyword argument to the initializer.
+If either of those is specified, the filter will only apply to form tags with
+an attribute matching the specified value.
+
+
+HTML Sanitizer
+==============
+
+The filter ``genshi.filters.html.HTMLSanitizer`` filter can be used to clean up
+user-submitted HTML markup, removing potentially dangerous constructs that could
+be used for various kinds of abuse, such as cross-site scripting (XSS) attacks:
+
+.. code-block:: pycon
+
+  >>> from genshi.filters import HTMLSanitizer
+  >>> from genshi.input import HTML
+  
+  >>> html = HTML("""<div>
+  ...   <p>Innocent looking text.</p>
+  ...   <script>alert("Danger: " + document.cookie)</script>
+  ... </div>""")
+  >>> sanitize = HTMLSanitizer()
+  >>> print(html | sanitize)
+  <div>
+    <p>Innocent looking text.</p>
+  </div>
+
+In this example, the ``<script>`` tag was removed from the output.
+
+You can determine which tags and attributes should be allowed by initializing
+the filter with corresponding sets. See the API documentation for more
+information.
+
+Inline ``style`` attributes are forbidden by default. If you allow them, the
+filter will still perform sanitization on the contents any encountered inline
+styles: the proprietary ``expression()`` function (supported only by Internet
+Explorer) is removed, and any property using an ``url()`` which a potentially
+dangerous URL scheme (such as ``javascript:``) are also stripped out:
+
+.. code-block:: pycon
+
+  >>> from genshi.filters import HTMLSanitizer
+  >>> from genshi.input import HTML
+  
+  >>> html = HTML("""<div>
+  ...   <br style="background: url(javascript:alert(document.cookie); color: #000" />
+  ... </div>""")
+  >>> sanitize = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS | set(['style']))
+  >>> print(html | sanitize)
+  <div>
+    <br style="color: #000"/>
+  </div>
+
+.. warning:: You should probably not rely on the ``style`` filtering, as
+             sanitizing mixed HTML, CSS, and Javascript is very complicated and
+             suspect to various browser bugs. If you can somehow get away with
+             not allowing inline styles in user-submitted content, that would
+             definitely be the safer route to follow.
+
+
+Transformer
+===========
+
+The filter ``genshi.filters.transform.Transformer`` provides a convenient way to
+transform or otherwise work with markup event streams. It allows you to specify
+which parts of the stream you're interested in with XPath expressions, and then
+attach a variety of transformations to the parts that match:
+
+.. code-block:: pycon
+
+  >>> from genshi.builder import tag
+  >>> from genshi.core import TEXT
+  >>> from genshi.filters import Transformer
+  >>> from genshi.input import HTML
+  
+  >>> html = HTML('''<html>
+  ...   <head><title>Some Title</title></head>
+  ...   <body>
+  ...     Some <em>body</em> text.
+  ...   </body>
+  ... </html>''')
+  
+  >>> print(html | Transformer('body/em').map(unicode.upper, TEXT)
+  ...                                    .unwrap().wrap(tag.u).end()
+  ...                                    .select('body/u')
+  ...                                    .prepend('underlined '))
+  <html>
+    <head><title>Some Title</title></head>
+    <body>
+      Some <u>underlined BODY</u> text.
+    </body>
+  </html>
+
+This example sets up a transformation that:
+
+ 1. matches any `<em>` element anywhere in the body,
+ 2. uppercases any text nodes in the element,
+ 3. strips off the `<em>` start and close tags,
+ 4. wraps the content in a `<u>` tag, and
+ 5. inserts the text `underlined` inside the `<u>` tag.
+
+A number of commonly useful transformations are available for this filter.
+Please consult the API documentation a complete list.
+
+In addition, you can also perform custom transformations. For example, the
+following defines a transformation that changes the name of a tag:
+
+.. code-block:: pycon
+
+  >>> from genshi import QName
+  >>> from genshi.filters.transform import ENTER, EXIT
+  
+  >>> class RenameTransformation(object):
+  ...    def __init__(self, name):
+  ...        self.name = QName(name)
+  ...    def __call__(self, stream):
+  ...        for mark, (kind, data, pos) in stream:
+  ...            if mark is ENTER:
+  ...                data = self.name, data[1]
+  ...            elif mark is EXIT:
+  ...                data = self.name
+  ...            yield mark, (kind, data, pos)
+
+A transformation can be any callable object that accepts an augmented event
+stream. In this case we define a class, so that we can initialize it with the
+tag name.
+
+Custom transformations can be applied using the `apply()` method of a
+transformer instance:
+
+.. code-block:: pycon
+
+  >>> xform = Transformer('body//em').map(unicode.upper, TEXT) \
+  >>> xform = xform.apply(RenameTransformation('u'))
+  >>> print(html | xform)
+  <html>
+    <head><title>Some Title</title></head>
+    <body>
+      Some <u>BODY</u> text.
+    </body>
+  </html>
+
+.. note:: The transformation filter was added in Genshi 0.5.
+
+
+Translator
+==========
+
+The ``genshi.filters.i18n.Translator`` filter implements basic support for
+internationalizing and localizing templates. When used as a filter, it
+translates a configurable set of text nodes and attribute values using a
+``gettext``-style translation function.
+
+The ``Translator`` class also defines the ``extract`` class method, which can
+be used to extract localizable messages from a template.
+
+Please refer to the API documentation for more information on this filter.
+
+.. note:: The translation filter was added in Genshi 0.4.
diff --git a/lib/genshi/doc/i18n.txt b/lib/genshi/doc/i18n.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/i18n.txt
@@ -0,0 +1,507 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=====================================
+Internationalization and Localization
+=====================================
+
+Genshi provides comprehensive supporting infrastructure for internationalizing
+and localizing templates. That includes functionality for extracting
+localizable strings from templates, as well as a template filter and special
+directives that can apply translations to templates as they get rendered.
+
+This support is based on `gettext`_ message catalogs and the `gettext Python 
+module`_. The extraction process can be used from the API level, or through
+the front-ends implemented by the `Babel`_ project, for which Genshi provides
+a plugin.
+
+.. _`gettext`: http://www.gnu.org/software/gettext/
+.. _`gettext python module`: http://docs.python.org/lib/module-gettext.html
+.. _`babel`: http://babel.edgewall.org/
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+
+Basics
+======
+
+The simplest way to internationalize and translate templates would be to wrap
+all localizable strings in a ``gettext()`` function call (which is often
+aliased to ``_()`` for brevity). In that case, no extra template filter is
+required.
+
+.. code-block:: genshi
+
+  <p>${_("Hello, world!")}</p>
+
+However, this approach results in significant &#8220;character noise&#8221; in templates,
+making them harder to read and preview.
+
+The ``genshi.filters.Translator`` filter allows you to get rid of the 
+explicit `gettext`_ function calls, so you can (often) just continue to write:
+
+.. code-block:: genshi
+
+  <p>Hello, world!</p>
+
+This text will still be extracted and translated as if you had wrapped it in a
+``_()`` call.
+
+.. note:: For parameterized or pluralizable messages, you need to use the
+          special `template directives`_ described below, or use the
+          corresponding ``gettext`` function in embedded Python expressions.
+
+You can control which tags should be ignored by this process; for example, it
+doesn't really make sense to translate the content of the HTML 
+``<script></script>`` element. Both ``<script>`` and ``<style>`` are excluded
+by default.
+
+Attribute values can also be automatically translated. The default is to 
+consider the attributes ``abbr``, ``alt``, ``label``, ``prompt``, ``standby``,
+``summary``, and ``title``, which is a list that makes sense for HTML
+documents.  Of course, you can tell the translator to use a different set of
+attribute names, or none at all.
+
+----------------
+Language Tagging
+----------------
+
+You can control automatic translation in your templates using the ``xml:lang``
+attribute. If the value of that attribute is a literal string, the contents and
+attributes of the element will be ignored:
+
+.. code-block:: genshi
+
+  <p xml:lang="en">Hello, world!</p>
+
+On the other hand, if the value of the ``xml:lang`` attribute contains a Python
+expression, the element contents and attributes are still considered for 
+automatic translation:
+
+.. code-block:: genshi
+
+  <html xml:lang="$locale">
+    ...
+  </html>
+
+
+.. _`template directives`:
+
+Template Directives
+===================
+
+Sometimes localizable strings in templates may contain dynamic parameters, or
+they may depend on the numeric value of some variable to choose a proper
+plural form. Sometimes the strings contain embedded markup, such as tags for
+emphasis or hyperlinks, and you don't want to rely on the people doing the
+translations to know the syntax and escaping rules of HTML and XML.
+
+In those cases the simple text extraction and translation process described
+above is not sufficient. You could just use ``gettext`` API functions in
+embedded Python expressions for parameters and pluralization, but that does
+not help when messages contain embedded markup. Genshi provides special
+template directives for internationalization that attempt to provide a
+comprehensive solution for this problem space.
+
+To enable these directives, you'll need to register them with the templates
+they are used in. You can do this by adding them manually via the
+``Template.add_directives(namespace, factory)`` (where ``namespace`` would be
+&#8220;http://genshi.edgewall.org/i18n&#8221; and ``factory`` would be an instance of the
+``Translator`` class). Or you can just call the ``Translator.setup(template)``
+class method, which both registers the directives and adds the translation
+filter.
+
+After the directives have been registered with the template engine on the
+Python side of your application, you need to declare the corresponding
+directive namespace in all markup templates that use them. For example:
+
+.. code-block:: genshi
+
+  <html xmlns:py="http://genshi.edgewall.org/"
+        xmlns:i18n="http://genshi.edgewall.org/i18n">
+    &#8230;
+  </html>
+
+These directives only make sense in the context of `markup templates`_. For
+`text templates`_, you can just use the corresponding ``gettext`` API calls as needed.
+
+.. note:: The internationalization directives are still somewhat experimental
+          and have some known issues. However, the attribute language they
+          implement should be stable and is not subject to change
+          substantially in future versions.
+
+.. _`markup templates`: xml-templates.html
+.. _`text templates`: text-templates.html
+
+--------
+Messages
+--------
+
+``i18n:msg``
+------------
+
+This is the basic directive for defining localizable text passages that
+contain parameters and/or markup.
+
+For example, consider the following template snippet:
+
+.. code-block:: genshi
+
+  <p>
+    Please visit <a href="${site.url}">${site.name}</a> for help.
+  </p>
+
+Without further annotation, the translation filter would treat this sentence
+as two separate messages (&#8220;Please visit&#8221; and &#8220;for help&#8221;), and the translator
+would have no control over the position of the link in the sentence.
+
+However, when you use the Genshi internationalization directives, you simply
+add an ``i18n:msg`` attribute to the enclosing ``<p>`` element:
+
+.. code-block:: genshi
+
+  <p i18n:msg="name">
+    Please visit <a href="${site.url}">${site.name}</a> for help.
+  </p>
+
+Genshi is then able to identify the text in the ``<p>`` element as a single
+message for translation purposes. You'll see the following string in your
+message catalog::
+
+  Please visit [1:%(name)s] for help.
+
+The `<a>` element with its attribute has been replaced by a part in square
+brackets, which does not include the tag name or the attributes of the element.
+
+The value of the ``i18n:msg`` attribute is a comma-separated list of parameter
+names, which serve as simplified aliases for the actual Python expressions the
+message contains. The order of the paramer names in the list must correspond
+to the order of the expressions in the text. In this example, there is only
+one parameter: its alias for translation is &#8220;name&#8221;, while the corresponding
+expression is ``${site.name}``.
+
+The translator now has complete control over the structure of the sentence. He
+or she certainly does need to make sure that any bracketed parts are not
+removed, and that the ``name`` parameter is preserved correctly. But those are
+things that can be easily checked by validating the message catalogs. The
+important thing is that the translator can change the sentence structure, and
+has no way to break the application by forgetting to close a tag, for example.
+
+So if the German translator of this snippet decided to translate it to::
+
+  Um Hilfe zu erhalten, besuchen Sie bitte [1:%(name)s]
+
+The resulting output might be:
+
+.. code-block:: xml
+
+  <p>
+    Um Hilfe zu erhalten, besuchen Sie bitte
+    <a href="http://example.com/">Example</a>
+  </p>
+
+Messages may contain multiple tags, and they may also be nested. For example:
+
+.. code-block:: genshi
+
+  <p i18n:msg="name">
+    <i>Please</i> visit <b>the site <a href="${site.url}">${site.name}</a></b>
+    for help.
+  </p>
+
+This would result in the following message ID::
+
+  [1:Please] visit [2:the site [3:%(name)s]] for help.
+
+Again, the translator has full control over the structure of the sentence. So
+the German translation could actually look like this::
+
+  Um Hilfe zu erhalten besuchen Sie [1:bitte]
+  [3:%(name)s], [2:das ist eine Web-Site]
+
+Which Genshi would recompose into the following outout:
+
+.. code-block:: xml
+
+  <p>
+    Um Hilfe zu erhalten besuchen Sie <i>bitte</i>
+    <a href="http://example.com/">Example</a>, <b>das ist eine Web-Site</b>
+  </p>
+
+Note how the translation has changed the order and even the nesting of the
+tags.
+
+.. warning:: Please note that ``i18n:msg`` directives do not support other
+             nested directives. Directives commonly change the structure of
+             the generated markup dynamically, which often would result in the
+             structure of the text changing, thus making translation as a
+             single message ineffective.
+
+``i18n:choose``, ``i18n:singular``, ``i18n:plural``
+---------------------------------------------------
+
+Translatable strings that vary based on some number of objects, such as &#8220;You
+have 1 new message&#8221; or &#8220;You have 3 new messages&#8221;, present their own challenge,
+in particular when you consider that different languages have different rules
+for pluralization. For example, while English and most western languages have
+two plural forms (one for ``n=1`` and an other for ``n<>1``), Welsh has five
+different plural forms, while Hungarian only has one.
+
+The ``gettext`` framework has long supported this via the ``ngettext()``
+family of functions. You specify two default messages, one singular and one
+plural, and the number of items. The translations however may contain any
+number of plural forms for the message, depending on how many are commonly
+used in the language. ``ngettext`` will choose the correct plural form of the
+translated message based on the specified number of items.
+
+Genshi provides a variant of the ``i18n:msg`` directive described above that
+allows choosing the proper plural form based on the numeric value of a given
+variable. The pluralization support is implemented in a set of three
+directives that must be used together: ``i18n:choose``, ``i18n:singular``, and
+``i18n:plural``.
+
+The ``i18n:choose`` directive is used to set up the context of the message: it
+simply wraps the singular and plural variants.
+
+The value of this directive is split into two parts: the first is the
+*numeral*, a Python expression that evaluates to a number to determine which
+plural form should be chosen. The second part, separated by a semicolon, lists
+the parameter names. This part is equivalent to the value of the ``i18n:msg``
+directive.
+
+For example:
+
+.. code-block:: genshi
+
+  <p i18n:choose="len(messages); num">
+    <i18n:singular>You have <b>${len(messages)}</b> new message.</i18n:singular>
+    <i18n:plural>You have <b>${len(messages)}</b> new messages.</i18n:plural>
+  </p>
+
+All three directives can be used either as elements or attribute. So the above
+example could also be written as follows:
+
+.. code-block:: genshi
+
+  <i18n:choose numeral="len(messages)" params="num">
+    <p i18n:singular="">You have <b>${len(messages)}</b> new message.</p>
+    <p i18n:plural="">You have <b>${len(messages)}</b> new messages.</p>
+  </i18n:choose>
+
+When used as an element, the two parts of the ``i18n:choose`` value are split
+into two different attributes: ``numeral`` and ``params``. The
+``i18n:singular`` and ``i18n:plural`` directives do not require or support any
+value (or any extra attributes).
+
+--------------------
+Comments and Domains
+--------------------
+
+``i18n:comment``
+----------------
+
+The ``i18n:comment`` directive can be used to supply a comment for the
+translator. For example, if a template snippet is not easily understood
+outside of its context, you can add a translator comment to help the
+translator understand in what context the message will be used:
+
+.. code-block:: genshi
+
+  <p i18n:msg="name" i18n:comment="Link to the relevant support site">
+    Please visit <a href="${site.url}">${site.name}</a> for help.
+  </p>
+
+This comment will be extracted together with the message itself, and will
+commonly be placed along the message in the message catalog, so that it is
+easily visible to the person doing the translation.
+
+This directive has no impact on how the template is rendered, and is ignored
+outside of the extraction process.
+
+``i18n:domain``
+---------------
+
+In larger projects, message catalogs are commonly split up into different
+*domains*. For example, you might have a core application domain, and then
+separate domains for extensions or libraries.
+
+Genshi provides a directive called ``i18n:domain`` that lets you choose the
+translation domain for a particular scope. For example:
+
+.. code-block:: genshi
+
+  <div i18n:domain="examples">
+    <p>Hello, world!</p>
+  </div>
+
+
+Extraction
+==========
+
+The ``Translator`` class provides a class method called ``extract``, which is
+a generator yielding all localizable strings found in a template or markup 
+stream. This includes both literal strings in text nodes and attribute values,
+as well as strings in ``gettext()`` calls in embedded Python code. See the API
+documentation for details on how to use this method directly.
+
+-----------------
+Babel Integration
+-----------------
+
+This functionality is integrated with the message extraction framework provided
+by the `Babel`_ project. Babel provides a command-line interface as well as 
+commands that can be used from ``setup.py`` scripts using `Setuptools`_ or 
+`Distutils`_.
+
+.. _`setuptools`: http://peak.telecommunity.com/DevCenter/setuptools
+.. _`distutils`: http://docs.python.org/dist/dist.html
+
+The first thing you need to do to make Babel extract messages from Genshi 
+templates is to let Babel know which files are Genshi templates. This is done
+using a &#8220;mapping configuration&#8221;, which can be stored in a configuration file,
+or specified directly in your ``setup.py``.
+
+In a configuration file, the mapping may look like this:
+
+.. code-block:: ini
+
+  # Python souce
+  [python:**.py]
+
+  # Genshi templates
+  [genshi:**/templates/**.html]
+  include_attrs = title
+
+  [genshi:**/templates/**.txt]
+  template_class = genshi.template.TextTemplate
+  encoding = latin-1
+
+Please consult the Babel documentation for details on configuration.
+
+If all goes well, running the extraction with Babel should create a POT file
+containing the strings from your Genshi templates and your Python source files.
+
+
+---------------------
+Configuration Options
+---------------------
+
+The Genshi extraction plugin for Babel supports the following options:
+
+``template_class``
+------------------
+The concrete ``Template`` class that the file should be loaded with. Specify
+the package/module name and the class name, separated by a colon.
+
+The default is to use ``genshi.template:MarkupTemplate``, and you'll want to
+set it to ``genshi.template:TextTemplate`` for `text templates`_.
+
+.. _`text templates`: text-templates.html
+
+``encoding``
+------------
+The encoding of the template file. This is only used for text templates. The
+default is to assume &#8220;utf-8&#8221;.
+
+``include_attrs``
+-----------------
+Comma-separated list of attribute names that should be considered to have 
+localizable values. Only used for markup templates.
+
+``ignore_tags``
+---------------
+Comma-separated list of tag names that should be ignored. Only used for markup 
+templates.
+
+``extract_text``
+----------------
+Whether text outside explicit ``gettext`` function calls should be extracted.
+By default, any text nodes not inside ignored tags, and values of attribute in
+the ``include_attrs`` list are extracted. If this option is disabled, only 
+strings in ``gettext`` function calls are extracted.
+
+.. note:: If you disable this option, and do not make use of the
+          internationalization directives, it's not necessary to add the
+          translation filter as described above. You only need to make sure
+          that the template has access to the ``gettext`` functions it uses.
+
+
+Translation
+===========
+
+If you have prepared MO files for use with Genshi using the appropriate tools,
+you can access the message catalogs with the `gettext Python module`_. You'll
+probably want to create a ``gettext.GNUTranslations`` instance, and make the
+translation functions it provides available to your templates by putting them
+in the template context.
+
+The ``Translator`` filter needs to be added to the filters of the template
+(applying it as a stream filter will likely not have the desired effect).
+Furthermore it needs to be the first filter in the list, including the internal
+filters that Genshi adds itself:
+
+.. code-block:: python
+
+  from genshi.filters import Translator
+  from genshi.template import MarkupTemplate
+  
+  template = MarkupTemplate("...")
+  template.filters.insert(0, Translator(translations.ugettext))
+
+The ``Translator`` class also provides the convenience method ``setup()``,
+which will both add the filter and register the i18n directives:
+
+.. code-block:: python
+
+  from genshi.filters import Translator
+  from genshi.template import MarkupTemplate
+  
+  template = MarkupTemplate("...")
+  translator = Translator(translations.ugettext)
+  translator.setup(template)
+
+.. warning:: If you're using ``TemplateLoader``, you should specify a
+            `callback function`_ in which you add the filter. That ensures
+            that the filter is not added everytime the template is rendered,
+            thereby being applied multiple times.
+
+.. _`callback function`: loader.html#callback-interface
+
+
+Related Considerations
+======================
+
+If you intend to produce an application that is fully prepared for an 
+international audience, there are a couple of other things to keep in mind:
+
+-------
+Unicode
+-------
+
+Use ``unicode`` internally, not encoded bytestrings. Only encode/decode where
+data enters or exits the system. This means that your code works with characters
+and not just with bytes, which is an important distinction for example when 
+calculating the length of a piece of text. When you need to decode/encode, it's
+probably a good idea to use UTF-8.
+
+-------------
+Date and Time
+-------------
+
+If your application uses datetime information that should be displayed to users 
+in different timezones, you should try to work with UTC (universal time) 
+internally. Do the conversion from and to "local time" when the data enters or 
+exits the system. Make use the Python `datetime`_ module and the third-party 
+`pytz`_ package.
+
+--------------------------
+Formatting and Locale Data
+--------------------------
+
+Make sure you check out the functionality provided by the `Babel`_ project for 
+things like number and date formatting, locale display strings, etc.
+
+.. _`datetime`: http://docs.python.org/lib/module-datetime.html
+.. _`pytz`: http://pytz.sourceforge.net/
diff --git a/lib/genshi/doc/index.txt b/lib/genshi/doc/index.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/index.txt
@@ -0,0 +1,45 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=======
+Preface
+=======
+
+.. image:: logo.png
+   :width: 225
+   :height: 81
+   :align: center
+   :alt: Genshi - Generate output for the web
+   :class: logo
+
+--------------------------------------------
+Toolkit for generation of output for the web
+--------------------------------------------
+
+Genshi is a Python library that provides an integrated set of components
+for parsing, generating, and processing HTML, XML or other textual content
+for output generation on the web. The major feature is a template language,
+which is heavily inspired by Kid.
+
+Installation
+------------
+
+* `Installing Genshi <install.html>`_
+* `Upgrading from Previous Versions <upgrade.html>`_
+
+Usage
+-----
+
+* `Markup Streams <streams.html>`_
+* `Templating Basics <templates.html>`_
+* `XML Template Language <xml-templates.html>`_
+* `Text Template Language <text-templates.html>`_
+* `Loading Templates <loader.html>`_
+* `Using Stream Filters <filters.html>`_
+* `Using XPath <xpath.html>`_
+* `Internationalization and Localization <i18n.html>`_
+* `Using the Templating Plugin <plugin.html>`_
+
+API Documentation
+-----------------
+
+* `Generated API Documentation <api/index.html>`_
diff --git a/lib/genshi/doc/install.txt b/lib/genshi/doc/install.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/install.txt
@@ -0,0 +1,88 @@
+Installing Genshi
+=================
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+
+Prerequisites
+-------------
+
+* Python_ 2.4 or later
+* Optional: Setuptools_ 0.6c3 or later
+
+.. _python: http://www.python.org/
+.. _setuptools: http://cheeseshop.python.org/pypi/setuptools
+
+Setuptools is only required for the `template engine plugin`_, which can be
+used to integrate Genshi with Python web application frameworks such as Pylons
+or TurboGears. Genshi also provides a Setuptools-based plugin that integrates
+its `internationalization support`_ with the Babel_ library, but that support
+can also be used without Setuptools being available (although in a slightly
+less convenient fashion).
+
+.. _`template engine plugin`: plugin.html
+.. _`internationalization support`: i18n.html
+.. _babel: http://babel.edgewall.org/
+
+
+Installing via ``easy_install``
+-------------------------------
+
+If you have a recent version of Setuptools_ installed, you can directly install
+Genshi using the easy_install command-line tool::
+
+  $ easy_install Genshi
+
+This downloads and installs the latest version of the Genshi package.
+
+If you have an older Genshi release installed and would like to upgrade, add
+the ``-U`` option to the above command.
+
+
+Installing from a Binary Installer
+----------------------------------
+
+Binary packages for Windows and Mac OS X are provided for Genshi. To install
+from such a package, simply download and open it.
+
+
+Installing from a Source Tarball
+--------------------------------
+
+Once you've downloaded and unpacked a Genshi source release, enter the
+directory where the archive was unpacked, and run::
+
+  $ python setup.py install
+
+Note that you may need administrator/root privileges for this step, as this
+command will by default attempt to install Genshi to the Python
+``site-packages`` directory on your system.
+
+Genshi comes with an optional extension module written in C that is used to
+improve performance in some areas. This extension is automatically compiled
+when you run the ``setup.py`` script as shown above. In the case that the
+extension can not be compiled, possibly due to a missing or incompatible C
+compiler, the compilation is skipped. If you'd prefer Genshi to not use this
+native extension module, you can explicitly bypass the compilation using the
+``--without-speedups`` option::
+
+  $ python setup.py --without-speedups install
+
+For other build and installation options, please consult the easy_install_
+and/or the Python distutils_ documentation.
+
+.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
+.. _distutils:  http://docs.python.org/inst/inst.html
+
+
+Support
+-------
+
+If you encounter any problems with Genshi, please don't hesitate to ask
+questions on the Genshi `mailing list`_ or `IRC channel`_.
+
+.. _`mailing list`: http://genshi.edgewall.org/wiki/MailingList
+.. _`irc channel`: http://genshi.edgewall.org/wiki/IrcChannel
diff --git a/lib/genshi/doc/loader.txt b/lib/genshi/doc/loader.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/loader.txt
@@ -0,0 +1,255 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=================
+Loading Templates
+=================
+
+Genshi comes with a simple but flexible implementation of a template loader in
+the ``genshi.template.loader`` module. The loader provides caching of
+templates so they do not need to be reparsed when used, support for multiple
+template directories that together form a virtual search path, as well as
+support for different template loading strategies.
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+
+-----
+Usage
+-----
+
+The basic usage pattern is simple: instantiate one ``TemplateLoader`` object
+and keep it around, then ask it to load a template whenever you need to load
+one:
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader
+  
+  loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'],
+                          auto_reload=True)
+  tmpl = loader.load('test.html')
+
+When you try to load a template that can't be found, you get a
+``TemplateNotFound`` error.
+
+The default template class used by the loader is ``MarkupTemplate``, but that
+can be overridden both with a different default (as a keyword argument to the
+``TemplateLoader`` constructor), as well as on invocation of the ``load()``
+method:
+
+.. code-block:: python
+
+  from genshi.template.text import NewTextTemplate
+  
+  tmpl = loader.load('mail.txt', cls=NewTextTemplate)
+
+
+-------
+Caching
+-------
+
+The ``TemplateLoader`` class provides a simple in-memory cache for parsed
+template objects. This improves performance, because templates do not need to
+be reparsed every time they are rendered.
+
+The size of this cache can be adjusted using the `max_cache_size` option on
+the ``TemplateLoader`` constructor. The value of that option determines the
+maximum number of template objects kept in the cache. When this limit is
+reached, any templates that haven't been used in a while get purged.
+Technically, this is a least-recently-used (LRU) cache, the default limit is
+set to 25 templates.
+
+Automatic Reloading
+===================
+
+Once a template has been cached, it will normally not get reparsed until it
+has been purged from the cache. This means that any changes to the template
+file are not taken into consideration as long as it is still found in the
+cache. As this is inconvenient in development scenarios, the ``auto_reload``
+option allows for automatic cache invalidation based on whether the template
+source has changed.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader
+  
+  loader = TemplateLoader('templates', auto_reload=True, max_cache_size=100)
+
+In production environments, automatic reloading should be disabled, as it does
+affect performance negatively.
+
+Callback Interface
+==================
+
+Sometimes you need to make sure that templates get properly configured after
+they have been loaded, but you only want to do that when the template is
+actually loaded and parsed, not when it is returned from the cache.
+
+For such cases, the ``TemplateLoader`` provides a way to specify a callback
+function that gets invoked whenever a template is loaded. You can specify that
+callback by passing it into the loader constructor via the ``callback``
+keyword argument, or later by setting the attribute of the same name. The
+callback function should expect a single argument, the template object.
+
+For example, to properly inject the `translation filter`_ into any loaded
+template, you'd use code similar to this:
+
+.. code-block:: python
+
+  from genshi.filters import Translator
+  from genshi.template import TemplateLoader
+  
+  def template_loaded(template):
+      Translator(translations.ugettext).setup(template)
+  
+  loader = TemplateLoader('templates', callback=template_loaded)
+
+.. _`translation filter`: i18n.html
+
+--------------------
+Template Search Path
+--------------------
+
+The template loader can be configured with a list of multiple directories to
+search for templates. The loader maps these directories to a single logical
+directory for locating templates by file name.
+
+The order of the directories making up the search path is significant: the
+loader will first try to locate a requested template in the first directory on
+the path, then in the second, and so on. If there are two templates with the
+same file name in multiple directories on the search path, whatever file is
+found first gets used.
+
+Based on this design, an application could, for example, configure a search
+path consisting of a directory containing the default templates, as well as a
+directory where site-specific templates can be stored that will override the
+default templates.
+
+
+Load Functions
+==============
+
+Usually the search path consists of strings representing directory paths, but
+it may also contain &#8220;load functions&#8221;: functions that are basically invoked
+with the file name, and return the template content.
+
+Genshi comes with three builtin load functions:
+
+``directory(path)``
+-------------------
+
+The equivalent of just using a string containing the directory path: looks up
+the file name in a specific directory.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader([loader.directory('/path/to/dir/')])
+
+That is the same as:
+
+.. code-block:: python
+
+  tl = TemplateLoader(['/path/to/dir/'])
+
+
+``package(name, path)``
+-----------------------
+
+Uses the ``pkg_resources`` API to locate files in Python package data (which
+may be inside a ZIP archive).
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader([loader.package('myapp', 'templates')])
+
+This will look for templates in the ``templates`` directory of the Python
+package ``myapp``.
+
+``prefixed(**delegates)``
+-------------------------
+
+Delegates load requests to different load functions based on the path prefix.
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader, loader
+  tl = TemplateLoader(loader.prefixed(
+    core = '/tmp/dir1',
+    plugin1 = loader.package('plugin1', 'templates'),
+    plugin2 = loader.package('plugin2', 'templates'),
+  ))
+  tmpl = tl.load('core/index.html')
+
+This example sets up a loader with three delegates, under the prefixes &#8220;core&#8221;,
+&#8220;plugin1&#8221;, and &#8220;plugin2&#8221;. When a template is requested, the ``prefixed`` load
+function looks for a delegate with a corresponding prefix, removes the prefix
+from the path and asks the delegate to load the template.
+
+In this case, assuming the directory ``/path/to/dir`` contains a file named
+``index.html``, that file will be used when we load ``core/index.html``. The
+other delegates are not checked as their prefix does not match.
+
+
+.. note:: These builtin load functions are available both as class methods
+          of the ``TemplateLoader`` class as well as on the module level
+
+
+Custom Load Functions
+---------------------
+
+You can easily use your own load function with the template loader, for
+example to load templates from a database. All that is needed is a callable
+object that accepts a ``filename`` (a string) and returns a tuple of the form
+``(filepath, filename, fileobj, uptodate_fun)``, where:
+
+``filepath``
+  is the absolute path to the template. This is primarily used for output in
+  tracebacks, and does not need to map to an actual path on the file system.
+``filename``
+  is the base name of the template file
+``fileobj``
+  is a readable file-like object that provides the content of the template
+``uptodate_fun``
+  is a function that the loader can invoke to check whether the cached version
+  of the template is still up-to-date, or ``None`` if the load function is not
+  able to provide such a check. If provided, the function should not expect
+  any parameters (so you'll definitely want to use a closure here), and should
+  return ``True`` if the template has not changed since it was last loaded.
+
+When the requested template can not be found, the function should raise an
+``IOError`` or ``TemplateNotFound`` exception.
+
+
+------------------
+Customized Loading
+------------------
+
+If you require a completely different implementation of template loading, you
+can extend or even replace the builtin ``TemplateLoader`` class.
+
+Protocol
+========
+
+The protocol between the template loader and the ``Template`` class is simple
+and only used for processing includes. The only required part of that protocol
+is that the object assigned to ``Template.loader`` implements a ``load``
+method compatible to that of the ``TemplateLoader`` class, at the minimum with
+the signature ``load(filename, relative_to=None, cls=None)``.
+
+In addition, templates currently check for the existence and value of a boolean
+``auto_reload`` property. If the property does not exist or evaluates to a
+non-truth value, inlining of included templates is disabled. Inlining is a
+small optimization that removes some overhead in the processing of includes.
+
+Subclassing ``TemplateLoader``
+==============================
+
+You can also adjust the behavior of the ``TemplateLoader`` class by subclassing
+it. You can of course override anything needed, but the class also provides the
+``_instantiate()`` hook, which is intended for use by subclasses to customize
+the creation of the template object from the file name and content. Please
+consult the code and the API documentation for more detail.
diff --git a/lib/genshi/doc/logo.gif b/lib/genshi/doc/logo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..05edacd14f1ae6f2cdf29559104655b815fba1bd
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/logo.lineform/data b/lib/genshi/doc/logo.lineform/data
new file mode 100644
index 0000000000000000000000000000000000000000..f836e7144ec22c73b80c41d7a346dae4d66307e9
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/logo.png b/lib/genshi/doc/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b290a6dac09aa4be51289e983fc33240d45f812
GIT binary patch

[cut]

diff --git a/lib/genshi/doc/plugin.txt b/lib/genshi/doc/plugin.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/plugin.txt
@@ -0,0 +1,260 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+===========================
+Using the Templating Plugin
+===========================
+
+While you can easily use Genshi templating through the APIs provided directly
+by Genshi, in some situations you may want to use Genshi through the template
+engine plugin API. Note though that this considerably limits the power and
+flexibility of Genshi templates (for example, there's no good way to use filters
+such as Genshi's `HTMLFormFiller`_ when the plugin
+API is sitting between your code and Genshi).
+
+.. _`HTMLFormFiller`: filters.html>#html-form-filler
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+
+Introduction
+============
+
+Some Python web frameworks support a variety of different templating engines
+through the `Template Engine Plugin API`_, which was first developed by the
+Buffet_ and TurboGears_ projects.
+
+.. _`Template Engine Plugin API`: http://docs.turbogears.org/1.0/TemplatePlugins
+.. _`Buffet`: http://projects.dowski.com/projects/buffet
+.. _`TurboGears`: http://www.turbogears.org/
+
+Genshi supports this API out of the box, so you can use it in frameworks like
+TurboGears or `Pylons`_ without installing any additional packages. A small
+example TurboGears application is included in the ``examples`` directory of
+source distributions of Genshi.
+
+.. _`Pylons`: http://pylonshq.com/
+
+
+Usage
+=====
+
+The way you use Genshi through the plugin API depends very much on the framework
+you're using. In general, the approach will look something like the following:
+
+(1) Configure Genshi as the default (or an additional) template engine
+(2) Optionally specify Genshi-specific `configuration options`_
+(3) For any given *view* or *controller* (or whatever those are called in your
+    framework of choice), specify the name of the template to use and which data
+    should be made available to it.
+
+For point 1, you'll have to specify the *name* of the template engine plugin.
+For Genshi, this is **"genshi"**. However, because Genshi supports both markup
+and text templates, it also provides two separate plugins, namely
+**"genshi-markup"** and **"genshi-text"** (the "genshi" name is just an
+alias for "genshi-markup").
+
+Usually, you can choose a default template engine, but also use a different
+engine on a per-request basis. So to use markup templates in general, but a text
+template in a specific controller, you'd configure "genshi" as the default
+template engine, and specify "genshi-text" for the controllers that should use
+text templates. How exactly this works depends on the framework in use.
+
+When rendering a specific template in a controller (point 3 above), you may also
+be able to pass additional options to the plugin. This includes the ``format``
+keyword argument, which Genshi will use to override the configured default
+serialization method. In combination with specifying the "genshi-text" engine
+name as explained above, you would use this to specify the "text" serialization
+method when you want to use a text template. Or you'd specify "xml" for the
+format when you want to produce an Atom feed or other XML content.
+
+
+Template Paths
+--------------
+
+How you specify template paths depends on whether you have a `search path`_ set
+up or not. The search path is a list of directories that Genshi should load
+templates from. Now when you request a template using a relative path such as
+``mytmpl.html`` or ``foo/mytmpl.html``, Genshi will look for that file in the
+directories on the search path.
+
+For mostly historical reasons, the Genshi template engine plugin uses a
+different approach when you **haven't** configured the template search path:
+you now load templates using *dotted notation*, for example ``mytmpl`` or
+``foo.mytmpl``.  Note how you've lost the ability to explicitly specify the
+file extension: you now have to use ``.html`` for markup templates, and
+``.txt`` for text templates.
+
+Using the search path is recommended for a number of reasons: First, it's
+the native Genshi model and is thus more robust and better supported.
+Second, a search path gives you much more flexibility for organizing your
+application templates. And as noted above, you aren't forced to use hardcoded
+filename extensions for your template files.
+
+
+Extra Implicit Objects
+----------------------
+
+The "genshi-markup" template engine plugin adds some extra functions that are
+made available to all templates implicitly, namely:
+
+``HTML(string)``
+  Parses the given string as HTML and returns a markup stream.
+``XML(string)``
+  Parses the given string as XML and returns a markup stream.
+``ET(tree)``
+  Adapts the given `ElementTree`_ object to a markup stream.
+
+The framework may make additional objects available by default. Consult the
+documentation of your framework for more information.
+
+.. _elementtree: http://effbot.org/zone/element-index.htm
+
+
+.. _`configuration options`:
+
+Configuration Options
+=====================
+
+The plugin API allows plugins to be configured using a dictionary of strings.
+The following is a list of configuration options that Genshi supports. These may
+or may not be made available by your framework. TurboGears 1.0, for example,
+only passes a fixed set of options to all plugins.
+
+``genshi.allow_exec``
+--------------------------
+Whether the Python code blocks should be permitted in templates. Specify "yes"
+to allow code blocks (which is the default), or "no" otherwise. Please note
+that disallowing code blocks in templates does not turn Genshi into a
+sandboxable template engine; there are sufficient ways to do harm even using
+plain expressions.
+
+``genshi.auto_reload``
+----------------------
+Whether the template loader should check the last modification time of template 
+files, and automatically reload them if they have been changed. Specify "yes"
+to enable this reloading (which is the default), or "no" to turn it off.
+
+You probably want to disable reloading in a production environment to improve
+performance of both templating loading and the processing of includes. But
+remember that you'll then have to manually restart the server process anytime
+the templates are updated.
+
+``genshi.default_doctype``
+--------------------------
+The default ``DOCTYPE`` declaration to use in generated markup. Valid values
+are:
+
+**html-strict** (or just **html**)
+  HTML 4.01 Strict
+**html-transitional**
+  HTML 4.01 Transitional
+**xhtml-strict** (or just **xhtml**)
+  XHTML 1.0 Strict
+**xhtml-transitional**
+  XHTML 1.0 Transitional
+**html5**
+  HTML5 (as `proposed`_ by the WHAT-WG)
+
+.. _proposed: http://www.whatwg.org/specs/web-apps/current-work/
+
+.. note:: While using the Genshi API directly allows you to specify document
+          types not in that list, the *dictionary-of-strings* based
+          configuration utilized by the plugin API unfortunately limits your
+          choices to those listed above.
+
+The default behavior is to not do any prepending/replacing of a ``DOCTYPE``, but
+rather pass through those defined in the templates (if any). If this option is
+set, however, any ``DOCTYPE`` declarations in the templates are replaced by the
+specified document type.
+
+Note that with (X)HTML, the presence and choice of the ``DOCTYPE`` can have a
+more or less dramatic impact on how modern browsers render pages that use CSS
+style sheets. In particular, browsers may switch to *quirks rendering mode* for
+certain document types, or when the ``DOCTYPE`` declaration is missing
+completely.
+
+For more information on the choice of the appropriate ``DOCTYPE``, see:
+
+* `Recommended DTDs to use in your Web document <http://www.w3.org/QA/2002/04/valid-dtd-list.html>`_
+* `Choosing a DOCTYPE <http://htmlhelp.com/tools/validator/doctype.html>`_
+
+``genshi.default_encoding``
+---------------------------
+The default output encoding to use when serializing a template. By default,
+Genshi uses UTF-8. If you need to, you can choose a different charset by
+specifying this option, although that rarely makes sense.
+
+As Genshi is not in control over what HTTP headers are being sent together with
+the template output, make sure that you (or the framework you're using)
+specify the chosen encoding as part of the outgoing ``Content-Type`` header.
+For example::
+
+  Content-Type: text/html; charset=utf-8
+
+.. note:: Browsers commonly use ISO-8859-1 by default for ``text/html``, so even
+          if you use Genshi's default UTF-8 encoding, you'll have to let the
+          browser know about that explicitly
+
+``genshi.default_format``
+-------------------------
+Determines the default serialization method to use. Valid options are:
+
+**xml**
+  Serialization to XML
+**xhtml**
+  Serialization to XHTML in a way that should be compatible with HTML (i.e. the
+  result can be sent using the ``text/html`` MIME type, but can also be handled
+  by XML parsers if you're careful).
+**html**
+  Serialization to HTML
+**text**
+  Plain text serialization
+
+See `Understanding HTML, XML and XHTML`_ for an excellent description of the
+subtle differences between the three different markup serialization options. As
+a general recommendation, if you don't have a special requirement to produce
+well-formed XML, you should probably use the **html** option for your web sites.
+
+.. _`Understanding HTML, XML and XHTML`: http://webkit.org/blog/?p=68
+
+``genshi.loader_callback``
+--------------------------
+The callback function that should be invoked whenever the template loader loads
+a new template.
+
+.. note:: Unlike the other options, this option can **not** be passed as
+          a string value, but rather must be a reference to the actual function.
+          That effectively means it can not be set from (non-Python)
+          configuration files.
+
+``genshi.lookup_errors``
+------------------------
+The error handling style to use in template expressions. Can be either
+**lenient** (the default) or **strict**. See the `Error Handling`_ section for
+detailled information on the differences between these two modes.
+
+.. _`Error Handling`: templates.html#template-expressions-and-code-blocks
+
+``genshi.max_cache_size``
+-------------------------
+The maximum number of templates that the template loader will cache in memory.
+The default value is **25**. You may want to choose a higher value if your web
+site uses a larger number of templates, and you have enough memory to spare.
+
+``genshi.new_text_syntax``
+--------------------------
+Whether the new syntax for text templates should be used. Specify "yes" to
+enable the new syntax, or "no" to use the old syntax.
+
+In the version of Genshi, the default is to use the old syntax for
+backwards-compatibility, but that will change in a future release.
+
+.. _`search path`:
+
+``genshi.search_path``
+----------------------
+A colon-separated list of file-system path names that the template loader should
+use to search for templates.
diff --git a/lib/genshi/doc/streams.txt b/lib/genshi/doc/streams.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/streams.txt
@@ -0,0 +1,485 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+==============
+Markup Streams
+==============
+
+A stream is the common representation of markup as a *stream of events*.
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+
+Basics
+======
+
+A stream can be attained in a number of ways. It can be:
+
+* the result of parsing XML or HTML text, or
+* the result of selecting a subset of another stream using XPath, or
+* programmatically generated.
+
+For example, the functions ``XML()`` and ``HTML()`` can be used to convert
+literal XML or HTML text to a markup stream:
+
+.. code-block:: pycon
+
+  >>> from genshi import XML
+  >>> stream = XML('<p class="intro">Some text and '
+  ...              '<a href="http://example.org/">a link</a>.'
+  ...              '<br/></p>')
+  >>> stream
+  <genshi.core.Stream object at ...>
+
+The stream is the result of parsing the text into events. Each event is a tuple
+of the form ``(kind, data, pos)``, where:
+
+* ``kind`` defines what kind of event it is (such as the start of an element,
+  text, a comment, etc).
+* ``data`` is the actual data associated with the event. How this looks depends
+  on the event kind (see  `event kinds`_)
+* ``pos`` is a ``(filename, lineno, column)`` tuple that describes where the
+  event &#8220;comes from&#8221;.
+
+.. code-block:: pycon
+
+  >>> for kind, data, pos in stream:
+  ...     print('%s %r %r' % (kind, data, pos))
+  ... 
+  START (QName('p'), Attrs([(QName('class'), u'intro')])) (None, 1, 0)
+  TEXT u'Some text and ' (None, 1, 17)
+  START (QName('a'), Attrs([(QName('href'), u'http://example.org/')])) (None, 1, 31)
+  TEXT u'a link' (None, 1, 61)
+  END QName('a') (None, 1, 67)
+  TEXT u'.' (None, 1, 71)
+  START (QName('br'), Attrs()) (None, 1, 72)
+  END QName('br') (None, 1, 77)
+  END QName('p') (None, 1, 77)
+
+
+Filtering
+=========
+
+One important feature of markup streams is that you can apply *filters* to the
+stream, either filters that come with Genshi, or your own custom filters.
+
+A filter is simply a callable that accepts the stream as parameter, and returns
+the filtered stream:
+
+.. code-block:: python
+
+  def noop(stream):
+      """A filter that doesn't actually do anything with the stream."""
+      for kind, data, pos in stream:
+          yield kind, data, pos
+
+Filters can be applied in a number of ways. The simplest is to just call the
+filter directly:
+
+.. code-block:: python
+
+  stream = noop(stream)
+
+The ``Stream`` class also provides a ``filter()`` method, which takes an
+arbitrary number of filter callables and applies them all:
+
+.. code-block:: python
+
+  stream = stream.filter(noop)
+
+Finally, filters can also be applied using the *bitwise or* operator (``|``),
+which allows a syntax similar to pipes on Unix shells:
+
+.. code-block:: python
+
+  stream = stream | noop
+
+One example of a filter included with Genshi is the ``HTMLSanitizer`` in
+``genshi.filters``. It processes a stream of HTML markup, and strips out any
+potentially dangerous constructs, such as Javascript event handlers.
+``HTMLSanitizer`` is not a function, but rather a class that implements
+``__call__``, which means instances of the class are callable:
+
+.. code-block:: python
+
+  stream = stream | HTMLSanitizer()
+
+Both the ``filter()`` method and the pipe operator allow easy chaining of
+filters:
+
+.. code-block:: python
+
+  from genshi.filters import HTMLSanitizer
+  stream = stream.filter(noop, HTMLSanitizer())
+
+That is equivalent to:
+
+.. code-block:: python
+
+  stream = stream | noop | HTMLSanitizer()
+
+For more information about the built-in filters, see `Stream Filters`_.
+
+.. _`Stream Filters`: filters.html
+
+
+Serialization
+=============
+
+Serialization means producing some kind of textual output from a stream of
+events, which you'll need when you want to transmit or store the results of
+generating or otherwise processing markup.
+
+The ``Stream`` class provides two methods for serialization: ``serialize()``
+and ``render()``. The former is a generator that yields chunks of ``Markup``
+objects (which are basically unicode strings that are considered safe for
+output on the web). The latter returns a single string, by default UTF-8
+encoded.
+
+Here's the output from ``serialize()``:
+
+.. code-block:: pycon
+
+  >>> for output in stream.serialize():
+  ...     print(repr(output))
+  ... 
+  <Markup u'<p class="intro">'>
+  <Markup u'Some text and '>
+  <Markup u'<a href="http://example.org/">'>
+  <Markup u'a link'>
+  <Markup u'</a>'>
+  <Markup u'.'>
+  <Markup u'<br/>'>
+  <Markup u'</p>'>
+
+And here's the output from ``render()``:
+
+.. code-block:: pycon
+
+  >>> print(stream.render())
+  <p class="intro">Some text and <a href="http://example.org/">a link</a>.<br/></p>
+
+Both methods can be passed a ``method`` parameter that determines how exactly
+the events are serialized to text. This parameter can be either a string or a 
+custom serializer class:
+
+.. code-block:: pycon
+
+  >>> print(stream.render('html'))
+  <p class="intro">Some text and <a href="http://example.org/">a link</a>.<br></p>
+
+Note how the `<br>` element isn't closed, which is the right thing to do for
+HTML. See  `serialization methods`_ for more details.
+
+In addition, the ``render()`` method takes an ``encoding`` parameter, which
+defaults to &#8220;UTF-8&#8221;. If set to ``None``, the result will be a unicode string.
+
+The different serializer classes in ``genshi.output`` can also be used
+directly:
+
+.. code-block:: pycon
+
+  >>> from genshi.filters import HTMLSanitizer
+  >>> from genshi.output import TextSerializer
+  >>> print(''.join(TextSerializer()(HTMLSanitizer()(stream))))
+  Some text and a link.
+
+The pipe operator allows a nicer syntax:
+
+.. code-block:: pycon
+
+  >>> print(stream | HTMLSanitizer() | TextSerializer())
+  Some text and a link.
+
+
+.. _`serialization methods`:
+
+Serialization Methods
+---------------------
+
+Genshi supports the use of different serialization methods to use for creating
+a text representation of a markup stream.
+
+``xml``
+  The ``XMLSerializer`` is the default serialization method and results in
+  proper XML output including namespace support, the XML declaration, CDATA
+  sections, and so on. It is not generally not suitable for serving HTML or
+  XHTML web pages (unless you want to use true XHTML 1.1), for which the
+  ``xhtml`` and ``html`` serializers described below should be preferred.
+
+``xhtml``
+  The ``XHTMLSerializer`` is a specialization of the generic ``XMLSerializer``
+  that understands the pecularities of producing XML-compliant output that can
+  also be parsed without problems by the HTML parsers found in modern web
+  browsers. Thus, the output by this serializer should be usable whether sent
+  as "text/html" or "application/xhtml+html" (although there are a lot of
+  subtle issues to pay attention to when switching between the two, in
+  particular with respect to differences in the DOM and CSS).
+
+  For example, instead of rendering a script tag as ``<script/>`` (which
+  confuses the HTML parser in many browsers), it will produce
+  ``<script></script>``. Also, it will normalize any boolean attributes values
+  that are minimized in HTML, so that for example ``<hr noshade="1"/>``
+  becomes ``<hr noshade="noshade" />``.
+
+  This serializer supports the use of namespaces for compound documents, for
+  example to use inline SVG inside an XHTML document.
+
+``html``
+  The ``HTMLSerializer`` produces proper HTML markup. The main differences
+  compared to ``xhtml`` serialization are that boolean attributes are
+  minimized, empty tags are not self-closing (so it's ``<br>`` instead of
+  ``<br />``), and that the contents of ``<script>`` and ``<style>`` elements
+  are not escaped.
+
+``text``
+  The ``TextSerializer`` produces plain text from markup streams. This is
+  useful primarily for `text templates`_, but can also be used to produce
+  plain text output from markup templates or other sources.
+
+.. _`text templates`: text-templates.html
+
+
+Serialization Options
+---------------------
+
+Both ``serialize()`` and ``render()`` support additional keyword arguments that
+are passed through to the initializer of the serializer class. The following
+options are supported by the built-in serializers:
+
+``strip_whitespace``
+  Whether the serializer should remove trailing spaces and empty lines.
+  Defaults to ``True``.
+
+  (This option is not available for serialization to plain text.)
+
+``doctype``
+  A ``(name, pubid, sysid)`` tuple defining the name, publid identifier, and
+  system identifier of a ``DOCTYPE`` declaration to prepend to the generated
+  output. If provided, this declaration will override any ``DOCTYPE``
+  declaration in the stream.
+
+  The parameter can also be specified as a string to refer to commonly used
+  doctypes:
+  
+  +-----------------------------+-------------------------------------------+
+  | Shorthand                   | DOCTYPE                                   |
+  +=============================+===========================================+
+  | ``html`` or                 | HTML 4.01 Strict                          |
+  | ``html-strict``             |                                           |
+  +-----------------------------+-------------------------------------------+
+  | ``html-transitional``       | HTML 4.01 Transitional                    |
+  +-----------------------------+-------------------------------------------+
+  | ``html-frameset``           | HTML 4.01 Frameset                        |
+  +-----------------------------+-------------------------------------------+
+  | ``html5``                   | DOCTYPE proposed for the work-in-progress |
+  |                             | HTML5 standard                            |
+  +-----------------------------+-------------------------------------------+
+  | ``xhtml`` or                | XHTML 1.0 Strict                          |
+  | ``xhtml-strict``            |                                           |
+  +-----------------------------+-------------------------------------------+
+  | ``xhtml-transitional``      | XHTML 1.0 Transitional                    |
+  +-----------------------------+-------------------------------------------+
+  | ``xhtml-frameset``          | XHTML 1.0 Frameset                        |
+  +-----------------------------+-------------------------------------------+
+  | ``xhtml11``                 | XHTML 1.1                                 |
+  +-----------------------------+-------------------------------------------+
+  | ``svg`` or ``svg-full``     | SVG 1.1                                   |
+  +-----------------------------+-------------------------------------------+
+  | ``svg-basic``               | SVG 1.1 Basic                             |
+  +-----------------------------+-------------------------------------------+
+  | ``svg-tiny``                | SVG 1.1 Tiny                              |
+  +-----------------------------+-------------------------------------------+
+
+  (This option is not available for serialization to plain text.)
+
+``namespace_prefixes``
+  The namespace prefixes to use for namespace that are not bound to a prefix
+  in the stream itself.
+
+  (This option is not available for serialization to HTML or plain text.)
+
+``drop_xml_decl``
+  Whether to remove the XML declaration (the ``<?xml ?>`` part at the
+  beginning of a document) when serializing. This defaults to ``True`` as an
+  XML declaration throws some older browsers into "Quirks" rendering mode.
+
+  (This option is only available for serialization to XHTML.)
+
+``strip_markup``
+  Whether the text serializer should detect and remove any tags or entity
+  encoded characters in the text.
+
+  (This option is only available for serialization to plain text.)
+
+
+
+Using XPath
+===========
+
+XPath can be used to extract a specific subset of the stream via the
+``select()`` method:
+
+.. code-block:: pycon
+
+  >>> substream = stream.select('a')
+  >>> substream
+  <genshi.core.Stream object at ...>
+  >>> print(substream)
+  <a href="http://example.org/">a link</a>
+
+Often, streams cannot be reused: in the above example, the sub-stream is based
+on a generator. Once it has been serialized, it will have been fully consumed,
+and cannot be rendered again. To work around this, you can wrap such a stream
+in a ``list``:
+
+.. code-block:: pycon
+
+  >>> from genshi import Stream
+  >>> substream = Stream(list(stream.select('a')))
+  >>> substream
+  <genshi.core.Stream object at ...>
+  >>> print(substream)
+  <a href="http://example.org/">a link</a>
+  >>> print(substream.select('@href'))
+  http://example.org/
+  >>> print(substream.select('text()'))
+  a link
+
+See `Using XPath in Genshi`_ for more information about the XPath support in
+Genshi.
+
+.. _`Using XPath in Genshi`: xpath.html
+
+
+.. _`event kinds`:
+
+Event Kinds
+===========
+
+Every event in a stream is of one of several *kinds*, which also determines
+what the ``data`` item of the event tuple looks like. The different kinds of
+events are documented below.
+
+.. note:: The ``data`` item is generally immutable. If the data is to be
+   modified when processing a stream, it must be replaced by a new tuple.
+   Effectively, this means the entire event tuple is immutable.
+
+START
+-----
+The opening tag of an element.
+
+For this kind of event, the ``data`` item is a tuple of the form
+``(tagname, attrs)``, where ``tagname`` is a ``QName`` instance describing the
+qualified name of the tag, and ``attrs`` is an ``Attrs`` instance containing
+the attribute names and values associated with the tag (excluding namespace
+declarations):
+
+.. code-block:: python
+
+  START, (QName('p'), Attrs([(QName('class'), u'intro')])), pos
+
+END
+---
+The closing tag of an element.
+
+The ``data`` item of end events consists of just a ``QName`` instance
+describing the qualified name of the tag:
+
+.. code-block:: python
+
+  END, QName('p'), pos
+
+TEXT
+----
+Character data outside of elements and comments.
+
+For text events, the ``data`` item should be a unicode object:
+
+.. code-block:: python
+
+  TEXT, u'Hello, world!', pos
+
+START_NS
+--------
+The start of a namespace mapping, binding a namespace prefix to a URI.
+
+The ``data`` item of this kind of event is a tuple of the form
+``(prefix, uri)``, where ``prefix`` is the namespace prefix and ``uri`` is the
+full URI to which the prefix is bound. Both should be unicode objects. If the
+namespace is not bound to any prefix, the ``prefix`` item is an empty string:
+
+.. code-block:: python
+
+  START_NS, (u'svg', u'http://www.w3.org/2000/svg'), pos
+
+END_NS
+------
+The end of a namespace mapping.
+
+The ``data`` item of such events consists of only the namespace prefix (a
+unicode object):
+
+.. code-block:: python
+
+  END_NS, u'svg', pos
+
+DOCTYPE
+-------
+A document type declaration.
+
+For this type of event, the ``data`` item is a tuple of the form
+``(name, pubid, sysid)``, where ``name`` is the name of the root element,
+``pubid`` is the public identifier of the DTD (or ``None``), and ``sysid`` is
+the system identifier of the DTD (or ``None``):
+
+.. code-block:: python
+
+  DOCTYPE, (u'html', u'-//W3C//DTD XHTML 1.0 Transitional//EN', \
+            u'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'), pos
+
+COMMENT
+-------
+A comment.
+
+For such events, the ``data`` item is a unicode object containing all character
+data between the comment delimiters:
+
+.. code-block:: python
+
+  COMMENT, u'Commented out', pos
+
+PI
+--
+A processing instruction.
+
+The ``data`` item is a tuple of the form ``(target, data)`` for processing
+instructions, where ``target`` is the target of the PI (used to identify the
+application by which the instruction should be processed), and ``data`` is text
+following the target (excluding the terminating question mark):
+
+.. code-block:: python
+
+  PI, (u'php', u'echo "Yo" '), pos
+
+START_CDATA
+-----------
+Marks the beginning of a ``CDATA`` section.
+
+The ``data`` item for such events is always ``None``:
+
+.. code-block:: python
+
+  START_CDATA, None, pos
+
+END_CDATA
+---------
+Marks the end of a ``CDATA`` section.
+
+The ``data`` item for such events is always ``None``:
+
+.. code-block:: python
+
+  END_CDATA, None, pos
diff --git a/lib/genshi/doc/templates.txt b/lib/genshi/doc/templates.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/templates.txt
@@ -0,0 +1,458 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+========================
+Genshi Templating Basics
+========================
+
+Genshi provides a template engine that can be used for generating either
+markup (such as HTML_ or XML_) or plain text. While both share some of the
+syntax (and much of the underlying implementation) they are essentially
+separate languages.
+
+.. _html: http://www.w3.org/html/
+.. _xml: http://www.w3.org/XML/
+
+This document describes the common parts of the template engine and will be most
+useful as reference to those developing Genshi templates. Templates are XML or
+plain text files that include processing directives_ that affect how the
+template is rendered, and template expressions_ that are dynamically substituted
+by variable data.
+
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+--------
+Synopsis
+--------
+
+A Genshi *markup template* is a well-formed XML document with embedded Python
+used for control flow and variable substitution. Markup templates should be
+used to generate any kind of HTML or XML output, as they provide a number of
+advantages over simple text-based templates (such as automatic escaping of
+variable data).
+
+The following is a simple Genshi markup template:
+
+.. code-block:: genshi
+
+  <?python
+    title = "A Genshi Template"
+    fruits = ["apple", "orange", "kiwi"]
+  ?>
+  <html xmlns:py="http://genshi.edgewall.org/">
+    <head>
+      <title py:content="title">This is replaced.</title>
+    </head>
+
+    <body>
+      <p>These are some of my favorite fruits:</p>
+      <ul>
+        <li py:for="fruit in fruits">
+          I like ${fruit}s
+        </li>
+      </ul>
+    </body>
+  </html>
+
+This example shows:
+
+(a) a Python code block in a processing instruction
+(b) the Genshi namespace declaration
+(c) usage of templates directives (``py:content`` and ``py:for``)
+(d) an inline Python expression (``${fruit}``).
+
+The template would generate output similar to this:
+
+.. code-block:: genshi
+
+  <html>
+    <head>
+      <title>A Genshi Template</title>
+    </head>
+
+    <body>
+      <p>These are some of my favorite fruits:</p>
+      <ul>
+        <li>I like apples</li>
+        <li>I like oranges</li>
+        <li>I like kiwis</li>
+      </ul>
+    </body>
+  </html>
+
+A *text template* is a simple plain text document that can also contain
+embedded Python code. Text templates are intended to be used for simple
+*non-markup* text formats, such as the body of an plain text email. For
+example:
+
+.. code-block:: genshitext
+
+  Dear $name,
+  
+  These are some of my favorite fruits:
+  #for fruit in fruits
+   * $fruit
+  #end
+
+
+----------
+Python API
+----------
+
+The Python code required for templating with Genshi is generally based on the
+following pattern:
+
+* Attain a ``MarkupTemplate`` or ``TextTemplate`` object from a string or
+  file-like object containing the template source. This can either be done
+  directly, or through a ``TemplateLoader`` instance.
+* Call the ``generate()`` method of the template, passing any data that should
+  be made available to the template as keyword arguments.
+* Serialize the resulting stream using its ``render()`` method.
+
+For example:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>')
+  >>> stream = tmpl.generate(name='world')
+  >>> print(stream.render('xhtml'))
+  <h1>Hello, world!</h1>
+
+.. note:: See the Serialization_ section of the `Markup Streams`_ page for
+          information on configuring template output options.
+
+Using a text template is similar:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import TextTemplate
+  >>> tmpl = TextTemplate('Hello, $name!')
+  >>> stream = tmpl.generate(name='world')
+  >>> print(stream)
+  Hello, world!
+
+.. note:: If you want to use text templates, you should consider using the
+          ``NewTextTemplate`` class instead of simply ``TextTemplate``. See
+          the `Text Template Language`_ page.
+
+.. _serialization: streams.html#serialization
+.. _`Text Template Language`: text-templates.html
+.. _`Markup Streams`: streams.html
+
+Using a `template loader`_ provides the advantage that &#8220;compiled&#8221; templates are
+automatically cached, and only parsed again when the template file changes. In
+addition, it enables the use of a *template search path*, allowing template
+directories to be spread across different file-system locations. Using a
+template loader would generally look as follows:
+
+.. code-block:: python
+
+  from genshi.template import TemplateLoader
+  loader = TemplateLoader([templates_dir1, templates_dir2])
+  tmpl = loader.load('test.html')
+  stream = tmpl.generate(title='Hello, world!')
+  print(stream.render())
+
+See the `API documentation <api/index.html>`_ for details on using Genshi via
+the Python API.
+
+.. _`template loader`: loader.html
+
+.. _`expressions`:
+
+------------------------------------
+Template Expressions and Code Blocks
+------------------------------------
+
+Python_ expressions can be used in text and directive arguments. An expression
+is substituted with the result of its evaluation against the template data.
+Expressions in text (which includes the values of non-directive attributes) need
+to prefixed with a dollar sign (``$``) and usually enclosed in curly braces
+(``{&#8230;}``).
+
+.. _python: http://www.python.org/
+
+If the expression starts with a letter and contains only letters, digits, dots,
+and underscores, the curly braces may be omitted. In all other cases, the
+braces are required so that the template processor knows where the expression
+ends:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>')
+  >>> print(tmpl.generate(items=['first', 'second']))
+  <em>First item</em>
+
+Expressions support the full power of Python. In addition, it is possible to
+access items in a dictionary using &#8220;dotted notation&#8221; (i.e. as if they were
+attributes), and vice-versa (i.e. access attributes as if they were items in a
+dictionary):
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>')
+  >>> print(tmpl.generate(dict={'foo': 'bar'}))
+  <em>bar</em>
+
+Because there are two ways to access either attributes or items, expressions
+do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but
+rather an exception of the type ``UndefinedError``. The same kind of error is
+raised when you try to use a top-level variable that is not in the context data.
+See `Error Handling`_ below for details on how such errors are handled.
+
+
+Escaping
+========
+
+If you need to include a literal dollar sign in the output where Genshi would
+normally detect an expression, you can simply add another dollar sign:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<em>$foo</em>') # Wanted "$foo" as literal output
+  >>> print(tmpl.generate())
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "foo" not defined
+  >>> tmpl = MarkupTemplate('<em>$$foo</em>')
+  >>> print(tmpl.generate())
+  <em>$foo</em>
+
+But note that this is not necessary if the characters following the dollar sign
+do not qualify as an expression. For example, the following needs no escaping:
+
+.. code-block:: pycon
+
+  >>> tmpl = MarkupTemplate('<script>$(function() {})</script>')
+  >>> print(tmpl.generate())
+  <script>$(function() {})</script>
+
+On the other hand, Genshi will always replace two dollar signs in text with a
+single dollar sign, so you'll need to use three dollar signs to get two in the
+output:
+
+.. code-block:: pycon
+
+  >>> tmpl = MarkupTemplate('<script>$$$("div")</script>')
+  >>> print(tmpl.generate())
+  <script>$$("div")</script>
+
+
+.. _`code blocks`:
+
+Code Blocks
+===========
+
+Templates also support full Python code blocks, using the ``<?python ?>``
+processing instruction in XML templates:
+
+.. code-block:: genshi
+
+  <div>
+    <?python
+        from genshi.builder import tag
+        def greeting(name):
+            return tag.b('Hello, %s!' % name) ?>
+    ${greeting('world')}
+  </div>
+
+This will produce the following output:
+
+.. code-block:: xml
+
+  <div>
+    <b>Hello, world!</b>
+  </div>
+
+In text templates (although only those using the new syntax introduced in
+Genshi 0.5), code blocks use the special ``{% python %}`` directive:
+
+.. code-block:: genshitext
+
+  {% python
+      from genshi.builder import tag
+      def greeting(name):
+          return 'Hello, %s!' % name
+  %}
+  ${greeting('world')}
+
+This will produce the following output::
+
+  Hello, world!
+
+
+Code blocks can import modules, define classes and functions, and basically do
+anything you can do in normal Python code. What code blocks can *not* do is to
+produce content that is emitted directly tp the generated output.
+
+.. note:: Using the ``print`` statement will print to the standard output
+          stream, just as it does for other Python code in your application.
+
+Unlike expressions, Python code in ``<?python ?>`` processing instructions can
+not use item and attribute access in an interchangeable manner. That means that
+&#8220;dotted notation&#8221; is always attribute access, and vice-versa.
+
+The support for Python code blocks in templates is not supposed to encourage
+mixing application code into templates, which is generally considered bad
+design. If you're using many code blocks, that may be a sign that you should
+move such code into separate Python modules.
+
+If you'd rather not allow the use of Python code blocks in templates, you can
+simply set the ``allow_exec`` parameter (available on the ``Template`` and the
+``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise
+a syntax error when a ``<?python ?>`` processing instruction is encountered.
+But please note that disallowing code blocks in templates does not turn Genshi
+into a sandboxable template engine; there are sufficient ways to do harm even
+using plain expressions.
+
+
+.. _`error handling`:
+
+Error Handling
+==============
+
+By default, Genshi raises an ``UndefinedError`` if a template expression
+attempts to access a variable that is not defined:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh}</p>')
+  >>> tmpl.generate().render('xhtml')
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "doh" not defined
+
+You can change this behavior by setting the variable lookup mode to "lenient".
+In that case, accessing undefined variables returns an `Undefined` object,
+meaning that the expression does not fail immediately. See below for details.
+
+If you need to check whether a variable exists in the template context, use the
+defined_ or the value_of_ function described below. To check for existence of
+attributes on an object, or keys in a dictionary, use the ``hasattr()``,
+``getattr()`` or ``get()`` functions, or the ``in`` operator, just as you would
+in regular Python code:
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${defined("doh")}</p>')
+  >>> print(tmpl.generate().render('xhtml'))
+  <p>False</p>
+
+.. note:: Lenient error handling was the default in Genshi prior to version 0.5.
+          Strict mode was introduced in version 0.4, and became the default in
+          0.5. The reason for this change was that the lenient error handling
+          was masking actual errors in templates, thereby also making it harder
+          to debug some problems.
+
+
+.. _`lenient`:
+
+Lenient Mode
+------------
+
+If you instruct Genshi to use the lenient variable lookup mode, it allows you
+to access variables that are not defined, without raising an ``UndefinedError``.
+
+This mode can be chosen by passing the ``lookup='lenient'`` keyword argument to
+the template initializer, or by passing the ``variable_lookup='lenient'``
+keyword argument to the ``TemplateLoader`` initializer:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='lenient')
+  >>> print(tmpl.generate().render('xhtml'))
+  <p></p>
+
+You *will* however get an exception if you try to call an undefined variable, or
+do anything else with it, such as accessing its attributes:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>', lookup='lenient')
+  >>> print(tmpl.generate().render('xhtml'))
+  Traceback (most recent call last):
+    ...
+  UndefinedError: "doh" not defined
+
+If you need to know whether a variable is defined, you can check its type
+against the ``Undefined`` class, for example in a conditional directive:
+
+.. code-block:: pycon
+
+  >>> from genshi.template import MarkupTemplate
+  >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>',
+  ...                       lookup='lenient')
+  >>> print(tmpl.generate().render('xhtml'))
+  <p>False</p>
+
+Alternatively, the built-in functions defined_ or value_of_ can be used in this
+case.
+
+Custom Modes
+------------
+
+In addition to the built-in "lenient" and "strict" modes, it is also possible to
+use a custom error handling mode. For example, you could use lenient error
+handling in a production environment, while also logging a warning when an
+undefined variable is referenced.
+
+See the API documentation of the ``genshi.template.eval`` module for details.
+
+
+Built-in Functions & Types
+==========================
+
+The following functions and types are available by default in template code, in
+addition to the standard built-ins that are available to all Python code.
+
+.. _`defined`:
+
+``defined(name)``
+-----------------
+This function determines whether a variable of the specified name exists in
+the context data, and returns ``True`` if it does.
+ 
+.. _`value_of`:
+
+``value_of(name, default=None)``
+--------------------------------
+This function returns the value of the variable with the specified name if
+such a variable is defined, and returns the value of the ``default``
+parameter if no such variable is defined.
+
+.. _`Markup`:
+
+``Markup(text)``
+----------------
+The ``Markup`` type marks a given string as being safe for inclusion in markup,
+meaning it will *not* be escaped in the serialization stage. Use this with care,
+as not escaping a user-provided string may allow malicious users to open your
+web site to cross-site scripting attacks.
+
+.. _`Undefined`:
+
+``Undefined``
+----------------
+The ``Undefined`` type can be used to check whether a reference variable is
+defined, as explained in `error handling`_.
+
+
+.. _`directives`:
+
+-------------------
+Template Directives
+-------------------
+
+Directives provide control flow functionality for templates, such as conditions
+or iteration. As the syntax for directives depends on whether you're using
+markup or text templates, refer to the
+`XML Template Language <xml-templates.html>`_ or
+`Text Template Language <text-templates.html>`_ pages for information.
diff --git a/lib/genshi/doc/text-templates.txt b/lib/genshi/doc/text-templates.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/text-templates.txt
@@ -0,0 +1,360 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=============================
+Genshi Text Template Language
+=============================
+
+In addition to the XML-based template language, Genshi provides a simple
+text-based template language, intended for basic plain text generation needs.
+The language is similar to the Django_ template language.
+
+This document describes the template language and will be most useful as
+reference to those developing Genshi text templates. Templates are text files of
+some kind that include processing directives_ that affect how the template is
+rendered, and template expressions that are dynamically substituted by
+variable data.
+
+See `Genshi Templating Basics <templates.html>`_ for general information on
+embedding Python code in templates.
+
+.. note:: Actually, Genshi currently has two different syntaxes for text
+          templates languages: One implemented by the class ``OldTextTemplate``
+          and another implemented by ``NewTextTemplate``. This documentation
+          concentrates on the latter, which is planned to completely replace the
+          older syntax. The older syntax is briefly described under legacy_.
+
+.. _django: http://www.djangoproject.com/
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+
+.. _`directives`:
+
+-------------------
+Template Directives
+-------------------
+
+Directives are template commands enclosed by ``{% ... %}`` characters. They can
+affect how the template is rendered in a number of ways: Genshi provides
+directives for conditionals and looping, among others.
+
+Each directive must be terminated using an ``{% end %}`` marker. You can add
+a string inside the ``{% end %}`` marker, for example to document which
+directive is being closed, or even the expression associated with  that
+directive. Any text after ``end`` inside the delimiters is  ignored,  and
+effectively treated as a comment.
+
+If you want to include a literal delimiter in the output, you need to escape it
+by prepending a backslash character (``\``).
+
+
+Conditional Sections
+====================
+
+.. _`if`:
+
+``{% if %}``
+------------
+
+The content is only rendered if the expression evaluates to a truth value:
+
+.. code-block:: genshitext
+
+  {% if foo %}
+    ${bar}
+  {% end %}
+
+Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this
+would produce::
+
+    Hello
+
+
+.. _`choose`:
+.. _`when`:
+.. _`otherwise`:
+
+``{% choose %}``
+----------------
+
+The ``choose`` directive, in combination with the directives ``when`` and
+``otherwise``, provides advanced contional processing for rendering one of
+several alternatives. The first matching ``when`` branch is rendered, or, if
+no ``when`` branch matches, the ``otherwise`` branch is be rendered.
+
+If the ``choose`` directive has no argument the nested ``when`` directives will
+be tested for truth:
+
+.. code-block:: genshitext
+
+  The answer is:
+  {% choose %}
+    {% when 0 == 1 %}0{% end %}
+    {% when 1 == 1 %}1{% end %}
+    {% otherwise %}2{% end %}
+  {% end %}
+
+This would produce the following output::
+
+  The answer is:
+    1
+
+If the ``choose`` does have an argument, the nested ``when`` directives will
+be tested for equality to the parent ``choose`` value:
+
+.. code-block:: genshitext
+
+  The answer is:
+  {% choose 1 %}\
+    {% when 0 %}0{% end %}\
+    {% when 1 %}1{% end %}\
+    {% otherwise %}2{% end %}\
+  {% end %}
+
+This would produce the following output::
+
+  The answer is:
+      1
+
+
+Looping
+=======
+
+.. _`for`:
+
+``{% for %}``
+-------------
+
+The content is repeated for every item in an iterable:
+
+.. code-block:: genshitext
+
+  Your items:
+  {% for item in items %}\
+    * ${item}
+  {% end %}
+
+Given ``items=[1, 2, 3]`` in the context data, this would produce::
+
+  Your items
+    * 1
+    * 2
+    * 3
+
+
+Snippet Reuse
+=============
+
+.. _`def`:
+.. _`macros`:
+
+``{% def %}``
+-------------
+
+The ``def`` directive can be used to create macros, i.e. snippets of template
+text that have a name and optionally some parameters, and that can be inserted
+in other places:
+
+.. code-block:: genshitext
+
+  {% def greeting(name) %}
+    Hello, ${name}!
+  {% end %}
+  ${greeting('world')}
+  ${greeting('everyone else')}
+
+The above would be rendered to::
+
+    Hello, world!
+    Hello, everyone else!
+
+If a macro doesn't require parameters, it can be defined without the
+parenthesis. For example:
+
+.. code-block:: genshitext
+
+  {% def greeting %}
+    Hello, world!
+  {% end %}
+  ${greeting()}
+
+The above would be rendered to::
+
+    Hello, world!
+
+
+.. _includes:
+.. _`include`:
+
+``{% include %}``
+-----------------
+
+To reuse common parts of template text across template files, you can include
+other files using the ``include`` directive:
+
+.. code-block:: genshitext
+
+  {% include base.txt %}
+
+Any content included this way is inserted into the generated output. The
+included template sees the context data as it exists at the point of the
+include. `Macros`_ in the included template are also available to the including
+template after the point it was included.
+
+Include paths are relative to the filename of the template currently being
+processed. So if the example above was in the file "``myapp/mail.txt``"
+(relative to the template search path), the include directive would look for
+the included file at "``myapp/base.txt``". You can also use Unix-style
+relative paths, for example "``../base.txt``" to look in the parent directory.
+
+Just like other directives, the argument to the ``include`` directive accepts
+any Python expression, so the path to the included template can be determined
+dynamically:
+
+.. code-block:: genshitext
+
+  {% include ${'%s.txt' % filename} %}
+
+Note that a ``TemplateNotFound`` exception is raised if an included file can't
+be found.
+
+.. note:: The include directive for text templates was added in Genshi 0.5.
+
+
+Variable Binding
+================
+
+.. _`with`:
+
+``{% with %}``
+--------------
+
+The ``{% with %}`` directive lets you assign expressions to variables, which can
+be used to make expressions inside the directive less verbose and more
+efficient. For example, if you need use the expression ``author.posts`` more
+than once, and that actually results in a database query, assigning the results
+to a variable using this directive would probably help.
+
+For example:
+
+.. code-block:: genshitext
+
+  Magic numbers!
+  {% with y=7; z=x+10 %}
+    $x $y $z
+  {% end %}
+
+Given ``x=42`` in the context data, this would produce::
+
+  Magic numbers!
+    42 7 52
+
+Note that if a variable of the same name already existed outside of the scope
+of the ``with`` directive, it will **not** be overwritten. Instead, it will
+have the same value it had prior to the ``with`` assignment. Effectively,
+this means that variables are immutable in Genshi.
+
+
+.. _whitespace:
+
+---------------------------
+White-space and Line Breaks
+---------------------------
+
+Note that space or line breaks around directives is never automatically removed.
+Consider the following example:
+
+.. code-block:: genshitext
+
+  {% for item in items %}
+    {% if item.visible %}
+      ${item}
+    {% end %}
+  {% end %}
+
+This will result in two empty lines above and beneath every item, plus the
+spaces used for indentation. If you want to supress a line break, simply end
+the line with a backslash:
+
+.. code-block:: genshitext
+
+  {% for item in items %}\
+    {% if item.visible %}\
+      ${item}
+    {% end %}\
+  {% end %}\
+
+Now there would be no empty lines between the items in the output. But you still
+get the spaces used for indentation, and because the line breaks are removed,
+they actually continue and add up between lines. There are numerous ways to
+control white-space in the output while keeping the template readable, such as
+moving the indentation into the delimiters, or moving the end delimiter on the
+next line, and so on.
+
+
+.. _comments:
+
+--------
+Comments
+--------
+
+Parts in templates can be commented out using the delimiters ``{# ... #}``.
+Any content in comments are removed from the output.
+
+.. code-block:: genshitext
+
+  {# This won't end up in the output #}
+  This will.
+
+Just like directive delimiters, these can be escaped by prefixing with a
+backslash.
+
+.. code-block:: genshitext
+
+  \{# This *will* end up in the output, including delimiters #}
+  This too.
+
+
+.. _legacy:
+
+---------------------------
+Legacy Text Template Syntax
+---------------------------
+
+The syntax for text templates was redesigned in version 0.5 of Genshi to make
+the language more flexible and powerful. The older syntax is based on line
+starting with dollar signs, similar to e.g. Cheetah_ or Velocity_.
+
+.. _cheetah: http://cheetahtemplate.org/
+.. _velocity: http://jakarta.apache.org/velocity/
+
+A simple template using the old syntax looked like this:
+
+.. code-block:: genshitext
+
+  Dear $name,
+  
+  We have the following items for you:
+  #for item in items
+   * $item
+  #end
+  
+  All the best,
+  Foobar
+
+Beyond the requirement of putting directives on separate lines prefixed with
+dollar signs, the language itself is very similar to the new one. Except that
+comments are lines that start with two ``#`` characters, and a line-break at the
+end of a directive is removed automatically.
+
+.. note:: If you're using this old syntax, it is strongly recommended to
+          migrate to the new syntax. Simply replace any references to
+          ``TextTemplate`` by ``NewTextTemplate`` (and also change the
+          text templates, of course). On the other hand, if you want to stick
+          with the old syntax for a while longer, replace references to
+          ``TextTemplate`` by ``OldTextTemplate``; while ``TextTemplate`` is
+          still an alias for the old language at this point, that will change
+          in a future release. But also note that the old syntax may be
+          dropped entirely in a future release.
diff --git a/lib/genshi/doc/upgrade.txt b/lib/genshi/doc/upgrade.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/upgrade.txt
@@ -0,0 +1,176 @@
+================
+Upgrading Genshi
+================
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+------------------------------------------------------
+Upgrading from Genshi 0.6.x to the development version
+------------------------------------------------------
+
+The Genshi development version now supports both Python 2 and Python 3.
+
+The most noticable API change in the Genshi development version is that the
+default encoding in numerous places is now None (i.e. unicode) instead
+of UTF-8. This change was made in order to ease the transition to Python 3
+where strings are unicode strings by default.
+
+If your application relies on the default UTF-8 encoding a simple way to
+have it work both with Genshi 0.6.x and the development version is to specify the
+encoding explicitly in calls to the following classes, methods and functions:
+
+* genshi.HTML
+* genshi.Stream.render
+* genshi.input.HTMLParser
+* genshi.template.MarkupTemplate
+* genshi.template.TemplateLoader
+* genshi.template.TextTemplate (and genshi.template.NewTextTemplate)
+* genshi.template.OldTextTemplate
+
+Whether you explicitly specify UTF-8 or explicitly specify None (unicode) is
+a matter of personal taste, although working with unicode may make porting
+your own application to Python 3 easier.
+
+
+------------------------------------
+Upgrading from Genshi 0.5.x to 0.6.x
+------------------------------------
+
+Required Python Version
+-----------------------
+
+Support for Python 2.3 has been dropped in this release. Python 2.4 is
+now the minimum version of Python required to run Genshi.
+
+The XPath engine has been completely overhauled for this version. Some
+patterns that previously matched incorrectly will no longer match, and
+the other way around. In such cases, the XPath expressions need to be
+fixed in your application and templates.
+
+
+------------------------------------
+Upgrading from Genshi 0.4.x to 0.5.x
+------------------------------------
+
+Error Handling
+--------------
+
+The default error handling mode has been changed to "strict". This
+means that accessing variables not defined in the template data will
+now generate an immediate exception, as will accessing object
+attributes or dictionary keys that don't exist. If your templates rely
+on the old lenient behavior, you can configure Genshi to use that
+instead. See the documentation for details on how to do that. But be
+warned that lenient error handling may be removed completely in a
+future release.
+
+Match Template Processing
+-------------------------
+
+There has also been a subtle change to how ``py:match`` templates are
+processed: in previous versions, all match templates would be applied
+to the content generated by the matching template, and only the
+matching template itself was applied recursively to the original
+content. This behavior resulted in problems with many kinds of
+recursive matching, and hence was changed for 0.5: now, all match
+templates declared before the matching template are applied to the
+original content, and match templates declared after the matching
+template are applied to the generated content. This change should not
+have any effect on most applications, but you may want to check your
+use of match templates to make sure.
+
+Text Templates
+--------------
+
+Genshi 0.5 introduces a new, alternative syntax for text templates,
+which is more flexible and powerful compared to the old syntax. For
+backwards compatibility, this new syntax is not used by default,
+though it will be in a future version. It is recommended that you
+migrate to using this new syntax. To do so, simply rename any
+references in your code to ``TextTemplate`` to ``NewTextTemplate``. To
+explicitly use the old syntax, use ``OldTextTemplate`` instead, so
+that you can be sure you'll be using the same language when the
+default in Genshi is changed (at least until the old implementation is
+completely removed).
+
+``Markup`` Constructor
+----------------------
+
+The ``Markup`` class no longer has a specialized constructor. The old
+(undocumented) constructor provided a shorthand for doing positional
+substitutions. If you have code like this:
+
+.. code-block:: python
+
+  Markup('<b>%s</b>', name)
+
+You must replace it by the more explicit:
+
+.. code-block:: python
+
+  Markup('<b>%s</b>') % name
+
+``Template`` Constructor
+------------------------
+
+The constructor of the ``Template`` class and its subclasses has changed
+slightly: instead of the optional ``basedir`` parameter, it now expects
+an (also optional) ``filepath`` parameter, which specifies the absolute
+path to the template. You probably aren't using those constructors
+directly, anyway, but using the ``TemplateLoader`` API instead.
+
+
+------------------------------------
+Upgrading from Genshi 0.3.x to 0.4.x
+------------------------------------
+
+The modules ``genshi.filters`` and ``genshi.template`` have been
+refactored into packages containing multiple modules. While code using
+the regular APIs should continue to work without problems, you should
+make sure to remove any leftover traces of the files ``filters.py``
+and ``template.py`` in the ``genshi`` package on the installation
+path (including the corresponding ``.pyc`` files). This is not
+necessary when Genshi was installed as a Python egg.
+
+Results of evaluating template expressions are no longer implicitly
+called if they are callable. If you have been using that feature, you
+will need to add the parenthesis to actually call the function.
+
+Instances of ``genshi.core.Attrs`` are now immutable. Filters
+manipulating the attributes in a stream may need to be updated. Also,
+the ``Attrs`` class no longer automatically wraps all attribute names
+in ``QName`` objects, so users of the ``Attrs`` class need to do this
+themselves. See the documentation of the ``Attrs`` class for more
+information.
+
+
+---------------------
+Upgrading from Markup
+---------------------
+
+Prior to version 0.3, the name of the Genshi project was "Markup". The
+name change means that you will have to adjust your import statements
+and the namespace URI of XML templates, among other things:
+
+* The package name was changed from "markup" to "genshi". Please
+  adjust any import statements referring to the old package name.
+* The namespace URI for directives in Genshi XML templates has changed
+  from ``http://markup.edgewall.org/`` to
+  ``http://genshi.edgewall.org/``. Please update the ``xmlns:py``
+  declaration in your template files accordingly.
+
+Furthermore, due to the inclusion of a text-based template language,
+the class::
+
+  markup.template.Template
+
+has been renamed to::
+
+  genshi.template.MarkupTemplate
+
+If you've been using the Template class directly, you'll need to
+update your code (a simple find/replace should do&#8212;the API itself
+did not change).
diff --git a/lib/genshi/doc/xml-templates.txt b/lib/genshi/doc/xml-templates.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/xml-templates.txt
@@ -0,0 +1,702 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+============================
+Genshi XML Template Language
+============================
+
+Genshi provides a XML-based template language that is heavily inspired by Kid_,
+which in turn was inspired by a number of existing template languages, namely
+XSLT_, TAL_, and PHP_.
+
+.. _kid: http://kid-templating.org/
+.. _python: http://www.python.org/
+.. _xslt: http://www.w3.org/TR/xslt
+.. _tal: http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL
+.. _php: http://www.php.net/
+
+This document describes the template language and will be most useful as
+reference to those developing Genshi XML templates. Templates are XML files of
+some kind (such as XHTML) that include processing directives_ (elements or
+attributes identified by a separate namespace) that affect how the template is
+rendered, and template expressions that are dynamically substituted by
+variable data.
+
+See `Genshi Templating Basics <templates.html>`_ for general information on
+embedding Python code in templates.
+
+
+.. contents:: Contents
+   :depth: 3
+.. sectnum::
+
+
+.. _`directives`:
+
+-------------------
+Template Directives
+-------------------
+
+Directives are elements and/or attributes in the template that are identified
+by the namespace ``http://genshi.edgewall.org/``. They can affect how the
+template is rendered in a number of ways: Genshi provides directives for
+conditionals and looping, among others.
+
+To use directives in a template, the namespace must be declared, which is
+usually done on the root element:
+
+.. code-block:: genshi
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:py="http://genshi.edgewall.org/"
+        lang="en">
+    ...
+  </html>
+
+In this example, the default namespace is set to the XHTML namespace, and the
+namespace for Genshi directives is bound to the prefix &#8220;py&#8221;.
+
+All directives can be applied as attributes, and some can also be used as
+elements. The ``if`` directives for conditionals, for example, can be used in
+both ways:
+
+.. code-block:: genshi
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:py="http://genshi.edgewall.org/"
+        lang="en">
+    ...
+    <div py:if="foo">
+      <p>Bar</p>
+    </div>
+    ...
+  </html>
+
+This is basically equivalent to the following:
+
+.. code-block:: genshi
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:py="http://genshi.edgewall.org/"
+        lang="en">
+    ...
+    <py:if test="foo">
+      <div>
+        <p>Bar</p>
+      </div>
+    </py:if>
+    ...
+  </html>
+
+The rationale behind the second form is that directives do not always map
+naturally to elements in the template. In such cases, the ``py:strip``
+directive can be used to strip off the unwanted element, or the directive can
+simply be used as an element.
+
+
+Conditional Sections
+====================
+
+.. _`py:if`:
+
+``py:if``
+---------
+
+The element and its content is only rendered if the expression evaluates to a
+truth value:
+
+.. code-block:: genshi
+
+  <div>
+    <b py:if="foo">${bar}</b>
+  </div>
+
+Given the data ``foo=True`` and ``bar='Hello'`` in the template context, this
+would produce:
+
+.. code-block:: xml
+
+  <div>
+    <b>Hello</b>
+  </div>
+
+But setting ``foo=False`` would result in the following output:
+
+.. code-block:: xml
+
+  <div>
+  </div>
+
+This directive can also be used as an element:
+
+.. code-block:: genshi
+
+  <div>
+    <py:if test="foo">
+      <b>${bar}</b>
+    </py:if>
+  </div>
+
+.. _`py:choose`:
+.. _`py:when`:
+.. _`py:otherwise`:
+
+``py:choose``
+-------------
+
+The ``py:choose`` directive, in combination with the directives ``py:when``
+and ``py:otherwise`` provides advanced conditional processing for rendering one
+of several alternatives. The first matching ``py:when`` branch is rendered, or,
+if no ``py:when`` branch matches, the ``py:otherwise`` branch is rendered.
+
+If the ``py:choose`` directive is empty the nested ``py:when`` directives will
+be tested for truth:
+
+.. code-block:: genshi
+
+  <div py:choose="">
+    <span py:when="0 == 1">0</span>
+    <span py:when="1 == 1">1</span>
+    <span py:otherwise="">2</span>
+  </div>
+
+This would produce the following output:
+
+.. code-block:: xml
+
+  <div>
+    <span>1</span>
+  </div>
+
+If the ``py:choose`` directive contains an expression the nested ``py:when``
+directives will be tested for equality to the parent ``py:choose`` value:
+
+.. code-block:: genshi
+
+  <div py:choose="1">
+    <span py:when="0">0</span>
+    <span py:when="1">1</span>
+    <span py:otherwise="">2</span>
+  </div>
+
+This would produce the following output:
+
+.. code-block:: xml
+
+  <div>
+    <span>1</span>
+  </div>
+
+These directives can also be used as elements:
+
+.. code-block:: genshi
+
+  <py:choose test="1">
+    <py:when test="0">0</py:when>
+    <py:when test="1">1</py:when>
+    <py:otherwise>2</py:otherwise>
+  </py:choose>
+
+Looping
+=======
+
+.. _`py:for`:
+
+``py:for``
+----------
+
+The element is repeated for every item in an iterable:
+
+.. code-block:: genshi
+
+  <ul>
+    <li py:for="item in items">${item}</li>
+  </ul>
+
+Given ``items=[1, 2, 3]`` in the context data, this would produce:
+
+.. code-block:: xml
+
+  <ul>
+    <li>1</li><li>2</li><li>3</li>
+  </ul>
+
+This directive can also be used as an element:
+
+.. code-block:: genshi
+
+  <ul>
+    <py:for each="item in items">
+      <li>${item}</li>
+    </py:for>
+  </ul>
+
+
+Snippet Reuse
+=============
+
+.. _`py:def`:
+.. _`macros`:
+
+``py:def``
+----------
+
+The ``py:def`` directive can be used to create macros, i.e. snippets of
+template code that have a name and optionally some parameters, and that can be
+inserted in other places:
+
+.. code-block:: genshi
+
+  <div>
+    <p py:def="greeting(name)" class="greeting">
+      Hello, ${name}!
+    </p>
+    ${greeting('world')}
+    ${greeting('everyone else')}
+  </div>
+
+The above would be rendered to:
+
+.. code-block:: xml
+
+  <div>
+    <p class="greeting">
+      Hello, world!
+    </p>
+    <p class="greeting">
+      Hello, everyone else!
+    </p>
+  </div>
+
+If a macro doesn't require parameters, it can be defined without the 
+parenthesis. For example:
+
+.. code-block:: genshi
+
+  <div>
+    <p py:def="greeting" class="greeting">
+      Hello, world!
+    </p>
+    ${greeting()}
+  </div>
+
+The above would be rendered to:
+
+.. code-block:: xml
+
+  <div>
+    <p class="greeting">
+      Hello, world!
+    </p>
+  </div>
+
+This directive can also be used as an element:
+
+.. code-block:: genshi
+
+  <div>
+    <py:def function="greeting(name)">
+      <p class="greeting">Hello, ${name}!</p>
+    </py:def>
+  </div>
+
+
+.. _Match Templates:
+.. _`py:match`:
+
+``py:match``
+------------
+
+This directive defines a *match template*: given an XPath expression, it
+replaces any element in the template that matches the expression with its own
+content.
+
+For example, the match template defined in the following template matches any
+element with the tag name &#8220;greeting&#8221;:
+
+.. code-block:: genshi
+
+  <div>
+    <span py:match="greeting">
+      Hello ${select('@name')}
+    </span>
+    <greeting name="Dude" />
+  </div>
+
+This would result in the following output:
+
+.. code-block:: xml
+
+  <div>
+    <span>
+      Hello Dude
+    </span>
+  </div>
+
+Inside the body of a ``py:match`` directive, the ``select(path)`` function is
+made available so that parts or all of the original element can be incorporated
+in the output of the match template. See `Using XPath`_ for more information
+about this function.
+
+.. _`Using XPath`: streams.html#using-xpath
+
+Match templates are applied both to the original markup as well to the
+generated markup. The order in which they are applied depends on the order
+they are declared in the template source: a match template defined after
+another match template is applied to the output generated by the first match
+template. The match templates basically form a pipeline.
+
+This directive can also be used as an element:
+
+.. code-block:: genshi
+
+  <div>
+    <py:match path="greeting">
+      <span>Hello ${select('@name')}</span>
+    </py:match>
+    <greeting name="Dude" />
+  </div>
+
+When used this way, the ``py:match`` directive can also be annotated with a
+couple of optimization hints. For example, the following informs the matching
+engine that the match should only be applied once:
+
+.. code-block:: genshi
+
+  <py:match path="body" once="true">
+    <body py:attrs="select('@*')">
+      <div id="header">...</div>
+      ${select("*|text()")}
+      <div id="footer">...</div>
+    </body>
+  </py:match>
+
+The following optimization hints are recognized:
+
++---------------+-----------+-----------------------------------------------+
+| Attribute     | Default   | Description                                   |
++===============+===========+===============================================+
+| ``buffer``    | ``true``  | Whether the matched content should be         |
+|               |           | buffered in memory. Buffering can improve     |
+|               |           | performance a bit at the cost of needing more |
+|               |           | memory during rendering. Buffering is         |
+|               |           | ''required'' for match templates that contain |
+|               |           | more than one invocation of the ``select()``  |
+|               |           | function. If there is only one call, and the  |
+|               |           | matched content can potentially be very long, |
+|               |           | consider disabling buffering to avoid         |
+|               |           | excessive memory use.                         |
++---------------+-----------+-----------------------------------------------+
+| ``once``      | ``false`` | Whether the engine should stop looking for    |
+|               |           | more matching elements after the first match. |
+|               |           | Use this on match templates that match        |
+|               |           | elements that can only occur once in the      |
+|               |           | stream, such as the ``<head>`` or ``<body>``  |
+|               |           | elements in an HTML template, or elements     |
+|               |           | with a specific ID.                           |
++---------------+-----------+-----------------------------------------------+
+| ``recursive`` | ``true``  | Whether the match template should be applied  |
+|               |           | to its own output. Note that ``once`` implies |
+|               |           | non-recursive behavior, so this attribute     |
+|               |           | only needs to be set for match templates that |
+|               |           | don't also have ``once`` set.                 |
++---------------+-----------+-----------------------------------------------+
+
+.. note:: The ``py:match`` optimization hints were added in the 0.5 release. In
+          earlier versions, the attributes have no effect.
+
+
+Variable Binding
+================
+
+.. _`with`:
+
+``py:with``
+-----------
+
+The ``py:with`` directive lets you assign expressions to variables, which can
+be used to make expressions inside the directive less verbose and more
+efficient. For example, if you need use the expression ``author.posts`` more
+than once, and that actually results in a database query, assigning the results
+to a variable using this directive would probably help.
+
+For example:
+
+.. code-block:: genshi
+
+  <div>
+    <span py:with="y=7; z=x+10">$x $y $z</span>
+  </div>
+
+Given ``x=42`` in the context data, this would produce:
+
+.. code-block:: xml
+
+  <div>
+    <span>42 7 52</span>
+  </div>
+
+This directive can also be used as an element:
+
+.. code-block:: genshi
+
+  <div>
+    <py:with vars="y=7; z=x+10">$x $y $z</py:with>
+  </div>
+
+Note that if a variable of the same name already existed outside of the scope
+of the ``py:with`` directive, it will **not** be overwritten. Instead, it
+will have the same value it had prior to the ``py:with`` assignment.
+Effectively, this means that variables are immutable in Genshi.
+
+
+Structure Manipulation
+======================
+
+.. _`py:attrs`:
+
+``py:attrs``
+------------
+
+This directive adds, modifies or removes attributes from the element:
+
+.. code-block:: genshi
+
+  <ul>
+    <li py:attrs="foo">Bar</li>
+  </ul>
+
+Given ``foo={'class': 'collapse'}`` in the template context, this would
+produce:
+
+.. code-block:: xml
+
+  <ul>
+    <li class="collapse">Bar</li>
+  </ul>
+
+Attributes with the value ``None`` are omitted, so given ``foo={'class': None}``
+in the context for the same template this would produce:
+
+.. code-block:: xml
+
+  <ul>
+    <li>Bar</li>
+  </ul>
+
+This directive can only be used as an attribute.
+
+
+.. _`py:content`:
+
+``py:content``
+--------------
+
+This directive replaces any nested content with the result of evaluating the
+expression:
+
+.. code-block:: genshi
+
+  <ul>
+    <li py:content="bar">Hello</li>
+  </ul>
+
+Given ``bar='Bye'`` in the context data, this would produce:
+
+.. code-block:: xml
+
+  <ul>
+    <li>Bye</li>
+  </ul>
+
+This directive can only be used as an attribute.
+
+
+.. _`py:replace`:
+
+``py:replace``
+--------------
+
+This directive replaces the element itself with the result of evaluating the
+expression:
+
+.. code-block:: genshi
+
+  <div>
+    <span py:replace="bar">Hello</span>
+  </div>
+
+Given ``bar='Bye'`` in the context data, this would produce:
+
+.. code-block:: xml
+
+  <div>
+    Bye
+  </div>
+
+This directive can also be used as an element (since version 0.5):
+
+.. code-block:: genshi
+
+  <div>
+    <py:replace value="title">Placeholder</py:replace>
+  </div>
+
+
+
+.. _`py:strip`:
+
+``py:strip``
+------------
+
+This directive conditionally strips the top-level element from the output. When
+the value of the ``py:strip`` attribute evaluates to ``True``, the element is
+stripped from the output:
+
+.. code-block:: genshi
+
+  <div>
+    <div py:strip="True"><b>foo</b></div>
+  </div>
+
+This would be rendered as:
+
+.. code-block:: xml
+
+  <div>
+    <b>foo</b>
+  </div>
+
+As a shorthand, if the value of the ``py:strip`` attribute is empty, that has
+the same effect as using a truth value (i.e. the element is stripped).
+
+
+.. _order:
+
+Processing Order
+================
+
+It is possible to attach multiple directives to a single element, although not
+all combinations make sense. When multiple directives are encountered, they are
+processed in the following order:
+
+#. `py:def`_
+#. `py:match`_
+#. `py:when`_
+#. `py:otherwise`_
+#. `py:for`_
+#. `py:if`_
+#. `py:choose`_
+#. `py:with`_
+#. `py:replace`_
+#. `py:content`_
+#. `py:attrs`_
+#. `py:strip`_
+
+
+.. _includes:
+
+--------
+Includes
+--------
+
+To reuse common snippets of template code, you can include other files using
+XInclude_.
+
+.. _xinclude: http://www.w3.org/TR/xinclude/
+
+For this, you need to declare the XInclude namespace (commonly bound to the
+prefix &#8220;xi&#8221;) and use the ``<xi:include>`` element where you want the external
+file to be pulled in:
+
+.. code-block:: genshi
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:py="http://genshi.edgewall.org/"
+        xmlns:xi="http://www.w3.org/2001/XInclude">
+    <xi:include href="base.html" />
+    ...
+  </html>
+
+Include paths are relative to the filename of the template currently being
+processed. So if the example above was in the file "``myapp/index.html``"
+(relative to the template search path), the XInclude processor would look for
+the included file at "``myapp/base.html``". You can also use Unix-style
+relative paths, for example "``../base.html``" to look in the parent directory.
+
+Any content included this way is inserted into the generated output instead of
+the ``<xi:include>`` element. The included template sees the same context data.
+`Match templates`_ and `macros`_ in the included template are also available to
+the including template after the point it was included.
+
+By default, an error will be raised if an included file is not found. If that's
+not what you want, you can specify fallback content that should be used if the
+include fails. For example, to to make the include above fail silently, you'd
+write:
+
+.. code-block:: genshi
+
+  <xi:include href="base.html"><xi:fallback /></xi:include>
+
+See the `XInclude specification`_ for more about fallback content. Note though 
+that Genshi currently only supports a small subset of XInclude.
+
+.. _`xinclude specification`: http://www.w3.org/TR/xinclude/
+
+
+Dynamic Includes
+================
+
+Incudes in Genshi are fully dynamic: Just like normal attributes, the `href`
+attribute accepts expressions, and directives_ can be used on the
+``<xi:include />`` element just as on any other element, meaning you can do
+things like conditional includes:
+
+.. code-block:: genshi
+
+  <xi:include href="${name}.html" py:if="not in_popup"
+              py:for="name in ('foo', 'bar', 'baz')" />
+
+
+Including Text Templates
+========================
+
+The ``parse`` attribute of the ``<xi:include>`` element can be used to specify
+whether the included template is an XML template or a text template (using the
+new syntax added in Genshi 0.5):
+
+.. code-block:: genshi
+
+  <xi:include href="myscript.js" parse="text" />
+
+This example would load the ``myscript.js`` file as a ``NewTextTemplate``. See
+`text templates`_ for details on the syntax of text templates.
+
+.. _`text templates`: text-templates.html
+
+
+.. _comments:
+
+--------
+Comments
+--------
+
+Normal XML/HTML comment syntax can be used in templates:
+
+.. code-block:: genshi
+
+  <!-- this is a comment -->
+
+However, such comments get passed through the processing pipeline and are by
+default included in the final output. If that's not desired, prefix the comment
+text with an exclamation mark:
+
+.. code-block:: genshi
+
+  <!-- !this is a comment too, but one that will be stripped from the output -->
+
+Note that it does not matter whether there's whitespace before or after the
+exclamation mark, so the above could also be written as follows:
+
+.. code-block:: genshi
+
+  <!--! this is a comment too, but one that will be stripped from the output -->
diff --git a/lib/genshi/doc/xpath.txt b/lib/genshi/doc/xpath.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/doc/xpath.txt
@@ -0,0 +1,101 @@
+.. -*- mode: rst; encoding: utf-8 -*-
+
+=====================
+Using XPath in Genshi
+=====================
+
+Genshi provides basic XPath_ support for matching and querying event streams.
+
+.. _xpath: http://www.w3.org/TR/xpath
+
+
+.. contents:: Contents
+   :depth: 2
+.. sectnum::
+
+
+-----------
+Limitations
+-----------
+
+Due to the streaming nature of the processing model, Genshi uses only a subset
+of the `XPath 1.0`_ language.
+
+.. _`XPath 1.0`: http://www.w3.org/TR/xpath
+
+In particular, only the following axes are supported:
+
+* ``attribute``
+* ``child``
+* ``descendant``
+* ``descendant-or-self``
+* ``self``
+
+This means you can't use the ``parent``, ancestor, or sibling axes in Genshi
+(the ``namespace`` axis isn't supported either, but what you'd ever need that
+for I don't know). Basically, any path expression that would require buffering
+of the stream is not supported.
+
+Predicates are of course supported, but path expressions *inside* predicates
+are restricted to attribute lookups (again due to the lack of buffering).
+
+Most of the XPath functions and operators are supported, however they
+(currently) only work inside predicates. The following functions are **not**
+supported:
+
+* ``count()``
+* ``id()``
+* ``lang()``
+* ``last()``
+* ``position()``
+* ``string()``
+* ``sum()``
+
+The mathematical operators (``+``, ``-``, ``*``, ``div``, and ``mod``) are not
+yet supported, whereas sub-expressions and the various comparison and logical
+operators should work as expected.
+
+You can also use XPath variable references (``$var``) inside predicates.
+
+
+----------------
+Querying Streams
+----------------
+
+The ``Stream`` class provides a ``select(path)`` function that can be used to
+retrieve subsets of the stream:
+
+.. code-block:: pycon
+
+  >>> from genshi.input import XML
+
+  >>> doc = XML('''<doc>
+  ...  <items count="4">
+  ...       <item status="new">
+  ...         <summary>Foo</summary>
+  ...       </item>
+  ...       <item status="closed">
+  ...         <summary>Bar</summary>
+  ...       </item>
+  ...       <item status="closed" resolution="invalid">
+  ...         <summary>Baz</summary>
+  ...       </item>
+  ...       <item status="closed" resolution="fixed">
+  ...         <summary>Waz</summary>
+  ...       </item>
+  ...   </items>
+  ... </doc>''')
+
+  >>> print(doc.select('items/item[@status="closed" and '
+  ...     '(@resolution="invalid" or not(@resolution))]/summary/text()'))
+  BarBaz
+
+
+
+---------------------
+Matching in Templates
+---------------------
+
+See the directive ``py:match`` in the `XML Template Language Specification`_.
+
+.. _`XML Template Language Specification`: xml-templates.html
diff --git a/lib/genshi/examples/basic/kidrun.py b/lib/genshi/examples/basic/kidrun.py
new file mode 100755
--- /dev/null
+++ b/lib/genshi/examples/basic/kidrun.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import time
+
+import kid
+
+def test():
+    base_path = os.path.dirname(os.path.abspath(__file__))
+    kid.path = kid.TemplatePath([base_path])
+
+    ctxt = dict(hello='<world>', hey='ZYX', bozz=None,
+                items=['Number %d' % num for num in range(1, 15)],
+                prefix='#')
+
+    start = time.clock()
+    template = kid.Template(file='test.kid', **ctxt)
+    print ' --> parse stage: %.4f ms' % ((time.clock() - start) * 1000)
+
+    for output in template.generate():
+        sys.stdout.write(output)
+    print
+
+    times = []
+    for i in range(1000):
+        start = time.clock()
+        list(template.generate())
+        times.append(time.clock() - start)
+        sys.stdout.write('.')
+        sys.stdout.flush()
+    print
+
+    print ' --> render stage: %s ms (average)' % (
+          (sum(times) / len(times) * 1000))
+
+if __name__ == '__main__':
+    if '-p' in sys.argv:
+        import hotshot, hotshot.stats
+        prof = hotshot.Profile("template.prof")
+        benchtime = prof.runcall(test)
+        stats = hotshot.stats.load("template.prof")
+        stats.strip_dirs()
+        stats.sort_stats('time', 'calls')
+        stats.print_stats()
+    else:
+        test()
diff --git a/lib/genshi/examples/basic/layout.html b/lib/genshi/examples/basic/layout.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/basic/layout.html
@@ -0,0 +1,15 @@
+<div xmlns:py="http://genshi.edgewall.org/" py:strip="">
+  <head>
+    <title>Hello ${hello}</title>
+    <style type="text/css">@import(style.css)</style>
+  </head>
+  <div py:def="macro1">reference me, please</div>
+  <div py:def="macro2(name, classname='expanded')" class="${classname}">
+    Hello ${name.title()}
+  </div>
+  <span py:match="greeting" class="greeting">
+    Hello ${select('@name')}
+  </span>
+  <span py:match="span[@class='greeting']" style="text-decoration: underline" 
+        py:content="select('text()')"/>
+</div>
diff --git a/lib/genshi/examples/basic/layout.kid b/lib/genshi/examples/basic/layout.kid
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/basic/layout.kid
@@ -0,0 +1,15 @@
+<div xmlns:py="http://purl.org/kid/ns#" py:strip="">
+  <head>
+    <title>Hello ${hello}</title>
+    <style type="text/css">@import(style.css)</style>
+  </head>
+  <div py:def="macro1">reference me, please</div>
+  <div py:def="macro2(name, classname='expanded')" class="${classname}">
+    Hello ${name.title()}
+  </div>
+  <span py:match="item.tag == '{http://www.w3.org/1999/xhtml}greeting'" class="greeting">
+    Hello ${item.get('name')}
+  </span>
+  <span py:match="item.tag == '{http://www.w3.org/1999/xhtml}span' and item.get('class') == 'greeting'"
+        py:content="item.text" style="text-decoration: underline" />
+</div>
diff --git a/lib/genshi/examples/basic/run.py b/lib/genshi/examples/basic/run.py
new file mode 100755
--- /dev/null
+++ b/lib/genshi/examples/basic/run.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+import time
+
+from genshi.template import TemplateLoader
+
+def test():
+    base_path = os.path.dirname(os.path.abspath(__file__))
+    loader = TemplateLoader([base_path], auto_reload=True)
+
+    start = time.clock()
+    tmpl = loader.load('test.html')
+    print ' --> parse stage: %.4f ms' % ((time.clock() - start) * 1000)
+
+    data = dict(hello='<world>', skin='default', hey='ZYX', bozz=None,
+                items=['Number %d' % num for num in range(1, 15)],
+                prefix='#')
+
+    print tmpl.generate(**data).render(method='html')
+
+    times = []
+    for i in range(1000):
+        start = time.clock()
+        list(tmpl.generate(**data))
+        times.append(time.clock() - start)
+        sys.stdout.write('.')
+        sys.stdout.flush()
+    print
+
+    print ' --> render stage: %s ms (average)' % (
+          (sum(times) / len(times) * 1000))
+
+if __name__ == '__main__':
+    if '-p' in sys.argv:
+        import hotshot, hotshot.stats
+        prof = hotshot.Profile("template.prof")
+        benchtime = prof.runcall(test)
+        stats = hotshot.stats.load("template.prof")
+        stats.strip_dirs()
+        stats.sort_stats('time', 'calls')
+        stats.print_stats()
+    else:
+        test()
diff --git a/lib/genshi/examples/basic/test.html b/lib/genshi/examples/basic/test.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/basic/test.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      lang="en">
+ <xi:include href="layout.html" />
+ <xi:include href="custom_stuff.html"><xi:fallback/></xi:include>
+ <body class="$bozz">
+  <ul py:attrs="{'id': 'second', 'class': None}" py:if="len(items) > 0">
+   <li py:for="item in items">Item $prefix${item.split()[-1]}</li>
+  </ul>
+  ${macro1()} ${macro1()} ${macro1()}
+  ${macro2('john')}
+  ${macro2('kate', classname='collapsed')}
+  <div py:content="macro2('helmut')" py:strip="">Replace me</div>
+  <greeting name="Dude" />
+  <greeting name="King" />
+  <span class="greeting">Hello Silicon</span>
+ </body>
+</html>
diff --git a/lib/genshi/examples/basic/test.kid b/lib/genshi/examples/basic/test.kid
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/basic/test.kid
@@ -0,0 +1,21 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://purl.org/kid/ns#"
+      py:extends="'layout.kid'"
+      lang="en">
+ <body class="${bozz}">
+  <ul py:attrs="{'id': 'second', 'class': None}" py:if="len(items) > 0">
+   <li py:for="item in items">Item $prefix${item.split()[-1]}</li>
+   XYZ ${hey}
+  </ul>
+  ${macro1()} ${macro1()} ${macro1()}
+  ${macro2('john')}
+  ${macro2('kate', classname='collapsed')}
+  <div py:content="macro2('helmut')" py:strip="">Replace me</div>
+  <greeting name="Dude" />
+  <greeting name="King" />
+  <span class="greeting">Hello Silicon</span>
+ </body>
+</html>
diff --git a/lib/genshi/examples/bench/basic.py b/lib/genshi/examples/bench/basic.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/basic.py
@@ -0,0 +1,204 @@
+# -*- encoding: utf-8 -*-
+# Template language benchmarks
+#
+# Objective: Test general templating features using a small template
+
+from cgi import escape
+import os
+from StringIO import StringIO
+import sys
+import timeit
+
+__all__ = ['clearsilver', 'mako', 'django', 'kid', 'genshi', 'genshi_text',
+           'simpletal']
+
+def genshi(dirname, verbose=False):
+    from genshi.template import TemplateLoader
+    loader = TemplateLoader([dirname], auto_reload=False)
+    template = loader.load('template.html')
+    def render():
+        data = dict(title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.generate(**data).render('xhtml')
+
+    if verbose:
+        print render()
+    return render
+
+def genshi_text(dirname, verbose=False):
+    from genshi.core import escape
+    from genshi.template import TemplateLoader, NewTextTemplate
+    loader = TemplateLoader([dirname], auto_reload=False)
+    template = loader.load('template.txt', cls=NewTextTemplate)
+    def render():
+        data = dict(escape=escape, title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.generate(**data).render('text')
+
+    if verbose:
+        print render()
+    return render
+
+def mako(dirname, verbose=False):
+    from mako.lookup import TemplateLookup
+    lookup = TemplateLookup(directories=[dirname], filesystem_checks=False)
+    template = lookup.get_template('template.html')
+    def render():
+        data = dict(title='Just a test', user='joe',
+                    list_items=['Number %d' % num for num in range(1, 15)])
+        return template.render(**data)
+    if verbose:
+        print render()
+    return render
+
+def cheetah(dirname, verbose=False):
+    # FIXME: infinite recursion somewhere... WTF?
+    try:
+        from Cheetah.Template import Template
+    except ImportError:
+        print>>sys.stderr, 'Cheetah not installed, skipping'
+        return lambda: None
+    class MyTemplate(Template):
+        def serverSidePath(self, path): return os.path.join(dirname, path)
+    filename = os.path.join(dirname, 'template.tmpl')
+    template = MyTemplate(file=filename)
+
+    def render():
+        template = MyTemplate(file=filename,
+                              searchList=[{'title': 'Just a test', 'user': 'joe',
+                                           'items': [u'Number %d' % num for num in range(1, 15)]}])
+        return template.respond()
+
+    if verbose:
+        print render()
+    return render
+
+def clearsilver(dirname, verbose=False):
+    try:
+        import neo_cgi
+    except ImportError:
+        print>>sys.stderr, 'ClearSilver not installed, skipping'
+        return lambda: None
+    neo_cgi.update()
+    import neo_util
+    import neo_cs
+    def render():
+        hdf = neo_util.HDF()
+        hdf.setValue('hdf.loadpaths.0', dirname)
+        hdf.setValue('title', escape('Just a test'))
+        hdf.setValue('user', escape('joe'))
+        for num in range(1, 15):
+            hdf.setValue('items.%d' % (num - 1), escape('Number %d' % num))
+        cs = neo_cs.CS(hdf)
+        cs.parseFile('template.cs')
+        return cs.render()
+
+    if verbose:
+        print render()
+    return render
+
+def django(dirname, verbose=False):
+    try:
+        from django.conf import settings
+        settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')])
+    except ImportError:
+        print>>sys.stderr, 'Django not installed, skipping'
+        return lambda: None
+    from django import template, templatetags
+    from django.template import loader
+    templatetags.__path__.append(os.path.join(dirname, 'templatetags'))
+    tmpl = loader.get_template('template.html')
+
+    def render():
+        data = {'title': 'Just a test', 'user': 'joe',
+                'items': ['Number %d' % num for num in range(1, 15)]}
+        return tmpl.render(template.Context(data))
+
+    if verbose:
+        print render()
+    return render
+
+def kid(dirname, verbose=False):
+    try:
+        import kid
+    except ImportError:
+        print>>sys.stderr, "Kid not installed, skipping"
+        return lambda: None
+    kid.path = kid.TemplatePath([dirname])
+    template = kid.load_template('template.kid').Template
+    def render():
+        return template(
+            title='Just a test', user='joe',
+            items=['Number %d' % num for num in range(1, 15)]
+        ).serialize(output='xhtml')
+
+    if verbose:
+        print render()
+    return render
+
+def simpletal(dirname, verbose=False):
+    try:
+        from simpletal import simpleTAL, simpleTALES
+    except ImportError:
+        print>>sys.stderr, "SimpleTAL not installed, skipping"
+        return lambda: None
+    fileobj = open(os.path.join(dirname, 'base.html'))
+    base = simpleTAL.compileHTMLTemplate(fileobj)
+    fileobj.close()
+    fileobj = open(os.path.join(dirname, 'template.html'))
+    template = simpleTAL.compileHTMLTemplate(fileobj)
+    fileobj.close()
+    def render():
+        ctxt = simpleTALES.Context(allowPythonPath=1)
+        ctxt.addGlobal('base', base)
+        ctxt.addGlobal('title', 'Just a test')
+        ctxt.addGlobal('user', 'joe')
+        ctxt.addGlobal('items', ['Number %d' % num for num in range(1, 15)])
+        buf = StringIO()
+        template.expand(ctxt, buf)
+        return buf.getvalue()
+
+    if verbose:
+        print render()
+    return render
+
+def run(engines, number=2000, verbose=False):
+    basepath = os.path.abspath(os.path.dirname(__file__))
+    for engine in engines:
+        dirname = os.path.join(basepath, engine)
+        if verbose:
+            print '%s:' % engine.capitalize()
+            print '--------------------------------------------------------'
+        else:
+            print '%s:' % engine.capitalize(),
+        t = timeit.Timer(setup='from __main__ import %s; render = %s(r"%s", %s)'
+                               % (engine, engine, dirname, verbose),
+                         stmt='render()')
+        time = t.timeit(number=number) / number
+        if verbose:
+            print '--------------------------------------------------------'
+        print '%.2f ms' % (1000 * time)
+        if verbose:
+            print '--------------------------------------------------------'
+
+
+if __name__ == '__main__':
+    engines = [arg for arg in sys.argv[1:] if arg[0] != '-']
+    if not engines:
+        engines = __all__
+
+    verbose = '-v' in sys.argv
+
+    if '-p' in sys.argv:
+        import cProfile, pstats
+        prof = cProfile.Profile()
+        prof.run('run(%r, number=200, verbose=%r)' % (engines, verbose))
+        stats = pstats.Stats(prof)
+        stats.strip_dirs()
+        stats.sort_stats('calls')
+        stats.print_stats(25)
+        if verbose:
+            stats.print_callees()
+            stats.print_callers()
+    else:
+        run(engines, verbose=verbose)
diff --git a/lib/genshi/examples/bench/bigtable.py b/lib/genshi/examples/bench/bigtable.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/bigtable.py
@@ -0,0 +1,233 @@
+# -*- encoding: utf-8 -*-
+# Template language benchmarks
+#
+# Objective: Generate a 1000x10 HTML table as fast as possible.
+#
+# Author: Jonas Borgstr&#246;m <jonas at edgewall.com>
+
+import cgi
+import sys
+import timeit
+from StringIO import StringIO
+from genshi.builder import tag
+from genshi.template import MarkupTemplate, NewTextTemplate
+
+try:
+    from elementtree import ElementTree as et
+except ImportError:
+    et = None
+
+try:
+    import cElementTree as cet
+except ImportError:
+    cet = None
+
+try:
+    import neo_cgi, neo_cs, neo_util
+except ImportError:
+    neo_cgi = None
+
+try:
+    import kid
+except ImportError:
+    kid = None
+
+try:
+    from django.conf import settings
+    settings.configure()
+    from django.template import Context as DjangoContext
+    from django.template import Template as DjangoTemplate
+except ImportError:
+    DjangoContext = DjangoTemplate = None
+
+try:
+    from mako.template import Template as MakoTemplate
+except ImportError:
+    MakoTemplate = None
+
+table = [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10)
+          for x in range(1000)]
+
+genshi_tmpl = MarkupTemplate("""
+<table xmlns:py="http://genshi.edgewall.org/">
+<tr py:for="row in table">
+<td py:for="c in row.values()" py:content="c"/>
+</tr>
+</table>
+""")
+
+genshi_tmpl2 = MarkupTemplate("""
+<table xmlns:py="http://genshi.edgewall.org/">$table</table>
+""")
+
+genshi_text_tmpl = NewTextTemplate("""
+<table>
+{% for row in table %}<tr>
+{% for c in row.values() %}<td>$c</td>{% end %}
+</tr>{% end %}
+</table>
+""")
+
+if DjangoTemplate:
+    django_tmpl = DjangoTemplate("""
+    <table>
+    {% for row in table %}
+    <tr>{% for col in row.values %}{{ col|escape }}{% endfor %}</tr>
+    {% endfor %}
+    </table>
+    """)
+
+    def test_django():
+        """Djange template"""
+        context = DjangoContext({'table': table})
+        django_tmpl.render(context)
+
+if MakoTemplate:
+    mako_tmpl = MakoTemplate("""
+<table>
+  % for row in table:
+    <tr>
+      % for col in row.values():
+        <td>${ col | h  }</td>
+      % endfor
+    </tr>
+  % endfor
+</table>
+""")
+    def test_mako():
+        """Mako Template"""
+        mako_tmpl.render(table=table)
+
+def test_genshi():
+    """Genshi template"""
+    stream = genshi_tmpl.generate(table=table)
+    stream.render('html', strip_whitespace=False)
+
+def test_genshi_text():
+    """Genshi text template"""
+    stream = genshi_text_tmpl.generate(table=table)
+    stream.render('text')
+
+def test_genshi_builder():
+    """Genshi template + tag builder"""
+    stream = tag.TABLE([
+        tag.tr([tag.td(c) for c in row.values()])
+        for row in table
+    ]).generate()
+    stream = genshi_tmpl2.generate(table=stream)
+    stream.render('html', strip_whitespace=False)
+
+def test_builder():
+    """Genshi tag builder"""
+    stream = tag.TABLE([
+        tag.tr([
+            tag.td(c) for c in row.values()
+        ])
+        for row in table
+    ]).generate()
+    stream.render('html', strip_whitespace=False)
+
+if kid:
+    kid_tmpl = kid.Template("""
+    <table xmlns:py="http://purl.org/kid/ns#">
+    <tr py:for="row in table">
+    <td py:for="c in row.values()" py:content="c"/>
+    </tr>
+    </table>
+    """)
+
+    kid_tmpl2 = kid.Template("""
+    <html xmlns:py="http://purl.org/kid/ns#">$table</html>
+    """)
+
+    def test_kid():
+        """Kid template"""
+        kid_tmpl.table = table
+        kid_tmpl.serialize(output='html')
+
+    if cet:
+        def test_kid_et():
+            """Kid template + cElementTree"""
+            _table = cet.Element('table')
+            for row in table:
+                td = cet.SubElement(_table, 'tr')
+                for c in row.values():
+                    cet.SubElement(td, 'td').text=str(c)
+            kid_tmpl2.table = _table
+            kid_tmpl2.serialize(output='html')
+
+if et:
+    def test_et():
+        """ElementTree"""
+        _table = et.Element('table')
+        for row in table:
+            tr = et.SubElement(_table, 'tr')
+            for c in row.values():
+                et.SubElement(tr, 'td').text=str(c)
+        et.tostring(_table)
+
+if cet:
+    def test_cet(): 
+        """cElementTree"""
+        _table = cet.Element('table')
+        for row in table:
+            tr = cet.SubElement(_table, 'tr')
+            for c in row.values():
+                cet.SubElement(tr, 'td').text=str(c)
+        cet.tostring(_table)
+
+if neo_cgi:
+    def test_clearsilver():
+        """ClearSilver"""
+        hdf = neo_util.HDF()
+        for i, row in enumerate(table):
+            for j, c in enumerate(row.values()):
+                hdf.setValue("rows.%d.cell.%d" % (i, j), cgi.escape(str(c)))
+
+        cs = neo_cs.CS(hdf)
+        cs.parseStr("""
+<table><?cs
+  each:row=rows
+?><tr><?cs each:c=row.cell
+  ?><td><?cs var:c ?></td><?cs /each
+?></tr><?cs /each?>
+</table>""")
+        cs.render()
+
+
+def run(which=None, number=10):
+    tests = ['test_builder', 'test_genshi', 'test_genshi_text',
+             'test_genshi_builder', 'test_mako', 'test_kid', 'test_kid_et',
+             'test_et', 'test_cet', 'test_clearsilver', 'test_django']
+
+    if which:
+        tests = filter(lambda n: n[5:] in which, tests)
+
+    for test in [t for t in tests if hasattr(sys.modules[__name__], t)]:
+        t = timeit.Timer(setup='from __main__ import %s;' % test,
+                         stmt='%s()' % test)
+        time = t.timeit(number=number) / number
+
+        if time < 0.00001:
+            result = '   (not installed?)'
+        else:
+            result = '%16.2f ms' % (1000 * time)
+        print '%-35s %s' % (getattr(sys.modules[__name__], test).__doc__, result)
+
+
+if __name__ == '__main__':
+    which = [arg for arg in sys.argv[1:] if arg[0] != '-']
+
+    if '-p' in sys.argv:
+        import cProfile, pstats
+        prof = cProfile.Profile()
+        prof.run('run(%r, number=1)' % which)
+        stats = pstats.Stats(prof)
+        stats.strip_dirs()
+        stats.sort_stats('time', 'calls')
+        stats.print_stats(25)
+        if '-v' in sys.argv:
+            stats.print_callees()
+            stats.print_callers()
+    else:
+        run(which)
diff --git a/lib/genshi/examples/bench/cheetah/footer.tmpl b/lib/genshi/examples/bench/cheetah/footer.tmpl
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/cheetah/footer.tmpl
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
diff --git a/lib/genshi/examples/bench/cheetah/header.tmpl b/lib/genshi/examples/bench/cheetah/header.tmpl
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/cheetah/header.tmpl
@@ -0,0 +1,3 @@
+<div id="header">
+  <h1>$title</h1>
+</div>
diff --git a/lib/genshi/examples/bench/cheetah/template.tmpl b/lib/genshi/examples/bench/cheetah/template.tmpl
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/cheetah/template.tmpl
@@ -0,0 +1,22 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    #include "cheetah/header.tmpl"
+
+    <h2>Loop</h2>
+    #if $items
+      <ul>
+        #for $item in $items
+          <li>$item</li>
+        #end for
+      </ul>
+    #end if
+
+    #include "cheetah/footer.tmpl"
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/clearsilver/footer.cs b/lib/genshi/examples/bench/clearsilver/footer.cs
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/clearsilver/footer.cs
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
diff --git a/lib/genshi/examples/bench/clearsilver/header.cs b/lib/genshi/examples/bench/clearsilver/header.cs
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/clearsilver/header.cs
@@ -0,0 +1,7 @@
+<div id="header">
+  <h1><?cs var:title ?></h1>
+</div>
+
+<?cs def:greeting(name) ?>
+  <p>Hello, <?cs var:name ?>!</p>
+<?cs /def ?>
diff --git a/lib/genshi/examples/bench/clearsilver/template.cs b/lib/genshi/examples/bench/clearsilver/template.cs
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/clearsilver/template.cs
@@ -0,0 +1,25 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title><?cs var:title ?></title>
+  </head>
+  <body>
+    <?cs include:"header.cs" ?>
+    <?cs call:greeting(user) ?>
+    <?cs call:greeting('me') ?>
+    <?cs call:greeting('world') ?>
+    
+    <h2>Loop</h2>
+    <?cs if:len(items) ?>
+      <ul>
+        <?cs each:item = items ?>
+          <li<?cs if:name(item) == len(items) ?> class="last"<?cs /if ?>><?cs var:item ?></li>
+        <?cs /each ?>
+      </ul>
+    <?cs /if ?>
+    
+    <?cs include:"footer.cs" ?>
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/django/templates/base.html b/lib/genshi/examples/bench/django/templates/base.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/django/templates/base.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+  {% block content %}
+    {% block header %}
+      <div id="header">
+        <h1>{{ title|escape }}</h1>
+      </div>
+    {% endblock %}
+
+    {% block footer %}
+      <div id="footer"></div>
+    {% endblock %}
+  {% endblock %}
+
+</html>
diff --git a/lib/genshi/examples/bench/django/templates/template.html b/lib/genshi/examples/bench/django/templates/template.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/django/templates/template.html
@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% load bench %}
+
+{% block content %}
+  <head>
+    <title>{{title|escape}}</title>
+  </head>
+
+  <body>
+    {% block header %}{% endblock %}
+
+    <div>{% greeting user %}</div>
+    <div>{% greeting "me" %}</div>
+    <div>{% greeting "world" %}</div>
+
+    <h2>Loop</h2>
+    {% if items %}
+      <ul>
+        {% for item in items %}
+          <li{% if forloop.last %} class="last"{% endif %}>{{ item|escape }}</li>
+        {% endfor %}
+      </ul>
+    {% endif %}
+
+    {% block footer %}{% endblock %}
+  </body>
+{% endblock %}
diff --git a/lib/genshi/examples/bench/django/templatetags/__init__.py b/lib/genshi/examples/bench/django/templatetags/__init__.py
new file mode 100644
diff --git a/lib/genshi/examples/bench/django/templatetags/bench.py b/lib/genshi/examples/bench/django/templatetags/bench.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/django/templatetags/bench.py
@@ -0,0 +1,8 @@
+from django.template import Library, Node, resolve_variable
+from django.utils.html import escape
+
+register = Library()
+
+def greeting(name):
+    return 'Hello, %s!' % escape(name)
+greeting = register.simple_tag(greeting)
diff --git a/lib/genshi/examples/bench/genshi/base.html b/lib/genshi/examples/bench/genshi/base.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/genshi/base.html
@@ -0,0 +1,17 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      py:strip="">
+
+  <p py:def="greeting(name)">
+    Hello, ${name}!
+  </p>
+
+  <py:match path="body" once="true"><body>
+    <div id="header">
+      <h1>${title}</h1>
+    </div>
+    ${select('*')}
+    <div id="footer" />
+  </body></py:match>
+
+</html>
diff --git a/lib/genshi/examples/bench/genshi/template.html b/lib/genshi/examples/bench/genshi/template.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/genshi/template.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      lang="en">
+  <xi:include href="base.html" />
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <div>${greeting(user)}</div>
+    <div>${greeting('me')}</div>
+    <div>${greeting('world')}</div>
+
+    <h2>Loop</h2>
+    <ul py:if="items">
+      <li py:for="idx, item in enumerate(items)" py:content="item"
+          class="${idx + 1 == len(items) and 'last' or None}" />
+    </ul>
+
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/genshi_text/footer.txt b/lib/genshi/examples/bench/genshi_text/footer.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/genshi_text/footer.txt
@@ -0,0 +1,1 @@
+<div id="footer"></div>
diff --git a/lib/genshi/examples/bench/genshi_text/header.txt b/lib/genshi/examples/bench/genshi_text/header.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/genshi_text/header.txt
@@ -0,0 +1,3 @@
+<div id="header">
+  <h1>${escape(title)}</h1>
+</div>
diff --git a/lib/genshi/examples/bench/genshi_text/template.txt b/lib/genshi/examples/bench/genshi_text/template.txt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/genshi_text/template.txt
@@ -0,0 +1,28 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+<head>
+  <title>${escape(title)}</title>
+</head>
+
+<body>
+  {% include header.txt %}
+  {% def greeting(name) %}
+    Hello, ${name}!
+  {% end %}
+
+  <div>${greeting(user)}</div>
+  <div>${greeting("me")}</div>
+  <div>${greeting("world")}</div>
+  
+  <h2>Loop</h2>
+  {% if items %}<ul>
+    {% for idx, item in enumerate(items) %}\
+      <li{% if idx + 1 == len(items) %} class="last"{% end %}>${escape(item)}</li>
+    {% end %}
+  </ul>{% end %}
+  
+  {% include footer.txt %}
+</body>
diff --git a/lib/genshi/examples/bench/kid/base.kid b/lib/genshi/examples/bench/kid/base.kid
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/kid/base.kid
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://purl.org/kid/ns#">
+
+  <p py:def="greeting(name)">
+    Hello, ${name}!
+  </p>
+
+  <body py:match="item.tag == '{http://www.w3.org/1999/xhtml}body'" py:strip="">
+    <div id="header">
+      <h1>${title}</h1>
+    </div>
+    ${item}
+    <div id="footer" />
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/kid/template.kid b/lib/genshi/examples/bench/kid/template.kid
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/kid/template.kid
@@ -0,0 +1,22 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://purl.org/kid/ns#"
+      py:extends="'base.kid'"
+      lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <div>${greeting(user)}</div>
+    <div>${greeting('me')}</div>
+    <div>${greeting('world')}</div>
+    
+    <h2>Loop</h2>
+    <ul py:if="items">
+      <li py:for="idx, item in enumerate(items)" py:content="item"
+          class="${idx + 1 == len(items) and 'last' or None}" />
+    </ul>
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/mako/footer.html b/lib/genshi/examples/bench/mako/footer.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/mako/footer.html
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
diff --git a/lib/genshi/examples/bench/mako/header.html b/lib/genshi/examples/bench/mako/header.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/mako/header.html
@@ -0,0 +1,5 @@
+<div id="header">
+  <h1>${title | h}</h1>
+</div>
+
+
diff --git a/lib/genshi/examples/bench/mako/template.html b/lib/genshi/examples/bench/mako/template.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/mako/template.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <%def name="greeting(name)">
+      <p>Hello, ${name | h}!</p>
+    </%def>
+  
+    <%include file="header.html"/>
+  
+    ${greeting(user)}
+    ${greeting('me')}
+    ${greeting('world')}
+    
+    <h2>Loop</h2>
+    % if items:
+      <ul>
+        % for idx, item in enumerate(items):
+          <li ${idx+1==len(items) and "class='last'" or ""}>${item | h}</li>
+        % endfor
+      </ul>
+    % endif
+    <%include file="footer.html"/>
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/myghty/base.myt b/lib/genshi/examples/bench/myghty/base.myt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/myghty/base.myt
@@ -0,0 +1,26 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+<%method wrap>
+<%args scope="request">
+  title
+</%args>
+<div id="header">
+  <h1><% title %></h1>
+</div>
+
+<% m.content() %>
+
+</%method>
+
+<div id="footer"></div>
+</html>
+
+<%method greeting>
+<%args>
+   name
+</%args>
+Hello, <% name | h %>
+</%method>
diff --git a/lib/genshi/examples/bench/myghty/template.myt b/lib/genshi/examples/bench/myghty/template.myt
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/myghty/template.myt
@@ -0,0 +1,25 @@
+<%args>
+	title
+	items
+	user
+</%args>
+
+<head>
+  <title><% title %></title>
+</head>
+
+ <&|base.myt:wrap &>
+  <div><& base.myt:greeting, name=user &></div>
+  <div><& base.myt:greeting, name="me"&></div>
+  <div><& base.myt:greeting, name="world" &></div>
+
+  <h2>Loop</h2>
+%if items:
+      <ul>
+%	for item in items:
+  <li><% item %></li>
+%
+      </ul>
+%
+
+ </&>
diff --git a/lib/genshi/examples/bench/simpletal/base.html b/lib/genshi/examples/bench/simpletal/base.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/simpletal/base.html
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+  <p metal:define-macro="greeting">
+    Hello, <span metal:define-slot="name">name</span>
+  </p>
+
+  <body metal:define-macro="content">
+    <div id="header">
+      <h1 tal:content="title" />
+    </div>
+    <div metal:define-slot="content" tal:omit-tag="" />
+    <div id="footer"></div>
+  </body>
+
+</html>
diff --git a/lib/genshi/examples/bench/simpletal/template.html b/lib/genshi/examples/bench/simpletal/template.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/simpletal/template.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title tal:content="title">Title</title>
+  </head>
+  <body metal:use-macro="base/macros/content">
+    <div metal:fill-slot="content">
+
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:content="user" tal:omit-tag=""></span>
+      </div>
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:omit-tag="">me</span>
+      </div>
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:omit-tag="">world</span>
+      </div>
+
+      <h2>Loop</h2>
+      <ul tal:condition="items">
+        <li tal:repeat="item items" tal:content="item"
+            tal:attributes="class python:repeat['item'].getEnd() and 'last' or None">Item</li>
+      </ul>
+
+    </div>
+  </body>
+</html>
diff --git a/lib/genshi/examples/bench/xpath.py b/lib/genshi/examples/bench/xpath.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/bench/xpath.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2008 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+
+try:
+    from os import times
+    def time_func():
+        tup = times()
+        #just user time
+        return tup[0] # + tup[1]
+except ImportError:
+    from time import time as time_func
+
+from genshi.core import START, END
+from genshi.path import Path
+from genshi.input import XML
+
+def benchmark(f, acurate_time=1):
+    """Checks how much time does function f work. It runs it as
+    many times as needed for avoiding inaccuracy"""
+
+    runs = 1
+    while True:
+        start_time = time_func()
+        for _ in xrange(runs):
+            f()
+        dt = time_func() - start_time
+        if dt >= acurate_time:
+            break
+        runs *= 2
+    return dt / runs
+
+def spell(t):
+    """Returns spelled representation of time"""
+    units = [(0.000001, 'microsecond', 'microseconds'),
+             (0.001, 'milisecond', 'miliseconds'),
+             (1, 'second', 'seconds'),
+             (60, 'minute', 'minutes'),
+             (60*60, 'hour', 'hours'),
+            ]
+    i = 0
+    at = abs(t)
+    while i + 1 < len(units) and at >= units[i + 1][0]:
+        i += 1
+    t /= units[i][0]
+    if t >= 2:
+        name = units[i][2]
+    else:
+        name = units[i][1]
+    return "%f %s"%(t, name)
+
+def test_paths_in_streams(exprs, streams, test_strategies=False):
+    for expr in exprs:
+        print "Testing path %r" % expr
+        for stream, sname in streams:
+            print '\tRunning on "%s" example:' % sname
+
+            path = Path(expr)
+            def f():
+                for e in path.select(stream):
+                    pass
+            t = spell(benchmark(f))
+            print "\t\tselect:\t\t%s" % t
+
+            def f():
+                path = Path(expr)
+                for e in path.select(stream):
+                    pass
+            t = spell(benchmark(f))
+            print "\t\tinit + select:\t%s" % t
+
+            if test_strategies and len(path.paths) == 1:
+                from genshi.path import GenericStrategy, SingleStepStrategy, \
+                                        SimplePathStrategy
+                from genshi.tests.path import FakePath
+                strategies = (GenericStrategy, SingleStepStrategy,
+                              SimplePathStrategy)
+                for strategy in strategies:
+                    if not strategy.supports(path.paths[0]):
+                        continue
+                    print "\t\t%s Strategy"%strategy.__name__
+                    fp = FakePath(strategy(path.paths[0]))
+                    def f():
+                        for e in fp.select(stream):
+                            pass
+                    t = spell(benchmark(f))
+                    print "\t\t\tselect:\t\t%s"%t
+
+
+def test_documents(test_strategies=False):
+    streams = []
+
+    s = XML("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" xmlns:py="http://genshi.edgewall.org/" py:strip="" lang="en">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>Foo</title>
+    </head>
+    <body>
+        <h1>Hello</h1>
+    </body>
+</html>
+""")
+    streams.append((s, "small document"))
+
+    s = XML("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" xmlns:py="http://genshi.edgewall.org/" py:strip="" lang="en">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>Foo</title>
+    </head>
+    <body>
+        <h1>Hello</h1>
+        <div id="splash">
+            <ul>
+                <li><a class="b1" href="http://genshi.edgewall.org/">
+                        <strong>Genshi</strong>
+                        Python toolkit for generating output for the web</a></li>
+                <li><a class="b2" href="http://babel.edgewall.org/">
+                        <strong>Babel</strong>
+                        Python library for I18n/L10n in web applications</a></li>
+                <li><a class="b3" href="http://bitten.edgewall.org/">
+                        <strong>Bitten</strong>
+                        Continuous integration plugin for Trac</a></li>
+                <li><a class="b4" href="http://posterity.edgewall.org/">
+                        <strong>Posterity</strong>
+                        Web-based email system</a></li>
+            </ul>
+            <div id="trac-splash">
+                <a href="http://trac.edgewall.org/">
+                    <strong>Trac</strong> Web-based lightweight project management
+                    system
+                </a>
+            </div>
+        </div>
+    </body>
+</html>
+""")
+    streams.append((s, "big document"))
+
+    paths = [
+        '.',
+        '*|text()',
+        'html',
+        'html[@lang="en"]',
+        'html/body/h1/text()',
+        'html/body/div/a/@href',
+        'html/body/div[@id="splash"]/a[@class="b4"]/strong/text()',
+        'descendant-or-self::text()',
+        'descendant-or-self::h1/text()',
+    ]
+    test_paths_in_streams(paths, streams, test_strategies)
+
+if __name__ == '__main__':
+    from sys import argv
+    if "--strategies" in argv:
+        test_strategies = True
+    else:
+        test_strategies = False
+    test_documents(test_strategies)
diff --git a/lib/genshi/examples/tutorial/geddit/__init__.py b/lib/genshi/examples/tutorial/geddit/__init__.py
new file mode 100644
diff --git a/lib/genshi/examples/tutorial/geddit/controller.py b/lib/genshi/examples/tutorial/geddit/controller.py
new file mode 100755
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/controller.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+import operator, os, pickle, sys
+
+import cherrypy
+from formencode import Invalid
+from genshi.input import HTML
+from genshi.filters import HTMLFormFiller, HTMLSanitizer
+
+from geddit.form import LinkForm, CommentForm
+from geddit.lib import ajax, template
+from geddit.model import Link, Comment
+
+
+class Root(object):
+
+    def __init__(self, data):
+        self.data = data
+
+    @cherrypy.expose
+    @template.output('index.html')
+    def index(self):
+        links = sorted(self.data.values(), key=operator.attrgetter('time'))
+        return template.render(links=links)
+
+    @cherrypy.expose
+    @template.output('submit.html')
+    def submit(self, cancel=False, **data):
+        if cherrypy.request.method == 'POST':
+            if cancel:
+                raise cherrypy.HTTPRedirect('/')
+            form = LinkForm()
+            try:
+                data = form.to_python(data)
+                link = Link(**data)
+                self.data[link.id] = link
+                raise cherrypy.HTTPRedirect('/')
+            except Invalid, e:
+                errors = e.unpack_errors()
+        else:
+            errors = {}
+
+        return template.render(errors=errors) | HTMLFormFiller(data=data)
+
+    @cherrypy.expose
+    @template.output('info.html')
+    def info(self, id):
+        link = self.data.get(id)
+        if not link:
+            raise cherrypy.NotFound()
+        return template.render(link=link)
+
+    @cherrypy.expose
+    @template.output('comment.html')
+    def comment(self, id, cancel=False, **data):
+        link = self.data.get(id)
+        if not link:
+            raise cherrypy.NotFound()
+        if cherrypy.request.method == 'POST':
+            if cancel:
+                raise cherrypy.HTTPRedirect('/info/%s' % link.id)
+            form = CommentForm()
+            try:
+                data = form.to_python(data)
+                markup = HTML(data['content']) | HTMLSanitizer()
+                data['content'] = markup.render('xhtml')
+                comment = link.add_comment(**data)
+                if not ajax.is_xhr():
+                    raise cherrypy.HTTPRedirect('/info/%s' % link.id)
+                return template.render('_comment.html', comment=comment,
+                                       num=len(link.comments))
+            except Invalid, e:
+                errors = e.unpack_errors()
+        else:
+            errors = {}
+
+        if ajax.is_xhr():
+            stream = template.render('_form.html', link=link, errors=errors)
+        else:
+            stream = template.render(link=link, comment=None, errors=errors)
+        return stream | HTMLFormFiller(data=data)
+
+    @cherrypy.expose
+    @template.output('index.xml', method='xml')
+    def feed(self, id=None):
+        if id:
+            link = self.data.get(id)
+            if not link:
+                raise cherrypy.NotFound()
+            return template.render('info.xml', link=link)
+        else:
+            links = sorted(self.data.values(), key=operator.attrgetter('time'))
+            return template.render(links=links)
+
+
+def main(filename):
+    # load data from the pickle file, or initialize it to an empty list
+    if os.path.exists(filename):
+        fileobj = open(filename, 'rb')
+        try:
+            data = pickle.load(fileobj)
+        finally:
+            fileobj.close()
+    else:
+        data = {}
+
+    def _save_data():
+        # save data back to the pickle file
+        fileobj = open(filename, 'wb')
+        try:
+            pickle.dump(data, fileobj)
+        finally:
+            fileobj.close()
+    if hasattr(cherrypy.engine, 'subscribe'): # CherryPy >= 3.1
+        cherrypy.engine.subscribe('stop', _save_data)
+    else:
+        cherrypy.engine.on_stop_engine_list.append(_save_data)
+
+    # Some global configuration; note that this could be moved into a
+    # configuration file
+    cherrypy.config.update({
+        'tools.encode.on': True, 'tools.encode.encoding': 'utf-8',
+        'tools.decode.on': True,
+        'tools.trailing_slash.on': True,
+        'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)),
+    })
+
+    cherrypy.quickstart(Root(data), '/', {
+        '/media': {
+            'tools.staticdir.on': True,
+            'tools.staticdir.dir': 'static'
+        }
+    })
+
+if __name__ == '__main__':
+    import formencode
+    formencode.api.set_stdtranslation(languages=['en'])
+    main(sys.argv[1])
diff --git a/lib/genshi/examples/tutorial/geddit/form.py b/lib/genshi/examples/tutorial/geddit/form.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/form.py
@@ -0,0 +1,12 @@
+from formencode import Schema, validators
+
+
+class LinkForm(Schema):
+    username = validators.UnicodeString(not_empty=True)
+    url = validators.URL(not_empty=True, add_http=True, check_exists=False)
+    title = validators.UnicodeString(not_empty=True)
+
+
+class CommentForm(Schema):
+    username = validators.UnicodeString(not_empty=True)
+    content = validators.UnicodeString(not_empty=True)
diff --git a/lib/genshi/examples/tutorial/geddit/lib/__init__.py b/lib/genshi/examples/tutorial/geddit/lib/__init__.py
new file mode 100644
diff --git a/lib/genshi/examples/tutorial/geddit/lib/ajax.py b/lib/genshi/examples/tutorial/geddit/lib/ajax.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/lib/ajax.py
@@ -0,0 +1,5 @@
+import cherrypy
+
+def is_xhr():
+    requested_with = cherrypy.request.headers.get('X-Requested-With')
+    return requested_with and requested_with.lower() == 'xmlhttprequest'
diff --git a/lib/genshi/examples/tutorial/geddit/lib/template.py b/lib/genshi/examples/tutorial/geddit/lib/template.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/lib/template.py
@@ -0,0 +1,47 @@
+import os
+
+import cherrypy
+from genshi.core import Stream
+from genshi.output import encode, get_serializer
+from genshi.template import Context, TemplateLoader
+
+from geddit.lib import ajax
+
+loader = TemplateLoader(
+    os.path.join(os.path.dirname(__file__), '..', 'templates'),
+    auto_reload=True
+)
+
+def output(filename, method='html', encoding='utf-8', **options):
+    """Decorator for exposed methods to specify what template the should use
+    for rendering, and which serialization method and options should be
+    applied.
+    """
+    def decorate(func):
+        def wrapper(*args, **kwargs):
+            cherrypy.thread_data.template = loader.load(filename)
+            opt = options.copy()
+            if not ajax.is_xhr() and method == 'html':
+                opt.setdefault('doctype', 'html')
+            serializer = get_serializer(method, **opt)
+            stream = func(*args, **kwargs)
+            if not isinstance(stream, Stream):
+                return stream
+            return encode(serializer(stream), method=serializer,
+                          encoding=encoding)
+        return wrapper
+    return decorate
+
+def render(*args, **kwargs):
+    """Function to render the given data to the template specified via the
+    ``@output`` decorator.
+    """
+    if args:
+        assert len(args) == 1, \
+            'Expected exactly one argument, but got %r' % (args,)
+        template = loader.load(args[0])
+    else:
+        template = cherrypy.thread_data.template
+    ctxt = Context(url=cherrypy.url)
+    ctxt.push(kwargs)
+    return template.generate(ctxt)
diff --git a/lib/genshi/examples/tutorial/geddit/model.py b/lib/genshi/examples/tutorial/geddit/model.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/model.py
@@ -0,0 +1,31 @@
+from datetime import datetime
+
+
+class Link(object):
+
+    def __init__(self, username, url, title):
+        self.username = username
+        self.url = url
+        self.title = title
+        self.time = datetime.utcnow()
+        self.id = hex(hash(tuple([username, url, title, self.time])))[2:]
+        self.comments = []
+
+    def __repr__(self):
+        return '<%s %r>' % (type(self).__name__, self.title)
+
+    def add_comment(self, username, content):
+        comment = Comment(username, content)
+        self.comments.append(comment)
+        return comment
+
+
+class Comment(object):
+
+    def __init__(self, username, content):
+        self.username = username
+        self.content = content
+        self.time = datetime.utcnow()
+
+    def __repr__(self):
+        return '<%s by %r>' % (type(self).__name__, self.username)
diff --git a/lib/genshi/examples/tutorial/geddit/static/jquery.js b/lib/genshi/examples/tutorial/geddit/static/jquery.js
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/static/jquery.js
@@ -0,0 +1,11 @@
+/*
+ * jQuery 1.1.4 - New Wave Javascript
+ *
+ * Copyright (c) 2007 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2007-08-23 21:49:27 -0400 (Thu, 23 Aug 2007) $
+ * $Rev: 2862 $
+ */
+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}('(9(){6(1f C!="Q")E v=C;E C=19.16=9(a,c){6(19==7||!7.4a)F 1s C(a,c);F 7.4a(a,c)};6(1f $!="Q")E B=$;19.$=C;E q=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;C.15=C.3v={4a:9(a,c){a=a||R;6(1f a=="1E"){E m=q.2d(a);6(m&&(m[1]||!c)){6(m[1])a=C.3c([m[1]]);G{E b=R.37(m[3]);6(b)6(b.2j!=m[3])F C().1F(a);G{7[0]=b;7.H=1;F 7}G a=[]}}G F 1s C(c).1F(a)}G 6(C.1g(a))F 1s C(R)[C.15.1L?"1L":"2f"](a);F 7.5J(a.1b==1K&&a||(a.3w||a.H&&a!=19&&!a.1t&&a[0]!=Q&&a[0].1t)&&C.2V(a)||[a])},3w:"1.1.4",7K:9(){F 7.H},H:0,21:9(a){F a==Q?C.2V(7):7[a]},1O:9(a){E b=C(a);b.5c=7;F b},5J:9(a){7.H=0;1K.3v.Y.T(7,a);F 7},J:9(a,b){F C.J(7,a,b)},45:9(a){E b=-1;7.J(9(i){6(7==a)b=i});F b},1j:9(f,d,e){E c=f;6(f.1b==3n)6(d==Q)F 7.H&&C[e||"1j"](7[0],f)||Q;G{c={};c[f]=d}F 7.J(9(a){I(E b 17 c)C.1j(e?7.S:7,b,C.4Q(7,c[b],e,a,b))})},1h:9(b,a){F 7.1j(b,a,"34")},2Q:9(e){6(1f e!="4P"&&e!=K)F 7.3K().3H(R.60(e));E t="";C.J(e||7,9(){C.J(7.2Z,9(){6(7.1t!=8)t+=7.1t!=1?7.5S:C.15.2Q([7])})});F t},82:9(){E a,2e=1a;F 7.J(9(){6(!a)a=C.3c(2e,7.2I);E b=a[0].3B(O);7.P.2p(b,7);20(b.1k)b=b.1k;b.4p(7)})},3H:9(){F 7.2J(1a,O,1,9(a){7.4p(a)})},5v:9(){F 7.2J(1a,O,-1,9(a){7.2p(a,7.1k)})},5u:9(){F 7.2J(1a,M,1,9(a){7.P.2p(a,7)})},5t:9(){F 7.2J(1a,M,-1,9(a){7.P.2p(a,7.2a)})},3L:9(){F 7.5c||C([])},1F:9(t){E b=C.3M(7,9(a){F C.1F(t,a)});F 7.1O(/[^+>] [^+>]/.1d(t)||t.U("..")>-1?C.4d(b):b)},7o:9(e){e=e!=Q?e:O;E d=7.1r(7.1F("*"));6(C.N.12){d.J(9(){7.2l$1i={};I(E a 17 7.$1i)7.2l$1i[a]=C.14({},7.$1i[a])}).49()}E r=7.1O(C.3M(7,9(a){F a.3B(e)}));6(C.N.12){d.J(9(){E c=7.2l$1i;I(E a 17 c)I(E b 17 c[a])C.1c.1r(7,a,c[a][b],c[a][b].V);7.2l$1i=K})}6(e){E f=r.1r(r.1F(\'*\')).1l(\'2b,39[@L=3i]\');d.1l(\'2b,39[@L=3i]\').J(9(i){6(7.3j)f[i].3j=7.3j;6(7.27)f[i].27=O})}F r},1l:9(t){F 7.1O(C.1g(t)&&C.2B(7,9(b,a){F t.T(b,[a])})||C.2R(t,7))},5l:9(t){F 7.1O(t.1b==3n&&C.2R(t,7,O)||C.2B(7,9(a){F(t.1b==1K||t.3w)?C.4K(a,t)<0:a!=t}))},1r:9(t){F 7.1O(C.29(7.21(),t.1b==3n?C(t).21():t.H!=Q&&(!t.W||t.W=="6s")?t:[t]))},3y:9(a){F a?C.2R(a,7).H>0:M},2G:9(a){F a==Q?(7.H?7[0].2A:K):7.1j("2A",a)},5W:9(a){F a==Q?(7.H?7[0].2W:K):7.3K().3H(a)},3S:9(){F 7.1O(1K.3v.3S.T(7,1a))},2J:9(f,d,g,e){E c=7.H>1,a;F 7.J(9(){6(!a){a=C.3c(f,7.2I);6(g<0)a.8E()}E b=7;6(d&&C.W(7,"1A")&&C.W(a[0],"3O"))b=7.4L("1w")[0]||7.4p(R.6a("1w"));C.J(a,9(){6(C.W(7,"33")){6(7.32)C.31({1G:7.32,2w:M,3G:"33"});G C.4E(7.2Q||7.5Z||7.2W||"")}G e.T(b,[c?7.3B(O):7])})})}};C.14=C.15.14=9(){E c=1a[0]||{},a=1,1M=1a.H,4D=M;6(c.1b==8d){4D=c;c=1a[1]||{}}6(1M==1){c=7;a=0}E b;I(;a<1M;a++)6((b=1a[a])!=K)I(E i 17 b){6(c==b[i])5X;6(4D&&1f b[i]==\'4P\'&&c[i])C.14(c[i],b[i]);G 6(b[i]!=Q)c[i]=b[i]}F c};C.14({8a:9(a){19.$=B;6(a)19.16=v;F C},1g:9(a){F!!a&&1f a!="1E"&&!a.W&&a.1b!=1K&&/9/i.1d(a+"")},3E:9(a){F a.3D&&!a.4z||a.4y&&a.2I&&!a.2I.4z},4E:9(a){a=C.2s(a);6(a){6(19.5N)19.5N(a);G 6(C.N.1H)19.4x(a,0);G 2T.2S(19,a)}},W:9(b,a){F b.W&&b.W.1I()==a.1I()},J:9(a,b,c){6(c){6(a.H==Q)I(E i 17 a)b.T(a[i],c);G I(E i=0,3A=a.H;i<3A;i++)6(b.T(a[i],c)===M)1J}G{6(a.H==Q)I(E i 17 a)b.2S(a[i],i,a[i]);G I(E i=0,3A=a.H,2G=a[0];i<3A&&b.2S(2G,i,2G)!==M;2G=a[++i]){}}F a},4Q:9(c,b,d,e,a){6(C.1g(b))b=b.2S(c,[e]);E f=/z-?45|7S-?7Q|1e|5y|7O-?1u/i;F b&&b.1b==3x&&d=="34"&&!f.1d(a)?b+"4t":b},18:{1r:9(b,c){C.J((c||"").2M(/\\s+/),9(i,a){6(!C.18.2N(b.18,a))b.18+=(b.18?" ":"")+a})},23:9(b,c){b.18=c!=Q?C.2B(b.18.2M(/\\s+/),9(a){F!C.18.2N(c,a)}).5w(" "):""},2N:9(t,c){F C.4K(c,(t.18||t).3s().2M(/\\s+/))>-1}},1V:9(e,o,f){I(E i 17 o){e.S["2U"+i]=e.S[i];e.S[i]=o[i]}f.T(e,[]);I(E i 17 o)e.S[i]=e.S["2U"+i]},1h:9(e,p){6(p=="1u"||p=="24"){E b={},3p,3o,d=["7J","7G","7F","7B"];C.J(d,9(){b["7A"+7]=0;b["7x"+7+"7u"]=0});C.1V(e,b,9(){6(C(e).3y(\':4N\')){3p=e.7t;3o=e.7q}G{e=C(e.3B(O)).1F(":4e").5d("27").3L().1h({3V:"1C",3k:"7n",11:"2m",7h:"0",7e:"0"}).57(e.P)[0];E a=C.1h(e.P,"3k")||"3g";6(a=="3g")e.P.S.3k="76";3p=e.74;3o=e.71;6(a=="3g")e.P.S.3k="3g";e.P.3e(e)}});F p=="1u"?3p:3o}F C.34(e,p)},34:9(h,d,g){E i,1R=[],1V=[];9 2E(a){6(!C.N.1H)F M;E b=R.2L.3b(a,K);F!b||b.44("2E")==""}6(d=="1e"&&C.N.12){i=C.1j(h.S,"1e");F i==""?"1":i}6(d.2k(/3a/i))d=x;6(!g&&h.S[d])i=h.S[d];G 6(R.2L&&R.2L.3b){6(d.2k(/3a/i))d="3a";d=d.1v(/([A-Z])/g,"-$1").2D();E e=R.2L.3b(h,K);6(e&&!2E(h))i=e.44(d);G{I(E a=h;a&&2E(a);a=a.P)1R.42(a);I(a=0;a<1R.H;a++)6(2E(1R[a])){1V[a]=1R[a].S.11;1R[a].S.11="2m"}i=d=="11"&&1V[1R.H-1]!=K?"1T":R.2L.3b(h,K).44(d)||"";I(a=0;a<1V.H;a++)6(1V[a]!=K)1R[a].S.11=1V[a]}6(d=="1e"&&i=="")i="1"}G 6(h.41){E f=d.1v(/\\-(\\w)/g,9(m,c){F c.1I()});i=h.41[d]||h.41[f]}F i},3c:9(a,c){E r=[];c=c||R;C.J(a,9(i,b){6(!b)F;6(b.1b==3x)b=b.3s();6(1f b=="1E"){E s=C.2s(b).2D(),1m=c.6a("1m"),1P=[];E a=!s.U("<1Z")&&[1,"<2b>","</2b>"]||!s.U("<6L")&&[1,"<4V>","</4V>"]||s.2k(/^<(6I|1w|6H|6F|6D)/)&&[1,"<1A>","</1A>"]||!s.U("<3O")&&[2,"<1A><1w>","</1w></1A>"]||(!s.U("<6A")||!s.U("<6y"))&&[3,"<1A><1w><3O>","</3O></1w></1A>"]||!s.U("<6x")&&[2,"<1A><1w></1w><4T>","</4T></1A>"]||C.N.12&&[1,"1m<1m>","</1m>"]||[0,"",""];1m.2W=a[1]+b+a[2];20(a[0]--)1m=1m.3Y;6(C.N.12){6(!s.U("<1A")&&s.U("<1w")<0)1P=1m.1k&&1m.1k.2Z;G 6(a[1]=="<1A>"&&s.U("<1w")<0)1P=1m.2Z;I(E n=1P.H-1;n>=0;--n)6(C.W(1P[n],"1w")&&!1P[n].2Z.H)1P[n].P.3e(1P[n]);6(/^\\s/.1d(b))1m.2p(c.60(b.2k(/^\\s*/)[0]),1m.1k)}b=C.2V(1m.2Z)}6(0===b.H&&(!C.W(b,"38")&&!C.W(b,"2b")))F;6(b[0]==Q||C.W(b,"38")||b.6u)r.Y(b);G r=C.29(r,b)});F r},1j:9(c,d,a){E e=C.3E(c)?{}:C.4q;6(d=="28"&&C.N.1H)c.P.3j;6(e[d]){6(a!=Q)c[e[d]]=a;F c[e[d]]}G 6(C.N.12&&d=="S")F C.1j(c.S,"6p",a);G 6(a==Q&&C.N.12&&C.W(c,"38")&&(d=="6n"||d=="6m"))F c.6k(d).5S;G 6(c.4y){6(a!=Q)c.6j(d,a);6(C.N.12&&/5R|32/.1d(d)&&!C.3E(c))F c.3F(d,2);F c.3F(d)}G{6(d=="1e"&&C.N.12){6(a!=Q){c.5y=1;c.1l=(c.1l||"").1v(/5T\\([^)]*\\)/,"")+(3m(a).3s()=="6d"?"":"5T(1e="+a*6c+")")}F c.1l?(3m(c.1l.2k(/1e=([^)]*)/)[1])/6c).3s():""}d=d.1v(/-([a-z])/8I,9(z,b){F b.1I()});6(a!=Q)c[d]=a;F c[d]}},2s:9(t){F(t||"").1v(/^\\s+|\\s+$/g,"")},2V:9(a){E r=[];6(1f a!="8H")I(E i=0,1M=a.H;i<1M;i++)r.Y(a[i]);G r=a.3S(0);F r},4K:9(b,a){I(E i=0,1M=a.H;i<1M;i++)6(a[i]==b)F i;F-1},29:9(a,b){6(C.N.12){I(E i=0;b[i];i++)6(b[i].1t!=8)a.Y(b[i])}G I(E i=0;b[i];i++)a.Y(b[i]);F a},4d:9(a){E r=[],4O=C.1q++;2g{I(E i=0,69=a.H;i<69;i++)6(4O!=a[i].1q){a[i].1q=4O;r.Y(a[i])}}2h(e){r=a}F r},1q:0,2B:9(b,a,c){6(1f a=="1E")a=2T("M||9(a,i){F "+a+"}");E d=[];I(E i=0,3P=b.H;i<3P;i++)6(!c&&a(b[i],i)||c&&!a(b[i],i))d.Y(b[i]);F d},3M:9(c,b){6(1f b=="1E")b=2T("M||9(a){F "+b+"}");E d=[];I(E i=0,3P=c.H;i<3P;i++){E a=b(c[i],i);6(a!==K&&a!=Q){6(a.1b!=1K)a=[a];d=d.8x(a)}}F d}});E u=8w.8u.2D();C.N={6b:(u.2k(/.+(?:8s|8q|8p|8o)[\\/: ]([\\d.]+)/)||[])[1],1H:/61/.1d(u),2t:/2t/.1d(u),12:/12/.1d(u)&&!/2t/.1d(u),3J:/3J/.1d(u)&&!/(8n|61)/.1d(u)};E x=C.N.12?"3I":"4G";C.14({8m:!C.N.12||R.8l=="8k",3I:C.N.12?"3I":"4G",4q:{"I":"8j","8i":"18","3a":x,4G:x,3I:x,2W:"2W",18:"18",2A:"2A",30:"30",27:"27",8h:"8g",28:"28",8f:"8e"}});C.J({5Y:"a.P",4C:"16.4C(a)",8c:"16.25(a,2,\'2a\')",8b:"16.25(a,2,\'4B\')",88:"16.4A(a.P.1k,a)",87:"16.4A(a.1k)"},9(i,n){C.15[i]=9(a){E b=C.3M(7,n);6(a&&1f a=="1E")b=C.2R(a,b);F 7.1O(C.4d(b))}});C.J({57:"3H",86:"5v",2p:"5u",85:"5t"},9(i,n){C.15[i]=9(){E a=1a;F 7.J(9(){I(E j=0,1M=a.H;j<1M;j++)C(a[j])[n](7)})}});C.J({5d:9(a){C.1j(7,a,"");7.84(a)},83:9(c){C.18.1r(7,c)},81:9(c){C.18.23(7,c)},80:9(c){C.18[C.18.2N(7,c)?"23":"1r"](7,c)},23:9(a){6(!a||C.1l(a,[7]).r.H)7.P.3e(7)},3K:9(){20(7.1k)7.3e(7.1k)}},9(i,n){C.15[i]=9(){F 7.J(n,1a)}});C.J(["5Q","5P","5M","5L"],9(i,n){C.15[n]=9(a,b){F 7.1l(":"+n+"("+a+")",b)}});C.J(["1u","24"],9(i,n){C.15[n]=9(h){F h==Q?(7.H?C.1h(7[0],n):K):7.1h(n,h.1b==3n?h:h+"4t")}});E A=C.N.1H&&5K(C.N.6b)<7Z?"(?:[\\\\w*2l-]|\\\\\\\\.)":"(?:[\\\\w\\7Y-\\7V*2l-]|\\\\\\\\.)",5I=1s 3C("^[/>]\\\\s*("+A+"+)"),5H=1s 3C("^("+A+"+)(#)("+A+"+)"),5G=1s 3C("^([#.]?)("+A+"*)");C.14({4w:{"":"m[2]==\'*\'||16.W(a,m[2])","#":"a.3F(\'2j\')==m[2]",":":{5P:"i<m[3]-0",5M:"i>m[3]-0",25:"m[3]-0==i",5Q:"m[3]-0==i",2H:"i==0",2P:"i==r.H-1",5E:"i%2==0",5D:"i%2","2H-3z":"a.P.4L(\'*\')[0]==a","2P-3z":"16.25(a.P.3Y,1,\'4B\')==a","7U-3z":"!16.25(a.P.3Y,2,\'4B\')",5Y:"a.1k",3K:"!a.1k",5L:"(a.5Z||a.7T||\'\').U(m[3])>=0",4N:\'"1C"!=a.L&&16.1h(a,"11")!="1T"&&16.1h(a,"3V")!="1C"\',1C:\'"1C"==a.L||16.1h(a,"11")=="1T"||16.1h(a,"3V")=="1C"\',7R:"!a.30",30:"a.30",27:"a.27",28:"a.28||16.1j(a,\'28\')",2Q:"\'2Q\'==a.L",4e:"\'4e\'==a.L",3i:"\'3i\'==a.L",4v:"\'4v\'==a.L",5C:"\'5C\'==a.L",4u:"\'4u\'==a.L",5B:"\'5B\'==a.L",5A:"\'5A\'==a.L",1X:\'"1X"==a.L||16.W(a,"1X")\',39:"/39|2b|7P|1X/i.1d(a.W)",2N:"16.1F(m[3],a).H"},"[":"16.1F(m[2],a).H"},5x:[/^\\[ *(@)([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(\\[)\\s*(.*?(\\[.*?\\])?[^[]*?)\\s*\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1s 3C("^([:.#]*)("+A+"+)")],2R:9(a,c,b){E d,1Y=[];20(a&&a!=d){d=a;E f=C.1l(a,c,b);a=f.t.1v(/^\\s*,\\s*/,"");1Y=b?c=f.r:C.29(1Y,f.r)}F 1Y},1F:9(t,l){6(1f t!="1E")F[t];6(l&&!l.1t)l=K;l=l||R;6(!t.U("//")){t=t.2K(2,t.H)}G 6(!t.U("/")&&!l.2I){l=l.3D;t=t.2K(1,t.H);6(t.U("/")>=1)t=t.2K(t.U("/"),t.H)}E d=[l],2q=[],2P;20(t&&2P!=t){E r=[];2P=t;t=C.2s(t).1v(/^\\/\\//,"");E k=M;E g=5I;E m=g.2d(t);6(m){E o=m[1].1I();I(E i=0;d[i];i++)I(E c=d[i].1k;c;c=c.2a)6(c.1t==1&&(o=="*"||c.W.1I()==o.1I()))r.Y(c);d=r;t=t.1v(g,"");6(t.U(" ")==0)5X;k=O}G{g=/^((\\/?\\.\\.)|([>\\/+~]))\\s*(\\w*)/i;6((m=g.2d(t))!=K){r=[];E o=m[4],1q=C.1q++;m=m[1];I(E j=0,2o=d.H;j<2o;j++)6(m.U("..")<0){E n=m=="~"||m=="+"?d[j].2a:d[j].1k;I(;n;n=n.2a)6(n.1t==1){6(m=="~"&&n.1q==1q)1J;6(!o||n.W.1I()==o.1I()){6(m=="~")n.1q=1q;r.Y(n)}6(m=="+")1J}}G r.Y(d[j].P);d=r;t=C.2s(t.1v(g,""));k=O}}6(t&&!k){6(!t.U(",")){6(l==d[0])d.4s();2q=C.29(2q,d);r=d=[l];t=" "+t.2K(1,t.H)}G{E h=5H;E m=h.2d(t);6(m){m=[0,m[2],m[3],m[1]]}G{h=5G;m=h.2d(t)}m[2]=m[2].1v(/\\\\/g,"");E f=d[d.H-1];6(m[1]=="#"&&f&&f.37&&!C.3E(f)){E p=f.37(m[2]);6((C.N.12||C.N.2t)&&p&&1f p.2j=="1E"&&p.2j!=m[2])p=C(\'[@2j="\'+m[2]+\'"]\',f)[0];d=r=p&&(!m[3]||C.W(p,m[3]))?[p]:[]}G{I(E i=0;d[i];i++){E a=m[1]!=""||m[0]==""?"*":m[2];6(a=="*"&&d[i].W.2D()=="4P")a="2O";r=C.29(r,d[i].4L(a))}6(m[1]==".")r=C.4r(r,m[2]);6(m[1]=="#"){E e=[];I(E i=0;r[i];i++)6(r[i].3F("2j")==m[2]){e=[r[i]];1J}r=e}d=r}t=t.1v(h,"")}}6(t){E b=C.1l(t,r);d=r=b.r;t=C.2s(b.t)}}6(t)d=[];6(d&&l==d[0])d.4s();2q=C.29(2q,d);F 2q},4r:9(r,m,a){m=" "+m+" ";E c=[];I(E i=0;r[i];i++){E b=(" "+r[i].18+" ").U(m)>=0;6(!a&&b||a&&!b)c.Y(r[i])}F c},1l:9(t,r,h){E d;20(t&&t!=d){d=t;E p=C.5x,m;I(E i=0;p[i];i++){m=p[i].2d(t);6(m){t=t.7N(m[0].H);m[2]=m[2].1v(/\\\\/g,"");1J}}6(!m)1J;6(m[1]==":"&&m[2]=="5l")r=C.1l(m[3],r,O).r;G 6(m[1]==".")r=C.4r(r,m[2],h);G 6(m[1]=="@"){E g=[],L=m[3];I(E i=0,2o=r.H;i<2o;i++){E a=r[i],z=a[C.4q[m[2]]||m[2]];6(z==K||/5R|32|28/.1d(m[2]))z=C.1j(a,m[2])||\'\';6((L==""&&!!z||L=="="&&z==m[5]||L=="!="&&z!=m[5]||L=="^="&&z&&!z.U(m[5])||L=="$="&&z.2K(z.H-m[5].H)==m[5]||(L=="*="||L=="~=")&&z.U(m[5])>=0)^h)g.Y(a)}r=g}G 6(m[1]==":"&&m[2]=="25-3z"){E e=C.1q++,g=[],1d=/(\\d*)n\\+?(\\d*)/.2d(m[3]=="5E"&&"2n"||m[3]=="5D"&&"2n+1"||!/\\D/.1d(m[3])&&"n+"+m[3]||m[3]),2H=(1d[1]||1)-0,d=1d[2]-0;I(E i=0,2o=r.H;i<2o;i++){E j=r[i],P=j.P;6(e!=P.1q){E c=1;I(E n=P.1k;n;n=n.2a)6(n.1t==1)n.4o=c++;P.1q=e}E b=M;6(2H==1){6(d==0||j.4o==d)b=O}G 6((j.4o+d)%2H==0)b=O;6(b^h)g.Y(j)}r=g}G{E f=C.4w[m[1]];6(1f f!="1E")f=C.4w[m[1]][m[2]];f=2T("M||9(a,i){F "+f+"}");r=C.2B(r,f,h)}}F{r:r,t:t}},4C:9(c){E b=[];E a=c.P;20(a&&a!=R){b.Y(a);a=a.P}F b},25:9(a,e,c,b){e=e||1;E d=0;I(;a;a=a[c])6(a.1t==1&&++d==e)1J;F a},4A:9(n,a){E r=[];I(;n;n=n.2a){6(n.1t==1&&(!a||n!=a))r.Y(n)}F r}});C.1c={1r:9(f,d,c,b){6(C.N.12&&f.3t!=Q)f=19;6(!c.22)c.22=7.22++;6(b!=Q){E e=c;c=9(){F e.T(7,1a)};c.V=b;c.22=e.22}6(!f.$1i)f.$1i={};6(!f.$1y)f.$1y=9(){E a;6(1f C=="Q"||C.1c.4n)F a;a=C.1c.1y.T(f,1a);F a};E g=f.$1i[d];6(!g){g=f.$1i[d]={};6(f.4m)f.4m(d,f.$1y,M);G f.7M("3r"+d,f.$1y)}g[c.22]=c;7.1D[d]=O},22:1,1D:{},23:9(c,b,a){E d=c.$1i,2c,45;6(d){6(b&&b.L){a=b.4l;b=b.L}6(!b){I(b 17 d)7.23(c,b)}G 6(d[b]){6(a)4k d[b][a.22];G I(a 17 c.$1i[b])4k d[b][a];I(2c 17 d[b])1J;6(!2c){6(c.4j)c.4j(b,c.$1y,M);G c.7L("3r"+b,c.$1y);2c=K;4k d[b]}}I(2c 17 d)1J;6(!2c)c.$1y=c.$1i=K}},1z:9(c,b,d){b=C.2V(b||[]);6(!d){6(7.1D[c])C("*").1r([19,R]).1z(c,b)}G{E a,2c,15=C.1g(d[c]||K);b.42(7.4i({L:c,1S:d}));6(C.1g(d.$1y))a=d.$1y.T(d,b);6(!15&&d["3r"+c]&&d["3r"+c].T(d,b)===M)a=M;6(15&&a!==M&&!(C.W(d,\'a\')&&c=="4h")){7.4n=O;d[c]()}7.4n=M}},1y:9(b){E a;b=C.1c.4i(b||19.1c||{});E c=7.$1i&&7.$1i[b.L],2e=1K.3v.3S.2S(1a,1);2e.42(b);I(E j 17 c){2e[0].4l=c[j];2e[0].V=c[j].V;6(c[j].T(7,2e)===M){b.2u();b.2X();a=M}}6(C.N.12)b.1S=b.2u=b.2X=b.4l=b.V=K;F a},4i:9(c){E a=c;c=C.14({},a);c.2u=9(){6(a.2u)a.2u();a.7I=M};c.2X=9(){6(a.2X)a.2X();a.7H=O};6(!c.1S&&c.5r)c.1S=c.5r;6(C.N.1H&&c.1S.1t==3)c.1S=a.1S.P;6(!c.4g&&c.4F)c.4g=c.4F==c.1S?c.7C:c.4F;6(c.5p==K&&c.66!=K){E e=R.3D,b=R.4z;c.5p=c.66+(e&&e.5o||b.5o||0);c.7z=c.7v+(e&&e.5m||b.5m||0)}6(!c.3Q&&(c.5k||c.5j))c.3Q=c.5k||c.5j;6(!c.5i&&c.5g)c.5i=c.5g;6(!c.3Q&&c.1X)c.3Q=(c.1X&1?1:(c.1X&2?3:(c.1X&4?2:0)));F c}};C.15.14({3l:9(c,a,b){F c=="5f"?7.5e(c,a,b):7.J(9(){C.1c.1r(7,c,b||a,b&&a)})},5e:9(d,b,c){F 7.J(9(){C.1c.1r(7,d,9(a){C(7).49(a);F(c||b).T(7,1a)},c&&b)})},49:9(a,b){F 7.J(9(){C.1c.23(7,a,b)})},1z:9(a,b){F 7.J(9(){C.1c.1z(a,b,7)})},1W:9(){E a=1a;F 7.4h(9(e){7.3T=0==7.3T?1:0;e.2u();F a[7.3T].T(7,[e])||M})},7p:9(f,g){9 3U(e){E p=e.4g;20(p&&p!=7)2g{p=p.P}2h(e){p=7};6(p==7)F M;F(e.L=="3W"?f:g).T(7,[e])}F 7.3W(3U).5b(3U)},1L:9(f){5a();6(C.36)f.T(R,[C]);G C.2C.Y(9(){F f.T(7,[C])});F 7}});C.14({36:M,2C:[],1L:9(){6(!C.36){C.36=O;6(C.2C){C.J(C.2C,9(){7.T(R)});C.2C=K}6(C.N.3J||C.N.2t)R.4j("59",C.1L,M);6(!19.7m.H)C(19).2f(9(){C("#4b").23()})}}});C.J(("7l,7k,2f,7j,7i,5f,4h,7g,"+"7f,7d,7c,3W,5b,7b,2b,"+"4u,7a,79,78,3f").2M(","),9(i,o){C.15[o]=9(f){F f?7.3l(o,f):7.1z(o)}});E w=M;9 5a(){6(w)F;w=O;6(C.N.3J||C.N.2t)R.4m("59",C.1L,M);G 6(C.N.12){R.75("<73"+"72 2j=4b 70=O "+"32=//:><\\/33>");E a=R.37("4b");6(a)a.6Z=9(){6(R.3d!="1x")F;C.1L()};a=K}G 6(C.N.1H)C.48=3t(9(){6(R.3d=="6Y"||R.3d=="1x"){47(C.48);C.48=K;C.1L()}},10);C.1c.1r(19,"2f",C.1L)}C.15.14({6X:9(c,b,a){7.2f(c,b,a,1)},2f:9(g,e,c,d){6(C.1g(g))F 7.3l("2f",g);c=c||9(){};E f="46";6(e)6(C.1g(e)){c=e;e=K}G{e=C.2O(e);f="55"}E h=7;C.31({1G:g,L:f,V:e,2F:d,1x:9(a,b){6(b=="1U"||!d&&b=="54")h.5W(a.43);4x(9(){h.J(c,[a.43,b,a])},13)}});F 7},6W:9(){F C.2O(7)},6V:9(){}});C.J("53,52,51,50,4Z,5h".2M(","),9(i,o){C.15[o]=9(f){F 7.3l(o,f)}});C.14({21:9(e,c,a,d,b){6(C.1g(c)){a=c;c=K}F C.31({L:"46",1G:e,V:c,1U:a,3G:d,2F:b})},6U:9(d,b,a,c){F C.21(d,b,a,c,1)},6T:9(b,a){F C.21(b,K,a,"33")},77:9(c,b,a){F C.21(c,b,a,"56")},6S:9(d,b,a,c){6(C.1g(b)){a=b;b={}}F C.31({L:"55",1G:d,V:b,1U:a,3G:c})},6R:9(a){C.3u.1Q=a},6Q:9(a){C.14(C.3u,a)},3u:{1D:O,L:"46",1Q:0,4Y:"6P/x-6O-38-6N",4X:O,2w:O,V:K},3h:{},31:9(s){s=C.14(O,s,C.14(O,{},C.3u,s));6(s.V){6(s.4X&&1f s.V!="1E")s.V=C.2O(s.V);6(s.L.2D()=="21"){s.1G+=(s.1G.U("?")>-1?"&":"?")+s.V;s.V=K}}6(s.1D&&!C.40++)C.1c.1z("53");E f=M;E h=19.4W?1s 4W("6M.6K"):1s 58();h.6J(s.L,s.1G,s.2w);6(s.V)h.4c("7r-7s",s.4Y);6(s.2F)h.4c("6G-3Z-6E",C.3h[s.1G]||"7w, 6C 7y 6B 4J:4J:4J 6z");h.4c("X-7D-7E","58");6(s.4U)s.4U(h);6(s.1D)C.1c.1z("5h",[h,s]);E g=9(d){6(!f&&h&&(h.3d==4||d=="1Q")){f=O;6(i){47(i);i=K}E c=d=="1Q"&&"1Q"||!C.5n(h)&&"3f"||s.2F&&C.5s(h,s.1G)&&"54"||"1U";6(c=="1U"){2g{E a=C.5q(h,s.3G)}2h(e){c="4I"}}6(c=="1U"){E b;2g{b=h.4f("4S-3Z")}2h(e){}6(s.2F&&b)C.3h[s.1G]=b;6(s.1U)s.1U(a,c);6(s.1D)C.1c.1z("4Z",[h,s])}G C.3X(s,h,c);6(s.1D)C.1c.1z("51",[h,s]);6(s.1D&&!--C.40)C.1c.1z("52");6(s.1x)s.1x(h,c);6(s.2w)h=K}};6(s.2w){E i=3t(g,13);6(s.1Q>0)4x(9(){6(h){h.6w();6(!f)g("1Q")}},s.1Q)}2g{h.6v(s.V)}2h(e){C.3X(s,h,K,e)}6(!s.2w)g();F h},3X:9(s,a,b,e){6(s.3f)s.3f(a,b,e);6(s.1D)C.1c.1z("50",[a,s,e])},40:0,5n:9(r){2g{F!r.26&&6t.6r=="4v:"||(r.26>=4R&&r.26<6q)||r.26==5z||C.N.1H&&r.26==Q}2h(e){}F M},5s:9(a,c){2g{E b=a.4f("4S-3Z");F a.26==5z||b==C.3h[c]||C.N.1H&&a.26==Q}2h(e){}F M},5q:9(r,a){E b=r.4f("6o-L");E c=a=="5F"||!a&&b&&b.U("5F")>=0;V=c?r.7W:r.43;6(c&&V.3D.4y=="4I")7X"4I";6(a=="33")C.4E(V);6(a=="56")V=2T("("+V+")");F V},2O:9(a){E s=[];6(a.1b==1K||a.3w)C.J(a,9(){s.Y(2y(7.6l)+"="+2y(7.2A))});G I(E j 17 a)6(a[j]&&a[j].1b==1K)C.J(a[j],9(){s.Y(2y(j)+"="+2y(7))});G s.Y(2y(j)+"="+2y(a[j]));F s.5w("&")}});C.15.14({1o:9(b,a){F b?7.1B({1u:"1o",24:"1o",1e:"1o"},b,a):7.1l(":1C").J(9(){7.S.11=7.2r?7.2r:"";6(C.1h(7,"11")=="1T")7.S.11="2m"}).3L()},1p:9(b,a){F b?7.1B({1u:"1p",24:"1p",1e:"1p"},b,a):7.1l(":4N").J(9(){7.2r=7.2r||C.1h(7,"11");6(7.2r=="1T")7.2r="2m";7.S.11="1T"}).3L()},5O:C.15.1W,1W:9(a,b){F C.1g(a)&&C.1g(b)?7.5O(a,b):a?7.1B({1u:"1W",24:"1W",1e:"1W"},a,b):7.J(9(){C(7)[C(7).3y(":1C")?"1o":"1p"]()})},6i:9(b,a){F 7.1B({1u:"1o"},b,a)},6h:9(b,a){F 7.1B({1u:"1p"},b,a)},6g:9(b,a){F 7.1B({1u:"1W"},b,a)},6f:9(b,a){F 7.1B({1e:"1o"},b,a)},89:9(b,a){F 7.1B({1e:"1p"},b,a)},6e:9(c,a,b){F 7.1B({1e:a},c,b)},1B:9(d,h,f,g){F 7.1n(9(){E c=C(7).3y(":1C"),1Z=C.5V(h,f,g),5U=7;I(E p 17 d){6(d[p]=="1p"&&c||d[p]=="1o"&&!c)F C.1g(1Z.1x)&&1Z.1x.T(7);6(p=="1u"||p=="24"){1Z.11=C.1h(7,"11");1Z.2z=7.S.2z}}6(1Z.2z!=K)7.S.2z="1C";7.2v=C.14({},d);C.J(d,9(a,b){E e=1s C.2Y(5U,1Z,a);6(b.1b==3x)e.3R(e.1Y()||0,b);G e[b=="1W"?c?"1o":"1p":b](d)});F O})},1n:9(a,b){6(!b){b=a;a="2Y"}F 7.J(9(){6(!7.1n)7.1n={};6(!7.1n[a])7.1n[a]=[];7.1n[a].Y(b);6(7.1n[a].H==1)b.T(7)})}});C.14({5V:9(b,a,c){E d=b&&b.1b==8G?b:{1x:c||!c&&a||C.1g(b)&&b,1N:b,35:c&&a||a&&a.1b!=8F&&a};d.1N=(d.1N&&d.1N.1b==3x?d.1N:{8D:8C,8B:4R}[d.1N])||8A;d.2U=d.1x;d.1x=9(){C.68(7,"2Y");6(C.1g(d.2U))d.2U.T(7)};F d},35:{62:9(p,n,b,a){F b+a*p},4H:9(p,n,b,a){F((-67.8z(p*67.8y)/2)+0.5)*a+b}},1n:{},68:9(b,a){a=a||"2Y";6(b.1n&&b.1n[a]){b.1n[a].4s();E f=b.1n[a][0];6(f)f.T(b)}},3N:[],2Y:9(f,e,g){E z=7;E y=f.S;z.a=9(){6(e.3q)e.3q.T(f,[z.2x]);6(g=="1e")C.1j(y,"1e",z.2x);G{y[g]=5K(z.2x)+"4t";6(g=="1u"||g=="24")y.11="2m"}};z.65=9(){F 3m(C.1h(f,g))};z.1Y=9(){E r=3m(C.34(f,g));F r&&r>-8v?r:z.65()};z.3R=9(c,b){z.4M=(1s 64()).63();z.2x=c;z.a();C.3N.Y(9(){F z.3q(c,b)});6(C.3N.H==1){E d=3t(9(){E a=C.3N;I(E i=0;i<a.H;i++)6(!a[i]())a.8t(i--,1);6(!a.H)47(d)},13)}};z.1o=9(){6(!f.2i)f.2i={};f.2i[g]=C.1j(f.S,g);e.1o=O;z.3R(0,7.1Y());6(g!="1e")y[g]="8r";C(f).1o()};z.1p=9(){6(!f.2i)f.2i={};f.2i[g]=C.1j(f.S,g);e.1p=O;z.3R(7.1Y(),0)};z.3q=9(a,c){E t=(1s 64()).63();6(t>e.1N+z.4M){z.2x=c;z.a();6(f.2v)f.2v[g]=O;E b=O;I(E i 17 f.2v)6(f.2v[i]!==O)b=M;6(b){6(e.11!=K){y.2z=e.2z;y.11=e.11;6(C.1h(f,"11")=="1T")y.11="2m"}6(e.1p)y.11="1T";6(e.1p||e.1o)I(E p 17 f.2v)C.1j(y,p,f.2i[p])}6(b&&C.1g(e.1x))e.1x.T(f);F M}G{E n=t-7.4M;E p=n/e.1N;z.2x=C.35[e.35||(C.35.4H?"4H":"62")](p,n,a,(c-a),e.1N);z.a()}F O}}})})();',62,541,'||||||if|this||function|||||||||||||||||||||||||||||||var|return|else|length|for|each|null|type|false|browser|true|parentNode|undefined|document|style|apply|indexOf|data|nodeName||push|||display|msie||extend|fn|jQuery|in|className|window|arguments|constructor|event|test|opacity|typeof|isFunction|css|events|attr|firstChild|filter|div|queue|show|hide|mergeNum|add|new|nodeType|height|replace|tbody|complete|handle|trigger|table|animate|hidden|global|string|find|url|safari|toUpperCase|break|Array|ready|al|duration|pushStack|tb|timeout|stack|target|none|success|swap|toggle|button|cur|opt|while|get|guid|remove|width|nth|status|checked|selected|merge|nextSibling|select|ret|exec|args|load|try|catch|orig|id|match|_|block||rl|insertBefore|done|oldblock|trim|opera|preventDefault|curAnim|async|now|encodeURIComponent|overflow|value|grep|readyList|toLowerCase|color|ifModified|val|first|ownerDocument|domManip|substr|defaultView|split|has|param|last|text|multiFilter|call|eval|old|makeArray|innerHTML|stopPropagation|fx|childNodes|disabled|ajax|src|script|curCSS|easing|isReady|getElementById|form|input|float|getComputedStyle|clean|readyState|removeChild|error|static|lastModified|checkbox|selectedIndex|position|bind|parseFloat|String|oWidth|oHeight|step|on|toString|setInterval|ajaxSettings|prototype|jquery|Number|is|child|ol|cloneNode|RegExp|documentElement|isXMLDoc|getAttribute|dataType|append|styleFloat|mozilla|empty|end|map|timers|tr|el|which|custom|slice|lastToggle|handleHover|visibility|mouseover|handleError|lastChild|Modified|active|currentStyle|unshift|responseText|getPropertyValue|index|GET|clearInterval|safariTimer|unbind|init|__ie_init|setRequestHeader|unique|radio|getResponseHeader|relatedTarget|click|fix|removeEventListener|delete|handler|addEventListener|triggered|nodeIndex|appendChild|props|classFilter|shift|px|submit|file|expr|setTimeout|tagName|body|sibling|previousSibling|parents|deep|globalEval|fromElement|cssFloat|swing|parsererror|00|inArray|getElementsByTagName|startTime|visible|num|object|prop|200|Last|colgroup|beforeSend|fieldset|ActiveXObject|processData|contentType|ajaxSuccess|ajaxError|ajaxComplete|ajaxStop|ajaxStart|notmodified|POST|json|appendTo|XMLHttpRequest|DOMContentLoaded|bindReady|mouseout|prevObject|removeAttr|one|unload|ctrlKey|ajaxSend|metaKey|keyCode|charCode|not|scrollTop|httpSuccess|scrollLeft|pageX|httpData|srcElement|httpNotModified|after|before|prepend|join|parse|zoom|304|reset|image|password|odd|even|xml|quickClass|quickID|quickChild|setArray|parseInt|contains|gt|execScript|_toggle|lt|eq|href|nodeValue|alpha|self|speed|html|continue|parent|textContent|createTextNode|webkit|linear|getTime|Date|max|clientX|Math|dequeue|fl|createElement|version|100|NaN|fadeTo|fadeIn|slideToggle|slideUp|slideDown|setAttribute|getAttributeNode|name|method|action|content|cssText|300|protocol|FORM|location|options|send|abort|col|th|GMT|td|1970|01|cap|Since|colg|If|tfoot|thead|open|XMLHTTP|leg|Microsoft|urlencoded|www|application|ajaxSetup|ajaxTimeout|post|getScript|getIfModified|evalScripts|serialize|loadIfModified|loaded|onreadystatechange|defer|clientWidth|ipt|scr|clientHeight|write|relative|getJSON|keyup|keypress|keydown|change|mousemove|mouseup|left|mousedown|dblclick|right|scroll|resize|focus|blur|frames|absolute|clone|hover|offsetWidth|Content|Type|offsetHeight|Width|clientY|Thu|border|Jan|pageY|padding|Left|toElement|Requested|With|Right|Bottom|cancelBubble|returnValue|Top|size|detachEvent|attachEvent|substring|line|textarea|weight|enabled|font|innerText|only|uFFFF|responseXML|throw|u0128|417|toggleClass|removeClass|wrap|addClass|removeAttribute|insertAfter|prependTo|children|siblings|fadeOut|noConflict|prev|next|Boolean|maxLength|maxlength|readOnly|readonly|class|htmlFor|CSS1Compat|compatMode|boxModel|compatible|ie|ra|it|1px|rv|splice|userAgent|10000|navigator|concat|PI|cos|400|fast|600|slow|reverse|Function|Object|array|ig'.split('|'),0,{}))
\ No newline at end of file
diff --git a/lib/genshi/examples/tutorial/geddit/static/layout.css b/lib/genshi/examples/tutorial/geddit/static/layout.css
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/static/layout.css
@@ -0,0 +1,42 @@
+html, body { margin: 0; padding: 0; }
+body { background: #ddd; color: #333; font: normal 90%/1.3 Arial,Helvetica,sans-serif; }
+:link, :visited { color: #c10000; text-decoration: none; }
+:link:hover, :visited:hover { text-decoration: underline; }
+:link img, :visited img { border: none; }
+h1 { color: #666;
+  font: normal xx-large/1.5 Georgia,serif; margin: 0 0 .5em;
+}
+blockquote { font-style: italic; }
+form table { margin-bottom: 1em; }
+form table tbody th { font-weight: normal; padding-top: .3em; text-align: right;
+  vertical-align: top;
+}
+form label { color: #666; font-size: 90%; }
+
+#wrap { background: #fff; width: 600px; margin: 30px auto; }
+#content { border-left: 10px solid #b00; min-height: 240px; padding: 10px; }
+#header img { float: right; margin-top: -21px; margin-right: -37px; }
+
+#footer { background: #4A4D4D; border-top: 2px solid #333; font-size: x-small;
+  padding: 3px; text-align: center;
+}
+#footer hr { display: none; }
+.legalese { color: #999; margin: 0; }
+
+ol.links li .info { font-size: 85%; }
+ol.links li .info :link, ol.links li .info :visited { color: #666; }
+
+ul.comments { list-style: none; margin: 1em 0; padding: 0 0 0 1em; }
+ul.comments li { color: #999; margin: 0 0 1em; }
+ul.comments blockquote { color: #333; font-style: normal; margin: 0;
+  padding: 0;
+}
+.action:link, .action:visited { background: #f3f3f3; border: 1px outset #ddd;
+  color: #666; font-size: 90%; padding: 0 .3em;
+}
+.action:link:hover, .action:visited:hover { background: #e8e8e8;
+  border-color: #aaa; color: #000; text-decoration: none;
+}
+
+form p.hint { color: #666; font-size: 90%; font-style: italic; margin: 0; }
+form .error { color: #b00; }
diff --git a/lib/genshi/examples/tutorial/geddit/static/logo.gif b/lib/genshi/examples/tutorial/geddit/static/logo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..60267e548999abf7ddb818be82c0e9397ef51b7b
GIT binary patch

[cut]

diff --git a/lib/genshi/examples/tutorial/geddit/templates/_comment.html b/lib/genshi/examples/tutorial/geddit/templates/_comment.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/_comment.html
@@ -0,0 +1,5 @@
+<?python from genshi import HTML ?>
+<li id="comment$num">
+  <strong>${comment.username}</strong> at ${comment.time.strftime('%x %X')}
+  <blockquote>${HTML(comment.content)}</blockquote>
+</li>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/_form.html b/lib/genshi/examples/tutorial/geddit/templates/_form.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/_form.html
@@ -0,0 +1,24 @@
+<form xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      class="comment" action="${url('/comment/%s/' % link.id)}" method="post">
+  <table summary=""><tbody><tr>
+    <th><label for="username">Your name:</label></th>
+    <td>
+      <input type="text" id="username" name="username" />
+      <span py:if="'username' in errors" class="error">${errors.username}</span>
+    </td>
+  </tr><tr>
+    <th><label for="comment">Comment:</label></th>
+    <td>
+      <textarea id="comment" name="content" rows="6" cols="50"></textarea>
+      <span py:if="'content' in errors" class="error"><br />${errors.content}</span>
+      <p class="hint">You can use HTML tags here for formatting.</p>
+    </td>
+  </tr><tr>
+    <td></td>
+    <td>
+      <input type="submit" value="Submit" />
+      <input type="submit" name="cancel" value="Cancel" />
+    </td>
+  </tr></tbody></table>
+</form>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/comment.html b/lib/genshi/examples/tutorial/geddit/templates/comment.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/comment.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="layout.html" />
+  <head>
+    <title>Comment on &#8220;${link.title}&#8221;</title>
+  </head>
+  <body class="comment">
+    <h1>Comment on &#8220;${link.title}&#8221;</h1>
+    <p py:if="comment">
+      In reply to <strong>${comment.username}</strong>
+      at ${comment.time.strftime('%x %X')}:
+      <blockquote>${comment.content}</blockquote>
+    </p>
+    <xi:include href="_form.html" />
+  </body>
+</html>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/index.html b/lib/genshi/examples/tutorial/geddit/templates/index.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="layout.html" />
+  <head>
+    <title>News</title>
+    <link rel="alternate" type="application/atom+xml" title="Geddit"
+          href="${url('/feed/')}" />
+  </head>
+  <body class="index">
+    <h1>News</h1>
+
+    <ol py:if="links" class="links">
+      <li py:for="link in links">
+        <a href="${link.url}">${link.title}</a>
+        posted by ${link.username} at ${link.time.strftime('%x %X')}
+        <div class="info">
+          <a href="${url('/info/%s/' % link.id)}">
+            ${len(link.comments)} comments
+          </a>
+        </div>
+      </li>
+    </ol>
+
+    <p><a class="action" href="${url('/submit/')}">Submit new link</a></p>
+  </body>
+</html>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/index.xml b/lib/genshi/examples/tutorial/geddit/templates/index.xml
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/index.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom"
+      xmlns:py="http://genshi.edgewall.org/">
+
+  <title>Geddit News</title>
+  <id href="${url('/')}"/>
+  <link rel="alternate" href="${url('/')}" type="text/html"/>
+  <link rel="self" href="${url('/feed/')}" type="application/atom+xml"/>
+  <updated>${links[0].time.isoformat()}</updated>
+
+  <entry py:for="link in reversed(links)">
+    <title>${link.url}</title>
+    <link rel="alternate" href="${link.url}" type="text/html"/>
+    <link rel="via" href="${url('/info/%s/' % link.id)}" type="text/html"/>
+    <id>${url('/info/%s/' % link.id)}</id>
+    <author>
+      <name>${link.username}</name>
+    </author>
+    <updated>${link.time.isoformat()}</updated>
+    <summary>${link.title}</summary>
+  </entry>
+
+</feed>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/info.html b/lib/genshi/examples/tutorial/geddit/templates/info.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/info.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="layout.html" />
+  <head>
+    <title>${link.title}</title>
+    <link rel="alternate" type="application/atom+xml" title="Geddit: ${link.title}"
+          href="${url('/feed/%s/' % link.id)}" />
+    <script type="text/javascript">
+      function loadCommentForm(a) {
+        $.get("${url('/comment/%s/' % link.id)}", {}, function(html) {
+          var form = a.hide().parent().after(html).next();
+          function closeForm() {
+            form.slideUp("fast", function() { a.fadeIn(); form.remove() });
+            return false;
+          }
+          function initForm() {
+            form.find("input[@name='cancel']").click(closeForm);
+            form.submit(function() {
+              var data = form.find("input[@type='text'], textarea").serialize();
+              $.post("${url('/comment/%s/' % link.id)}", data, function(html) {
+                var elem = $(html).get(0);
+                if (/form/i.test(elem.tagName)) {
+                  form.after(elem).remove();
+                  form = $(elem);
+                  initForm();
+                } else {
+                  if ($("ul.comments").length == 0) {
+                    a.parent().before('<ul class="comments"></ul>');
+                  }
+                  $("ul.comments").append($(elem));
+                  closeForm();
+                }
+              });
+              return false;
+            });
+          }
+          initForm();
+        });
+      }
+      $(document).ready(function() {
+        $("a.action").click(function() {
+          loadCommentForm($(this));
+          return false;
+        });
+      });
+    </script>
+  </head>
+  <body class="info">
+    <h1>${link.title}</h1>
+    <a href="${link.url}">${link.url}</a><br />
+    posted by ${link.username} at ${link.time.strftime('%x %X')}<br />
+
+    <ul py:if="link.comments" class="comments">
+      <xi:include href="_comment.html"
+          py:for="num, comment in enumerate(link.comments)" />
+    </ul>
+
+    <p><a class="action" href="${url('/comment/%s/' % link.id)}">Add comment</a></p>
+  </body>
+</html>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/info.xml b/lib/genshi/examples/tutorial/geddit/templates/info.xml
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/info.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom"
+      xmlns:py="http://genshi.edgewall.org/">
+
+  <title>Geddit: ${link.title}</title>
+  <id href="${url('/info/%s/' % link.id)}"/>
+  <link rel="alternate" href="${url('/info/%s/' % link.id)}" type="text/html"/>
+  <link rel="self" href="${url('/feed/%s/' % link.id)}" type="application/atom+xml"/>
+  <updated py:with="time=link.comments and link.comments[-1].time or link.time">
+    ${time.isoformat()}
+  </updated>
+
+  <?python from genshi import HTML ?>
+  <entry py:for="idx, comment in enumerate(reversed(link.comments))">
+    <title>Comment ${len(link.comments) - idx} on &#8220;${link.title}&#8221;</title>
+    <link rel="alternate" href="${url('/info/%s/' % link.id)}#comment${idx}"
+          type="text/html"/>
+    <id>${url('/info/%s/' % link.id)}#comment${idx}</id>
+    <author>
+      <name>${comment.username}</name>
+    </author>
+    <updated>${comment.time.isoformat()}</updated>
+    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
+      ${HTML(comment.content)}
+    </div></content>
+  </entry>
+
+</feed>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/layout.html b/lib/genshi/examples/tutorial/geddit/templates/layout.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/layout.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/" py:strip="">
+
+  <py:match path="head" once="true">
+    <head py:attrs="select('@*')">
+      <title py:with="title = list(select('title/text()'))">
+        Geddit<py:if test="title">: ${title}</py:if>
+      </title>
+      <link rel="stylesheet" href="${url('/media/layout.css')}" type="text/css" />
+      <script type="text/javascript" src="${url('/media/jquery.js')}"></script>
+      ${select('*[local-name()!="title"]')}
+    </head>
+  </py:match>
+
+  <py:match path="body" once="true">
+    <body py:attrs="select('@*')"><div id="wrap">
+      <div id="header">
+        <a href="/"><img src="${url('/media/logo.gif')}" width="201" height="79" alt="geddit?" /></a>
+      </div>
+      <div id="content">
+        ${select('*|text()')}
+      </div>
+      <div id="footer">
+        <hr />
+        <p class="legalese">&#169; 2007 Edgewall Software</p>
+      </div>
+    </div></body>
+  </py:match>
+
+</html>
diff --git a/lib/genshi/examples/tutorial/geddit/templates/submit.html b/lib/genshi/examples/tutorial/geddit/templates/submit.html
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples/tutorial/geddit/templates/submit.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      xmlns:py="http://genshi.edgewall.org/">
+  <xi:include href="layout.html" />
+  <head>
+    <title>Submit new link</title>
+  </head>
+  <body class="submit">
+    <h1>Submit new link</h1>
+
+    <form action="" method="post">
+      <table summary=""><tbody><tr>
+        <th><label for="username">Your name:</label></th>
+        <td>
+          <input type="text" id="username" name="username" />
+          <span py:if="'username' in errors" class="error">${errors.username}</span>
+        </td>
+      </tr><tr>
+        <th><label for="url">Link URL:</label></th>
+        <td>
+          <input type="text" id="url" name="url" />
+          <span py:if="'url' in errors" class="error">${errors.url}</span>
+        </td>
+      </tr><tr>
+        <th><label for="title">Title:</label></th>
+        <td>
+          <input type="text" name="title" />
+          <span py:if="'title' in errors" class="error">${errors.title}</span>
+        </td>
+      </tr><tr>
+        <td></td>
+        <td>
+          <input type="submit" value="Submit" />
+          <input type="submit" name="cancel" value="Cancel" />
+        </td>
+      </tr></tbody></table>
+    </form>
+
+  </body>
+</html>
diff --git a/lib/genshi/examples_to_py3k.sh b/lib/genshi/examples_to_py3k.sh
new file mode 100644
--- /dev/null
+++ b/lib/genshi/examples_to_py3k.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# Script to run 2to3 on files not covered by setup.py
+#
+export PYTHONIOENCODING=utf8
+
+# General 2to3 run
+2to3 -w --no-diffs examples/
diff --git a/lib/genshi/fixes/__init__.py b/lib/genshi/fixes/__init__.py
new file mode 100644
diff --git a/lib/genshi/fixes/fix_unicode_in_strings.py b/lib/genshi/fixes/fix_unicode_in_strings.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/fixes/fix_unicode_in_strings.py
@@ -0,0 +1,17 @@
+"""Fixer that changes expressions inside strings literals from u"..." to "...".
+
+"""
+
+import re
+from lib2to3 import fixer_base
+
+_literal_re = re.compile(r"(.+?)\b[uU]([rR]?[\'\"])")
+
+class FixUnicodeInStrings(fixer_base.BaseFix):
+
+    PATTERN = "STRING"
+
+    def transform(self, node, results):
+        new = node.clone()
+        new.value = _literal_re.sub(r"\1\2", new.value)
+        return new
diff --git a/lib/genshi/genshi/__init__.py b/lib/genshi/genshi/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/genshi/__init__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""This package provides various means for generating and processing web markup
+(XML or HTML).
+
+The design is centered around the concept of streams of markup events (similar
+in concept to SAX parsing events) which can be processed in a uniform manner
+independently of where or how they are produced.
+"""
+
+__docformat__ = 'restructuredtext en'
+__version__ = '0.7'
+
+from genshi.core import *
+from genshi.input import ParseError, XML, HTML
diff --git a/lib/genshi/genshi/_speedups.c b/lib/genshi/genshi/_speedups.c
new file mode 100644
--- /dev/null
+++ b/lib/genshi/genshi/_speedups.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2006-2008 Edgewall Software
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://genshi.edgewall.org/wiki/License.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For the exact contribution history, see the revision
+ * history and logs, available at http://genshi.edgewall.org/log/.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#if PY_MAJOR_VERSION > 2
+#   define IS_PY3K
+#elif PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+    typedef int Py_ssize_t;
+#   define PY_SSIZE_T_MAX INT_MAX
+#   define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+/* We only use Unicode Strings in this module */
+#ifndef IS_PY3K
+#   define PyObject_Str PyObject_Unicode
+#endif
+
+static PyObject *amp1, *amp2, *lt1, *lt2, *gt1, *gt2, *qt1, *qt2;
+static PyObject *stripentities, *striptags;
+
+static void
+init_constants(void)
+{
+    PyObject *util = PyImport_ImportModule("genshi.util");
+    stripentities = PyObject_GetAttrString(util, "stripentities");
+    striptags = PyObject_GetAttrString(util, "striptags");
+    Py_DECREF(util);
+
+    amp1 = PyUnicode_DecodeASCII("&", 1, NULL);
+    amp2 = PyUnicode_DecodeASCII("&amp;", 5, NULL);
+    lt1 = PyUnicode_DecodeASCII("<", 1, NULL);
+    lt2 = PyUnicode_DecodeASCII("&lt;", 4, NULL);
+    gt1 = PyUnicode_DecodeASCII(">", 1, NULL);
+    gt2 = PyUnicode_DecodeASCII("&gt;", 4, NULL);
+    qt1 = PyUnicode_DecodeASCII("\"", 1, NULL);
+    qt2 = PyUnicode_DecodeASCII("&#34;", 5, NULL);
+}
+
+/* Markup class */
+
+PyTypeObject MarkupType; /* declared later */
+
+PyDoc_STRVAR(Markup__doc__,
+"Marks a string as being safe for inclusion in HTML/XML output without\n\
+needing to be escaped.");
+
+static PyObject *
+escape(PyObject *text, int quotes)
+{
+    PyObject *args, *ret;
+    PyUnicodeObject *in, *out;
+    Py_UNICODE *inp, *outp;
+    int len, inn, outn;
+
+    if (PyObject_TypeCheck(text, &MarkupType)) {
+        Py_INCREF(text);
+        return text;
+    }
+    if (PyObject_HasAttrString(text, "__html__")) {
+        ret = PyObject_CallMethod(text, "__html__", NULL);
+        args = PyTuple_New(1);
+        if (args == NULL) {
+            Py_DECREF(ret);
+            return NULL;
+        }
+        PyTuple_SET_ITEM(args, 0, ret);
+        ret = MarkupType.tp_new(&MarkupType, args, NULL);
+        Py_DECREF(args);
+        return ret;
+    }
+    in = (PyUnicodeObject *) PyObject_Str(text);
+    if (in == NULL) {
+        return NULL;
+    }
+    /* First we need to figure out how long the escaped string will be */
+    len = inn = 0;
+    inp = in->str;
+    while (*(inp) || in->length > inp - in->str) {
+        switch (*inp++) {
+            case '&': len += 5; inn++;                                 break;
+            case '"': len += quotes ? 5 : 1; inn += quotes ? 1 : 0;    break;
+            case '<':
+            case '>': len += 4; inn++;                                 break;
+            default:  len++;
+        }
+    }
+
+    /* Do we need to escape anything at all? */
+    if (!inn) {
+        args = PyTuple_New(1);
+        if (args == NULL) {
+            Py_DECREF((PyObject *) in);
+            return NULL;
+        }
+        PyTuple_SET_ITEM(args, 0, (PyObject *) in);
+        ret = MarkupType.tp_new(&MarkupType, args, NULL);
+        Py_DECREF(args);
+        return ret;
+    }
+
+    out = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, len);
+    if (out == NULL) {
+        Py_DECREF((PyObject *) in);
+        return NULL;
+    }
+
+    outn = 0;
+    inp = in->str;
+    outp = out->str;
+    while (*(inp) || in->length > inp - in->str) {
+        if (outn == inn) {
+            /* copy rest of string if we have already replaced everything */
+            Py_UNICODE_COPY(outp, inp, in->length - (inp - in->str));
+            break;
+        }
+        switch (*inp) {
+            case '&':
+                Py_UNICODE_COPY(outp, ((PyUnicodeObject *) amp2)->str, 5);
+                outp += 5;
+                outn++;
+                break;
+            case '"':
+                if (quotes) {
+                    Py_UNICODE_COPY(outp, ((PyUnicodeObject *) qt2)->str, 5);
+                    outp += 5;
+                    outn++;
+                } else {
+                    *outp++ = *inp;
+                }
+                break;
+            case '<':
+                Py_UNICODE_COPY(outp, ((PyUnicodeObject *) lt2)->str, 4);
+                outp += 4;
+                outn++;
+                break;
+            case '>':
+                Py_UNICODE_COPY(outp, ((PyUnicodeObject *) gt2)->str, 4);
+                outp += 4;
+                outn++;
+                break;
+            default:
+                *outp++ = *inp;
+        }
+        inp++;
+    }
+
+    Py_DECREF((PyObject *) in);
+
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF((PyObject *) out);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, (PyObject *) out);
+    ret = MarkupType.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+    return ret;
+}
+
+PyDoc_STRVAR(escape__doc__,
+"Create a Markup instance from a string and escape special characters\n\
+it may contain (<, >, & and \").\n\
+\n\
+>>> escape('\"1 < 2\"')\n\
+<Markup u'&#34;1 &lt; 2&#34;'>\n\
+\n\
+If the `quotes` parameter is set to `False`, the \" character is left\n\
+as is. Escaping quotes is generally only required for strings that are\n\
+to be used in attribute values.\n\
+\n\
+>>> escape('\"1 < 2\"', quotes=False)\n\
+<Markup u'\"1 &lt; 2\"'>\n\
+\n\
+:param text: the text to escape\n\
+:param quotes: if ``True``, double quote characters are escaped in\n\
+               addition to the other special characters\n\
+:return: the escaped `Markup` string\n\
+:rtype: `Markup`\n\
+");
+
+static PyObject *
+Markup_escape(PyTypeObject* type, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"text", "quotes", 0};
+    PyObject *text = NULL;
+    char quotes = 1;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|b", kwlist, &text, &quotes)) {
+        return NULL;
+    }
+    if (PyObject_Not(text)) {
+        args = PyTuple_New(0);
+        if (args == NULL)
+            return NULL;
+        text = type->tp_new(type, args, NULL);
+        Py_DECREF(args);
+        return text;
+    }
+    if (PyObject_TypeCheck(text, type)) {
+        Py_INCREF(text);
+        return text;
+    }
+    return escape(text, quotes);
+}
+
+static PyObject *
+Markup_html(PyObject *self)
+{
+    Py_INCREF(self);
+    return self;
+}
+
+PyDoc_STRVAR(join__doc__,
+"Return a `Markup` object which is the concatenation of the strings\n\
+in the given sequence, where this `Markup` object is the separator\n\
+between the joined elements.\n\
+\n\
+Any element in the sequence that is not a `Markup` instance is\n\
+automatically escaped.\n\
+\n\
+:param seq: the sequence of strings to join\n\
+:param escape_quotes: whether double quote characters in the elements\n\
+                      should be escaped\n\
+:return: the joined `Markup` object\n\
+:rtype: `Markup`\n\
+:see: `escape`\n\
+");
+
+static PyObject *
+Markup_join(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"seq", "escape_quotes", 0};
+    PyObject *seq = NULL, *seq2, *tmp, *tmp2;
+    char quotes = 1;
+    Py_ssize_t n;
+    int i;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|b", kwlist, &seq, &quotes)) {
+        return NULL;
+    }
+    if (!PySequence_Check(seq)) {
+        return NULL;
+    }
+    n = PySequence_Size(seq);
+    if (n < 0) {
+        return NULL;
+    }
+    seq2 = PyTuple_New(n);
+    if (seq2 == NULL) {
+        return NULL;
+    }
+    for (i = 0; i < n; i++) {
+        tmp = PySequence_GetItem(seq, i);
+        if (tmp == NULL) {
+            Py_DECREF(seq2);
+            return NULL;
+        }
+        tmp2 = escape(tmp, quotes);
+        if (tmp2 == NULL) {
+            Py_DECREF(seq2);
+            return NULL;
+        }
+        PyTuple_SET_ITEM(seq2, i, tmp2);
+        Py_DECREF(tmp);
+    }
+    tmp = PyUnicode_Join(self, seq2);
+    Py_DECREF(seq2);
+    if (tmp == NULL)
+        return NULL;
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(tmp);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, tmp);
+    tmp = MarkupType.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+    return tmp;
+}
+
+static PyObject *
+Markup_add(PyObject *self, PyObject *other)
+{
+    PyObject *tmp, *tmp2, *args, *ret;
+    if (PyObject_TypeCheck(self, &MarkupType)) {
+        tmp = escape(other, 1);
+        if (tmp == NULL)
+            return NULL;
+        tmp2 = PyUnicode_Concat(self, tmp);
+    } else { // __radd__
+        tmp = escape(self, 1);
+        if (tmp == NULL)
+            return NULL;
+        tmp2 = PyUnicode_Concat(tmp, other);
+    }
+    Py_DECREF(tmp);
+    if (tmp2 == NULL)
+        return NULL;
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(tmp2);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, tmp2);
+    ret = MarkupType.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+    return ret;
+}
+
+static PyObject *
+Markup_mod(PyObject *self, PyObject *args)
+{
+    PyObject *tmp, *tmp2, *ret, *args2;
+    int i;
+    Py_ssize_t nargs = 0;
+    PyObject *kwds = NULL;
+
+    if (PyDict_Check(args)) {
+        kwds = args;
+    }
+    if (kwds && PyDict_Size(kwds)) {
+        PyObject *kwcopy, *key, *value;
+        Py_ssize_t pos = 0;
+
+        kwcopy = PyDict_Copy( kwds );
+        if (kwcopy == NULL) {
+            return NULL;
+        }
+        while (PyDict_Next(kwcopy, &pos, &key, &value)) {
+            tmp = escape(value, 1);
+            if (tmp == NULL) {
+                Py_DECREF(kwcopy);
+                return NULL;
+            }
+            if (PyDict_SetItem(kwcopy, key, tmp) < 0) {
+                Py_DECREF(tmp);
+                Py_DECREF(kwcopy);
+                return NULL;
+            }
+        }
+        tmp = PyUnicode_Format(self, kwcopy);
+        Py_DECREF(kwcopy);
+        if (tmp == NULL) {
+            return NULL;
+        }
+    } else if (PyTuple_Check(args)) {
+        nargs = PyTuple_GET_SIZE(args);
+        args2 = PyTuple_New(nargs);
+        if (args2 == NULL) {
+            return NULL;
+        }
+        for (i = 0; i < nargs; i++) {
+            tmp = escape(PyTuple_GET_ITEM(args, i), 1);
+            if (tmp == NULL) {
+                Py_DECREF(args2);
+                return NULL;
+            }
+            PyTuple_SET_ITEM(args2, i, tmp);
+        }
+        tmp = PyUnicode_Format(self, args2);
+        Py_DECREF(args2);
+        if (tmp == NULL) {
+            return NULL;
+        }
+    } else {
+        tmp2 = escape(args, 1);
+        if (tmp2 == NULL) {
+            return NULL;
+        }
+        tmp = PyUnicode_Format(self, tmp2);
+        Py_DECREF(tmp2);
+        if (tmp == NULL) {
+            return NULL;
+        }
+    }
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(tmp);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, tmp);
+    ret = PyUnicode_Type.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+    return ret;
+}
+
+static PyObject *
+Markup_mul(PyObject *self, PyObject *num)
+{
+    PyObject *unicode, *result, *args;
+
+    if (PyObject_TypeCheck(self, &MarkupType)) {
+        unicode = PyObject_Str(self);
+        if (unicode == NULL) return NULL;
+        result = PyNumber_Multiply(unicode, num);
+    } else { // __rmul__
+        unicode = PyObject_Str(num);
+        if (unicode == NULL) return NULL;
+        result = PyNumber_Multiply(unicode, self);
+    }
+    Py_DECREF(unicode);
+
+    if (result == NULL) return NULL;
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(result);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, result);
+    result = PyUnicode_Type.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+
+    return result;
+}
+
+static PyObject *
+Markup_repr(PyObject *self)
+{
+    PyObject *format, *result, *args;
+
+#ifdef IS_PY3K
+    format = PyUnicode_FromString("<Markup %r>");
+#else
+    format = PyString_FromString("<Markup %r>");
+#endif
+    if (format == NULL) return NULL;
+    result = PyObject_Str(self);
+    if (result == NULL) {
+        Py_DECREF(format);
+        return NULL;
+    }
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(format);
+        Py_DECREF(result);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, result);
+#ifdef IS_PY3K
+    result = PyUnicode_Format(format, args);
+#else
+    result = PyString_Format(format, args);
+#endif
+    Py_DECREF(format);
+    Py_DECREF(args);
+    return result;
+}
+
+PyDoc_STRVAR(unescape__doc__,
+"Reverse-escapes &, <, >, and \" and returns a `unicode` object.\n\
+\n\
+>>> Markup('1 &lt; 2').unescape()\n\
+u'1 < 2'\n\
+\n\
+:return: the unescaped string\n\
+:rtype: `unicode`\n\
+:see: `genshi.core.unescape`\n\
+");
+
+static PyObject *
+Markup_unescape(PyObject* self)
+{
+    PyObject *tmp, *tmp2;
+
+    tmp = PyUnicode_Replace(self, qt2, qt1, -1);
+    if (tmp == NULL) return NULL;
+    tmp2 = PyUnicode_Replace(tmp, gt2, gt1, -1);
+    Py_DECREF(tmp);
+    if (tmp2 == NULL) return NULL;
+    tmp = PyUnicode_Replace(tmp2, lt2, lt1, -1);
+    Py_DECREF(tmp2);
+    if (tmp == NULL) return NULL;
+    tmp2 = PyUnicode_Replace(tmp, amp2, amp1, -1);
+    Py_DECREF(tmp);
+    return tmp2;
+}
+
+PyDoc_STRVAR(stripentities__doc__,
+"Return a copy of the text with any character or numeric entities\n\
+replaced by the equivalent UTF-8 characters.\n\
+\n\
+If the `keepxmlentities` parameter is provided and evaluates to `True`,\n\
+the core XML entities (``&amp;``, ``&apos;``, ``&gt;``, ``&lt;`` and\n\
+``&quot;``) are not stripped.\n\
+\n\
+:return: a `Markup` instance with entities removed\n\
+:rtype: `Markup`\n\
+:see: `genshi.util.stripentities`\n\
+");
+
+static PyObject *
+Markup_stripentities(PyObject* self, PyObject *args, PyObject *kwds)
+{
+    static char *kwlist[] = {"keepxmlentities", 0};
+    PyObject *result, *args2;
+    char keepxml = 0;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|b", kwlist, &keepxml)) {
+        return NULL;
+    }
+
+    if (stripentities == NULL) return NULL;
+    result = PyObject_CallFunction(stripentities, "Ob", self, keepxml);
+    if (result == NULL) return NULL;
+    args2 = PyTuple_New(1);
+    if (args2 == NULL) {
+        Py_DECREF(result);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args2, 0, result);
+    result = MarkupType.tp_new(&MarkupType, args2, NULL);
+    Py_DECREF(args2);
+    return result;
+}
+
+PyDoc_STRVAR(striptags__doc__,
+"""Return a copy of the text with all XML/HTML tags removed.\n\
+\n\
+:return: a `Markup` instance with all tags removed\n\
+:rtype: `Markup`\n\
+:see: `genshi.util.striptags`\n\
+");
+
+static PyObject *
+Markup_striptags(PyObject* self)
+{
+    PyObject *result, *args;
+
+    if (striptags == NULL) return NULL;
+    result = PyObject_CallFunction(striptags, "O", self);
+    if (result == NULL) return NULL;
+    args = PyTuple_New(1);
+    if (args == NULL) {
+        Py_DECREF(result);
+        return NULL;
+    }
+    PyTuple_SET_ITEM(args, 0, result);
+    result = MarkupType.tp_new(&MarkupType, args, NULL);
+    Py_DECREF(args);
+    return result;
+}
+
+typedef struct {
+    PyUnicodeObject HEAD;
+} MarkupObject;
+
+static PyMethodDef Markup_methods[] = {
+    {"__html__", (PyCFunction) Markup_html, METH_NOARGS, NULL},
+    {"escape", (PyCFunction) Markup_escape,
+     METH_VARARGS|METH_CLASS|METH_KEYWORDS, escape__doc__},
+    {"join", (PyCFunction)Markup_join, METH_VARARGS|METH_KEYWORDS, join__doc__},
+    {"unescape", (PyCFunction)Markup_unescape, METH_NOARGS, unescape__doc__},
+    {"stripentities", (PyCFunction) Markup_stripentities,
+     METH_VARARGS|METH_KEYWORDS, stripentities__doc__},
+    {"striptags", (PyCFunction) Markup_striptags, METH_NOARGS,
+     striptags__doc__},
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods Markup_as_number = {
+    Markup_add, /*nb_add*/
+    0, /*nb_subtract*/
+    Markup_mul, /*nb_multiply*/
+#ifndef IS_PY3K
+    0, /*nb_divide*/
+#endif
+    Markup_mod, /*nb_remainder*/
+};
+
+PyTypeObject MarkupType = {
+#ifdef IS_PY3K
+    PyVarObject_HEAD_INIT(NULL, 0)
+#else
+    PyObject_HEAD_INIT(NULL)
+    0,
+#endif
+    "genshi._speedups.Markup",
+    sizeof(MarkupObject),
+    0,
+    0,          /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+#ifdef IS_PY3K
+    0,          /*tp_reserved*/
+#else
+    0,          /*tp_compare*/
+#endif
+    Markup_repr, /*tp_repr*/
+    &Markup_as_number, /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+
+    0,          /*tp_call*/
+    0,          /*tp_str*/
+    0,          /*tp_getattro*/
+    0,          /*tp_setattro*/
+    0,          /*tp_as_buffer*/
+
+#ifdef IS_PY3K
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_UNICODE_SUBCLASS, /*tp_flags*/
+#elif defined(Py_TPFLAGS_UNICODE_SUBCLASS)
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_UNICODE_SUBCLASS, /*tp_flags*/
+#else
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+#endif
+
+    Markup__doc__,/*tp_doc*/
+
+    0,          /*tp_traverse*/
+    0,          /*tp_clear*/
+
+    0,          /*tp_richcompare*/
+    0,          /*tp_weaklistoffset*/
+
+    0,          /*tp_iter*/
+    0,          /*tp_iternext*/
+
+    /* Attribute descriptor and subclassing stuff */
+
+    Markup_methods,/*tp_methods*/
+    0,          /*tp_members*/
+    0,          /*tp_getset*/
+    0,          /*tp_base*/
+    0,          /*tp_dict*/
+
+    0,          /*tp_descr_get*/
+    0,          /*tp_descr_set*/
+    0,          /*tp_dictoffset*/
+
+    0,          /*tp_init*/
+    0,          /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
+    0,          /*tp_new*/
+    0,          /*tp_free  Low-level free-memory routine */
+    0,          /*tp_is_gc For PyObject_IS_GC */
+    0,          /*tp_bases*/
+    0,          /*tp_mro method resolution order */
+    0,          /*tp_cache*/
+    0,          /*tp_subclasses*/
+    0           /*tp_weaklist*/
+};
+
+#ifdef IS_PY3K
+struct PyModuleDef module_def = {
+    PyModuleDef_HEAD_INIT, /*m_base*/
+    "_speedups",           /*m_name*/
+    NULL,                  /*m_doc*/
+    -1,                    /*m_size*/
+    NULL,                  /*m_methods*/
+    NULL,                  /*m_reload*/
+    NULL,                  /*m_traverse*/
+    NULL,                  /*m_clear*/
+    NULL                   /*m_free*/
+};
+
+PyObject *
+PyInit__speedups(void)
+#else
+PyMODINIT_FUNC
+init_speedups(void)
+#endif
+{
+    PyObject *module;
+
+    /* Workaround for quirk in Visual Studio, see
+        <http://www.python.it/faq/faq-3.html#3.24> */
+    MarkupType.tp_base = &PyUnicode_Type;
+
+    if (PyType_Ready(&MarkupType) < 0)
+#ifdef IS_PY3K
+        return NULL;
+#else
+        return;
+#endif
+
+    init_constants();
+
+#ifdef IS_PY3K
+    module = PyModule_Create(&module_def);
+#else
+    module = Py_InitModule("_speedups", NULL);
+#endif
+    Py_INCREF(&MarkupType);
+    PyModule_AddObject(module, "Markup", (PyObject *) &MarkupType);
+
+#ifdef IS_PY3K
+    return module;
+#endif
+}
diff --git a/lib/genshi/genshi/builder.py b/lib/genshi/genshi/builder.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/genshi/builder.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""Support for programmatically generating markup streams from Python code using
+a very simple syntax. The main entry point to this module is the `tag` object
+(which is actually an instance of the ``ElementFactory`` class). You should
+rarely (if ever) need to directly import and use any of the other classes in
+this module.
+
+Elements can be created using the `tag` object using attribute access. For
+example:
+
+>>> doc = tag.p('Some text and ', tag.a('a link', href='http://example.org/'), '.')
+>>> doc
+<Element "p">
+
+This produces an `Element` instance which can be further modified to add child
+nodes and attributes. This is done by "calling" the element: positional
+arguments are added as child nodes (alternatively, the `Element.append` method
+can be used for that purpose), whereas keywords arguments are added as
+attributes:
+
+>>> doc(tag.br)
+<Element "p">
+>>> print(doc)
+<p>Some text and <a href="http://example.org/">a link</a>.<br/></p>
+
+If an attribute name collides with a Python keyword, simply append an underscore
+to the name:
+
+>>> doc(class_='intro')
+<Element "p">
+>>> print(doc)
+<p class="intro">Some text and <a href="http://example.org/">a link</a>.<br/></p>
+
+As shown above, an `Element` can easily be directly rendered to XML text by
+printing it or using the Python ``str()`` function. This is basically a
+shortcut for converting the `Element` to a stream and serializing that
+stream:
+
+>>> stream = doc.generate()
+>>> stream #doctest: +ELLIPSIS
+<genshi.core.Stream object at ...>
+>>> print(stream)
+<p class="intro">Some text and <a href="http://example.org/">a link</a>.<br/></p>
+
+
+The `tag` object also allows creating "fragments", which are basically lists
+of nodes (elements or text) that don't have a parent element. This can be useful
+for creating snippets of markup that are attached to a parent element later (for
+example in a template). Fragments are created by calling the `tag` object, which
+returns an object of type `Fragment`:
+
+>>> fragment = tag('Hello, ', tag.em('world'), '!')
+>>> fragment
+<Fragment>
+>>> print(fragment)
+Hello, <em>world</em>!
+"""
+
+from genshi.core import Attrs, Markup, Namespace, QName, Stream, \
+                        START, END, TEXT
+
+__all__ = ['Fragment', 'Element', 'ElementFactory', 'tag']
+__docformat__ = 'restructuredtext en'
+
+
+class Fragment(object):
+    """Represents a markup fragment, which is basically just a list of element
+    or text nodes.
+    """
+    __slots__ = ['children']
+
+    def __init__(self):
+        """Create a new fragment."""
+        self.children = []
+
+    def __add__(self, other):
+        return Fragment()(self, other)
+
+    def __call__(self, *args):
+        """Append any positional arguments as child nodes.
+        
+        :see: `append`
+        """
+        for arg in args:
+            self.append(arg)
+        return self
+
+    def __iter__(self):
+        return self._generate()
+
+    def __repr__(self):
+        return '<%s>' % type(self).__name__
+
+    def __str__(self):
+        return str(self.generate())
+
+    def __unicode__(self):
+        return unicode(self.generate())
+
+    def __html__(self):
+        return Markup(self.generate())
+
+    def append(self, node):
+        """Append an element or string as child node.
+        
+        :param node: the node to append; can be an `Element`, `Fragment`, or a
+                     `Stream`, or a Python string or number
+        """
+        if isinstance(node, (Stream, Element, basestring, int, float, long)):
+            # For objects of a known/primitive type, we avoid the check for
+            # whether it is iterable for better performance
+            self.children.append(node)
+        elif isinstance(node, Fragment):
+            self.children.extend(node.children)
+        elif node is not None:
+            try:
+                for child in node:
+                    self.append(child)
+            except TypeError:
+                self.children.append(node)
+
+    def _generate(self):
+        for child in self.children:
+            if isinstance(child, Fragment):
+                for event in child._generate():
+                    yield event
+            elif isinstance(child, Stream):
+                for event in child:
+                    yield event
+            else:
+                if not isinstance(child, basestring):
+                    child = unicode(child)
+                yield TEXT, child, (None, -1, -1)
+
+    def generate(self):
+        """Return a markup event stream for the fragment.
+        
+        :rtype: `Stream`
+        """
+        return Stream(self._generate())
+
+
+def _kwargs_to_attrs(kwargs):
+    attrs = []
+    names = set()
+    for name, value in kwargs.items():
+        name = name.rstrip('_').replace('_', '-')
+        if value is not None and name not in names:
+            attrs.append((QName(name), unicode(value)))
+            names.add(name)
+    return Attrs(attrs)
+
+
+class Element(Fragment):
+    """Simple XML output generator based on the builder pattern.
+
+    Construct XML elements by passing the tag name to the constructor:
+
+    >>> print(Element('strong'))
+    <strong/>
+
+    Attributes can be specified using keyword arguments. The values of the
+    arguments will be converted to strings and any special XML characters
+    escaped:
+
+    >>> print(Element('textarea', rows=10, cols=60))
+    <textarea rows="10" cols="60"/>
+    >>> print(Element('span', title='1 < 2'))
+    <span title="1 &lt; 2"/>
+    >>> print(Element('span', title='"baz"'))
+    <span title="&#34;baz&#34;"/>
+
+    The " character is escaped using a numerical entity.
+    The order in which attributes are rendered is undefined.
+
+    If an attribute value evaluates to `None`, that attribute is not included
+    in the output:
+
+    >>> print(Element('a', name=None))
+    <a/>
+
+    Attribute names that conflict with Python keywords can be specified by
+    appending an underscore:
+
+    >>> print(Element('div', class_='warning'))
+    <div class="warning"/>
+
+    Nested elements can be added to an element using item access notation.
+    The call notation can also be used for this and for adding attributes
+    using keyword arguments, as one would do in the constructor.
+
+    >>> print(Element('ul')(Element('li'), Element('li')))
+    <ul><li/><li/></ul>
+    >>> print(Element('a')('Label'))
+    <a>Label</a>
+    >>> print(Element('a')('Label', href="target"))
+    <a href="target">Label</a>
+
+    Text nodes can be nested in an element by adding strings instead of
+    elements. Any special characters in the strings are escaped automatically:
+
+    >>> print(Element('em')('Hello world'))
+    <em>Hello world</em>
+    >>> print(Element('em')(42))
+    <em>42</em>
+    >>> print(Element('em')('1 < 2'))
+    <em>1 &lt; 2</em>
+
+    This technique also allows mixed content:
+
+    >>> print(Element('p')('Hello ', Element('b')('world')))
+    <p>Hello <b>world</b></p>
+
+    Quotes are not escaped inside text nodes:
+    >>> print(Element('p')('"Hello"'))
+    <p>"Hello"</p>
+
+    Elements can also be combined with other elements or strings using the
+    addition operator, which results in a `Fragment` object that contains the
+    operands:
+    
+    >>> print(Element('br') + 'some text' + Element('br'))
+    <br/>some text<br/>
+    
+    Elements with a namespace can be generated using the `Namespace` and/or
+    `QName` classes:
+    
+    >>> from genshi.core import Namespace
+    >>> xhtml = Namespace('http://www.w3.org/1999/xhtml')
+    >>> print(Element(xhtml.html, lang='en'))
+    <html xmlns="http://www.w3.org/1999/xhtml" lang="en"/>
+    """
+    __slots__ = ['tag', 'attrib']
+
+    def __init__(self, tag_, **attrib):
+        Fragment.__init__(self)
+        self.tag = QName(tag_)
+        self.attrib = _kwargs_to_attrs(attrib)
+
+    def __call__(self, *args, **kwargs):
+        """Append any positional arguments as child nodes, and keyword arguments
+        as attributes.
+        
+        :return: the element itself so that calls can be chained
+        :rtype: `Element`
+        :see: `Fragment.append`
+        """
+        self.attrib |= _kwargs_to_attrs(kwargs)
+        Fragment.__call__(self, *args)
+        return self
+
+    def __repr__(self):
+        return '<%s "%s">' % (type(self).__name__, self.tag)
+
+    def _generate(self):
+        yield START, (self.tag, self.attrib), (None, -1, -1)
+        for kind, data, pos in Fragment._generate(self):
+            yield kind, data, pos
+        yield END, self.tag, (None, -1, -1)
+
+    def generate(self):
+        """Return a markup event stream for the fragment.
+        
+        :rtype: `Stream`
+        """
+        return Stream(self._generate())
+
+
+class ElementFactory(object):
+    """Factory for `Element` objects.
+    
+    A new element is created simply by accessing a correspondingly named
+    attribute of the factory object:
+    
+    >>> factory = ElementFactory()
+    >>> print(factory.foo)
+    <foo/>
+    >>> print(factory.foo(id=2))
+    <foo id="2"/>
+    
+    Markup fragments (lists of nodes without a parent element) can be created
+    by calling the factory:
+    
+    >>> print(factory('Hello, ', factory.em('world'), '!'))
+    Hello, <em>world</em>!
+    
+    A factory can also be bound to a specific namespace:
+    
+    >>> factory = ElementFactory('http://www.w3.org/1999/xhtml')
+    >>> print(factory.html(lang="en"))
+    <html xmlns="http://www.w3.org/1999/xhtml" lang="en"/>
+    
+    The namespace for a specific element can be altered on an existing factory
+    by specifying the new namespace using item access:
+    
+    >>> factory = ElementFactory()
+    >>> print(factory.html(factory['http://www.w3.org/2000/svg'].g(id=3)))
+    <html><g xmlns="http://www.w3.org/2000/svg" id="3"/></html>
+    
+    Usually, the `ElementFactory` class is not be used directly. Rather, the
+    `tag` instance should be used to create elements.
+    """
+
+    def __init__(self, namespace=None):
+        """Create the factory, optionally bound to the given namespace.
+        
+        :param namespace: the namespace URI for any created elements, or `None`
+                          for no namespace
+        """
+        if namespace and not isinstance(namespace, Namespace):
+            namespace = Namespace(namespace)
+        self.namespace = namespace
+
+    def __call__(self, *args):
+        """Create a fragment that has the given positional arguments as child
+        nodes.
+
+        :return: the created `Fragment`
+        :rtype: `Fragment`
+        """
+        return Fragment()(*args)
+
+    def __getitem__(self, namespace):
+        """Return a new factory that is bound to the specified namespace.
+        
+        :param namespace: the namespace URI or `Namespace` object
+        :return: an `ElementFactory` that produces elements bound to the given
+                 namespace
+        :rtype: `ElementFactory`
+        """
+        return ElementFactory(namespace)
+
+    def __getattr__(self, name):
+        """Create an `Element` with the given name.
+        
+        :param name: the tag name of the element to create
+        :return: an `Element` with the specified name
+        :rtype: `Element`
+        """
+        return Element(self.namespace and self.namespace[name] or name)
+
+
+tag = ElementFactory()
+"""Global `ElementFactory` bound to the default namespace.
+
+:type: `ElementFactory`
+"""
diff --git a/lib/genshi/genshi/compat.py b/lib/genshi/genshi/compat.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/genshi/compat.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""Various Python version compatibility classes and functions."""
+
+import sys
+from types import CodeType
+
+
+IS_PYTHON2 = (sys.version_info[0] == 2)
+
+
+# This function should only be called in Python 2, and will fail in Python 3
+
+if IS_PYTHON2:
+    def stringrepr(string):
+        ascii = string.encode('ascii', 'backslashreplace')
+        quoted = "'" +  ascii.replace("'", "\\'") + "'"
+        if len(ascii) > len(string):
+            return 'u' + quoted
+        return quoted
+else:
+    def stringrepr(string):
+        raise RuntimeError(
+                'Python 2 compatibility function. Not usable in Python 3.')
+
+
+# We need to differentiate between StringIO and BytesIO in places
+
+if IS_PYTHON2:
+    from StringIO import StringIO
+    try:
+        from cStringIO import StringIO as BytesIO
+    except ImportError:
+        BytesIO = StringIO
+else:
+    from io import StringIO, BytesIO
+
+
+# We want to test bytestring input to some stuff.
+
+if IS_PYTHON2:
+    def wrapped_bytes(bstr):
+        assert bstr.startswith('b')
+        return bstr[1:]
+else:
+    def wrapped_bytes(bstr):
+        assert bstr.startswith('b')
+        return bstr
+
+
+# We do some scary stuff with CodeType() in template/eval.py
+
+if IS_PYTHON2:
+    def get_code_params(code):
+        return (code.co_nlocals, code.co_stacksize, code.co_flags,
+                code.co_code, code.co_consts, code.co_names, code.co_varnames,
+                code.co_filename, code.co_name, code.co_firstlineno,
+                code.co_lnotab, (), ())
+
+    def build_code_chunk(code, filename, name, lineno):
+        return CodeType(0, code.co_nlocals, code.co_stacksize,
+                        code.co_flags | 0x0040, code.co_code, code.co_consts,
+                        code.co_names, code.co_varnames, filename, name,
+                        lineno, code.co_lnotab, (), ())
+else:
+    def get_code_params(code):
+        return (code.co_nlocals, code.co_kwonlyargcount, code.co_stacksize,
+                code.co_flags, code.co_code, code.co_consts, code.co_names,
+                code.co_varnames, code.co_filename, code.co_name,
+                code.co_firstlineno, code.co_lnotab, (), ())
+
+    def build_code_chunk(code, filename, name, lineno):
+        return CodeType(0, code.co_nlocals, code.co_kwonlyargcount,
+                        code.co_stacksize, code.co_flags | 0x0040,
+                        code.co_code, code.co_consts, code.co_names,
+                        code.co_varnames, filename, name, lineno,
+                        code.co_lnotab, (), ())
+
+# Compatibility fallback implementations for Python < 2.6
+
+try:
+    next = next
+except NameError:
+    def next(iterator):
+        return iterator.next()
+
+# Compatibility fallback implementations for Python < 2.5
+
+try:
+    all = all
+    any = any
+except NameError:
+    def any(S):
+        for x in S:
+            if x:
+                return True
+        return False
+
+    def all(S):
+        for x in S:
+            if not x:
+                return False
+        return True
+
diff --git a/lib/genshi/genshi/core.py b/lib/genshi/genshi/core.py
new file mode 100644
--- /dev/null
+++ b/lib/genshi/genshi/core.py
@@ -0,0 +1,745 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""Core classes for markup processing."""
+
+try:
+    reduce # builtin in Python < 3
+except NameError:
+    from functools import reduce
+import sys
+from itertools import chain
+import operator
+
+from genshi.util import plaintext, stripentities, striptags, stringrepr
+
+__all__ = ['Stream', 'Markup', 'escape', 'unescape', 'Attrs', 'Namespace',
+           'QName']
+__docformat__ = 'restructuredtext en'
+
+
+class StreamEventKind(str):
+    """A kind of event on a markup stream."""
+    __slots__ = []
+    _instances = {}
+
+    def __new__(cls, val):
+        return cls._instances.setdefault(val, str.__new__(cls, val))
+
+
+class Stream(object):
+    """Represents a stream of markup events.
+    
+    This class is basically an iterator over the events.
+    
+    Stream events are tuples of the form::
+    
+      (kind, data, position)
+    
+    where ``kind`` is the event kind (such as `START`, `END`, `TEXT`, etc),
+    ``data`` depends on the kind of event, and ``position`` is a
+    ``(filename, line, offset)`` tuple that contains the location of the
+    original element or text in the input. If the original location is unknown,
+    ``position`` is ``(None, -1, -1)``.
+    
+    Also provided are ways to serialize the stream to text. The `serialize()`
+    method will return an iterator over generated strings, while `render()`
+    returns the complete generated text at once. Both accept various parameters
+    that impact the way the stream is serialized.
+    """
+    __slots__ = ['events', 'serializer']
+
+    START = StreamEventKind('START') #: a start tag
+    END = StreamEventKind('END') #: an end tag
+    TEXT = StreamEventKind('TEXT') #: literal text
+    XML_DECL = StreamEventKind('XML_DECL') #: XML declaration
+    DOCTYPE = StreamEventKind('DOCTYPE') #: doctype declaration
+    START_NS = StreamEventKind('START_NS') #: start namespace mapping
+    END_NS = StreamEventKind('END_NS') #: end namespace mapping
+    START_CDATA = StreamEventKind('START_CDATA') #: start CDATA section
+    END_CDATA = StreamEventKind('END_CDATA') #: end CDATA section
+    PI = StreamEventKind('PI') #: processing instruction
+    COMMENT = StreamEventKind('COMMENT') #: comment
+
+    def __init__(self, events, serializer=None):
+        """Initialize the stream with a sequence of markup events.
+        
+        :param events: a sequence or iterable providing the events
+        :param serializer: the default serialization method to use for this
+                           stream
+
+        :note: Changed in 0.5: added the `serializer` argument
+        """
+        self.events = events #: The underlying iterable producing the events
+        self.serializer = serializer #: The default serializion method
+
+    def __iter__(self):
+        return iter(self.events)
+
+    def __or__(self, function):
+        """Override the "bitwise or" operator to apply filters or serializers
+        to the stream, providing a syntax similar to pipes on Unix shells.
+        
+        Assume the following stream produced by the `HTML` function:
+        
+        >>> from genshi.input import HTML
+        >>> html = HTML('''<p onclick="alert('Whoa')">Hello, world!</p>''', encoding='utf-8')
+        >>> print(html)
+        <p onclick="alert('Whoa')">Hello, world!</p>
+        
+        A filter such as the HTML sanitizer can be applied to that stream using
+        the pipe notation as follows:
+        
+        >>> from genshi.filters import HTMLSanitizer
+        >>> sanitizer = HTMLSanitizer()
+        >>> print(html | sanitizer)
+        <p>Hello, world!</p>
+        
+        Filters can be any function that accepts and produces a stream (where
+        a stream is anything that iterates over events):
+        
+        >>> def uppercase(stream):
+        ...     for kind, data, pos in stream:
+        ...         if kind is TEXT:
+        ...             data = data.upper()
+        ...         yield kind, data, pos
+        >>> print(html | sanitizer | uppercase)
+        <p>HELLO, WORLD!</p>
+        
+        Serializers can also be used with this notation:
+        
+        >>> from genshi.output import TextSerializer
+        >>> output = TextSerializer()
+        >>> print(html | sanitizer | uppercase | output)
+        HELLO, WORLD!
+        
+        Commonly, serializers should be used at the end of the "pipeline";
+        using them somewhere in the middle may produce unexpected results.
+        
+        :param function: the callable object that should be applied as a filter
+        :return: the filtered stream
+        :rtype: `Stream`
+        """
+        return Stream(_ensure(function(self)), serializer=self.serializer)
+
+    def filter(self, *filters):
+        """Apply filters to the stream.
+        
+        This method returns a new stream with the given filters applied. The
+        filters must be callables that accept the stream object as parameter,
+        and return the filtered stream.
+        
+        The call::
+        
+            stream.filter(filter1, filter2)
+        
+        is equivalent to::
+        
+            stream | filter1 | filter2
+        
+        :param filters: one or more callable objects that should be applied as
+                        filters
+        :return: the filtered stream
+        :rtype: `Stream`
+        """
+        return reduce(operator.or_, (self,) + filters)
+
+    def render(self, method=None, encoding=None, out=None, **kwargs):
+        """Return a string representation of the stream.
+        
+        Any additional keyword arguments are passed to the serializer, and thus
+        depend on the `method` parameter value.
+        
+        :param method: determines how the stream is serialized; can be either
+                       "xml", "xhtml", "html", "text", or a custom serializer
+                       class; if `None`, the default serialization method of
+                       the stream is used
+        :param encoding: how the output string should be encoded; if set to
+                         `None`, this method returns a `unicode` object
+        :param out: a file-like object that the output should be written to
+                    instead of being returned as one big string; note that if
+                    this is a file or socket (or similar), the `encoding` must
+                    not be `None` (that is, the output must be encoded)
+        :return: a `str` or `unicode` object (depending on the `encoding`
+                 parameter), or `None` if the `out` parameter is provided
+        :rtype: `basestring`
+        
+        :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
+        :note: Changed in 0.5: added the `out` parameter
+        """
+        from genshi.output import encode
+        if method is None:
+            method = self.serializer or 'xml'
+        generator = self.serialize(method=method, **kwargs)
+        return encode(generator, method=method, encoding=encoding, out=out)
+
+    def select(self, path, namespaces=None, variables=None):
+        """Return a new stream that contains the events matching the given
+        XPath expression.
+        
+        >>> from genshi import HTML
+        >>> stream = HTML('<doc><elem>foo</elem><elem>bar</elem></doc>', encoding='utf-8')
+        >>> print(stream.select('elem'))
+        <elem>foo</elem><elem>bar</elem>
+        >>> print(stream.select('elem/text()'))
+        foobar
+        
+        Note that the outermost element of the stream becomes the *context
+        node* for the XPath test. That means that the expression "doc" would
+        not match anything in the example above, because it only tests against
+        child elements of the outermost element:
+        
+        >>> print(stream.select('doc'))
+        <BLANKLINE>
+        
+        You can use the "." expression to match the context node itself
+        (although that usually makes little sense):
+        
+        >>> print(stream.select('.'))
+        <doc><elem>foo</elem><elem>bar</elem></doc>
+        
+        :param path: a string containing the XPath expression
+        :param namespaces: mapping of namespace prefixes used in the path
+        :param variables: mapping of variable names to values
+        :return: the selected substream
+        :rtype: `Stream`
+        :raises PathSyntaxError: if the given path expression is invalid or not
+                                 supported
+        """
+        from genshi.path import Path
+        return Path(path).select(self, namespaces, variables)
+
+    def serialize(self, method='xml', **kwargs):
+        """Generate strings corresponding to a specific serialization of the
+        stream.
+        
+        Unlike the `render()` method, this method is a generator that returns
+        the serialized output incrementally, as opposed to returning a single
+        string.
+        
+        Any additional keyword arguments are passed to the serializer, and thus
+        depend on the `method` parameter value.
+        
+        :param method: determines how the stream is serialized; can be either
+                       "xml", "xhtml", "html", "text", or a custom serializer
+                       class; if `None`, the default serialization method of
+                       the stream is used
+        :return: an iterator over the serialization results (`Markup` or
+                 `unicode` objects, depending on the serialization method)
+        :rtype: ``iterator``
+        :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer
+        """
+        from genshi.output import get_serializer
+        if method is None:
+            method = self.serializer or 'xml'
+        return get_serializer(method, **kwargs)(_ensure(self))
+
+    def __str__(self):
+        return self.render()
+
+    def __unicode__(self):
+        return self.render(encoding=None)
+
+    def __html__(self):
+        return self
+
+
+START = Stream.START
+END = Stream.END
+TEXT = Stream.TEXT
+XML_DECL = Stream.XML_DECL
+DOCTYPE = Stream.DOCTYPE
+START_NS = Stream.START_NS
+END_NS = Stream.END_NS
+START_CDATA = Stream.START_CDATA
+END_CDATA = Stream.END_CDATA
+PI = Stream.PI
+COMMENT = Stream.COMMENT
+
+
+def _ensure(stream):
+    """Ensure that every item on the stream is actually a markup event."""
+    stream = iter(stream)
+    event = stream.next()
+
+    # Check whether the iterable is a real markup event stream by examining the
+    # first item it yields; if it's not we'll need to do some conversion
+    if type(event) is not tuple or len(event) != 3:
+        for event in chain([event], stream):
+            if hasattr(event, 'totuple'):
+                event = event.totuple()
+            else:
+                event = TEXT, unicode(event), (None, -1, -1)
+            yield event
+        return
+
+    # This looks like a markup event stream, so we'll just pass it through
+    # unchanged
+    yield event
+    for event in stream:
+        yield event
+
+
+class Attrs(tuple):
+    """Immutable sequence type that stores the attributes of an element.
+    
+    Ordering of the attributes is preserved, while access by name is also
+    supported.


More information about the pypy-commit mailing list