Imported Upstream version 1.0.6 75/124275/1 upstream upstream/1.0.6
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 11 Apr 2017 04:50:46 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 11 Apr 2017 04:51:11 +0000 (13:51 +0900)
Change-Id: I9241d6ebb001a58c20998c1b099e9bd90ad535ef
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
192 files changed:
CHANGES [new file with mode: 0644]
LICENSE [new file with mode: 0644]
MANIFEST.in [new file with mode: 0644]
Mako.egg-info/PKG-INFO [new file with mode: 0644]
Mako.egg-info/SOURCES.txt [new file with mode: 0644]
Mako.egg-info/dependency_links.txt [new file with mode: 0644]
Mako.egg-info/entry_points.txt [new file with mode: 0644]
Mako.egg-info/not-zip-safe [new file with mode: 0644]
Mako.egg-info/requires.txt [new file with mode: 0644]
Mako.egg-info/top_level.txt [new file with mode: 0644]
PKG-INFO [new file with mode: 0644]
README.rst [new file with mode: 0644]
doc/_sources/caching.txt [new file with mode: 0644]
doc/_sources/changelog.txt [new file with mode: 0644]
doc/_sources/defs.txt [new file with mode: 0644]
doc/_sources/filtering.txt [new file with mode: 0644]
doc/_sources/index.txt [new file with mode: 0644]
doc/_sources/inheritance.txt [new file with mode: 0644]
doc/_sources/namespaces.txt [new file with mode: 0644]
doc/_sources/runtime.txt [new file with mode: 0644]
doc/_sources/syntax.txt [new file with mode: 0644]
doc/_sources/unicode.txt [new file with mode: 0644]
doc/_sources/usage.txt [new file with mode: 0644]
doc/_static/basic.css [new file with mode: 0644]
doc/_static/changelog.css [new file with mode: 0644]
doc/_static/classic.css [new file with mode: 0644]
doc/_static/comment-bright.png [new file with mode: 0644]
doc/_static/comment-close.png [new file with mode: 0644]
doc/_static/comment.png [new file with mode: 0644]
doc/_static/default.css [new file with mode: 0644]
doc/_static/docs.css [new file with mode: 0644]
doc/_static/doctools.js [new file with mode: 0644]
doc/_static/down-pressed.png [new file with mode: 0644]
doc/_static/down.png [new file with mode: 0644]
doc/_static/file.png [new file with mode: 0644]
doc/_static/jquery-1.11.1.js [new file with mode: 0644]
doc/_static/jquery.js [new file with mode: 0644]
doc/_static/makoLogo.png [new file with mode: 0644]
doc/_static/minus.png [new file with mode: 0644]
doc/_static/plus.png [new file with mode: 0644]
doc/_static/pygments.css [new file with mode: 0644]
doc/_static/searchtools.js [new file with mode: 0644]
doc/_static/sidebar.js [new file with mode: 0644]
doc/_static/site.css [new file with mode: 0644]
doc/_static/sphinx_paramlinks.css [new file with mode: 0644]
doc/_static/underscore-1.3.1.js [new file with mode: 0644]
doc/_static/underscore.js [new file with mode: 0644]
doc/_static/up-pressed.png [new file with mode: 0644]
doc/_static/up.png [new file with mode: 0644]
doc/_static/websupport.js [new file with mode: 0644]
doc/build/Makefile [new file with mode: 0644]
doc/build/builder/__init__.py [new file with mode: 0644]
doc/build/builder/builders.py [new file with mode: 0644]
doc/build/builder/util.py [new file with mode: 0644]
doc/build/caching.rst [new file with mode: 0644]
doc/build/changelog.rst [new file with mode: 0644]
doc/build/conf.py [new file with mode: 0644]
doc/build/defs.rst [new file with mode: 0644]
doc/build/filtering.rst [new file with mode: 0644]
doc/build/index.rst [new file with mode: 0644]
doc/build/inheritance.rst [new file with mode: 0644]
doc/build/namespaces.rst [new file with mode: 0644]
doc/build/requirements.txt [new file with mode: 0644]
doc/build/runtime.rst [new file with mode: 0644]
doc/build/static/docs.css [new file with mode: 0644]
doc/build/static/makoLogo.png [new file with mode: 0644]
doc/build/static/site.css [new file with mode: 0644]
doc/build/syntax.rst [new file with mode: 0644]
doc/build/templates/base.mako [new file with mode: 0644]
doc/build/templates/genindex.mako [new file with mode: 0644]
doc/build/templates/layout.mako [new file with mode: 0644]
doc/build/templates/page.mako [new file with mode: 0644]
doc/build/templates/rtd_layout.mako [new file with mode: 0644]
doc/build/templates/search.mako [new file with mode: 0644]
doc/build/unicode.rst [new file with mode: 0644]
doc/build/usage.rst [new file with mode: 0644]
doc/caching.html [new file with mode: 0644]
doc/changelog.html [new file with mode: 0644]
doc/defs.html [new file with mode: 0644]
doc/filtering.html [new file with mode: 0644]
doc/genindex.html [new file with mode: 0644]
doc/index.html [new file with mode: 0644]
doc/inheritance.html [new file with mode: 0644]
doc/namespaces.html [new file with mode: 0644]
doc/runtime.html [new file with mode: 0644]
doc/search.html [new file with mode: 0644]
doc/searchindex.js [new file with mode: 0644]
doc/syntax.html [new file with mode: 0644]
doc/unicode.html [new file with mode: 0644]
doc/usage.html [new file with mode: 0644]
examples/bench/basic.py [new file with mode: 0644]
examples/bench/cheetah/footer.tmpl [new file with mode: 0644]
examples/bench/cheetah/header.tmpl [new file with mode: 0644]
examples/bench/cheetah/template.tmpl [new file with mode: 0644]
examples/bench/django/templatetags/__init__.py [new file with mode: 0644]
examples/bench/django/templatetags/bench.py [new file with mode: 0644]
examples/bench/kid/base.kid [new file with mode: 0644]
examples/bench/kid/template.kid [new file with mode: 0644]
examples/bench/myghty/base.myt [new file with mode: 0644]
examples/bench/myghty/template.myt [new file with mode: 0644]
examples/wsgi/run_wsgi.py [new file with mode: 0644]
mako/__init__.py [new file with mode: 0644]
mako/_ast_util.py [new file with mode: 0644]
mako/ast.py [new file with mode: 0644]
mako/cache.py [new file with mode: 0644]
mako/cmd.py [new file with mode: 0755]
mako/codegen.py [new file with mode: 0644]
mako/compat.py [new file with mode: 0644]
mako/exceptions.py [new file with mode: 0644]
mako/ext/__init__.py [new file with mode: 0644]
mako/ext/autohandler.py [new file with mode: 0644]
mako/ext/babelplugin.py [new file with mode: 0644]
mako/ext/beaker_cache.py [new file with mode: 0644]
mako/ext/extract.py [new file with mode: 0644]
mako/ext/linguaplugin.py [new file with mode: 0644]
mako/ext/preprocessors.py [new file with mode: 0644]
mako/ext/pygmentplugin.py [new file with mode: 0644]
mako/ext/turbogears.py [new file with mode: 0644]
mako/filters.py [new file with mode: 0644]
mako/lexer.py [new file with mode: 0644]
mako/lookup.py [new file with mode: 0644]
mako/parsetree.py [new file with mode: 0644]
mako/pygen.py [new file with mode: 0644]
mako/pyparser.py [new file with mode: 0644]
mako/runtime.py [new file with mode: 0644]
mako/template.py [new file with mode: 0644]
mako/util.py [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
test/__init__.py [new file with mode: 0644]
test/ext/__init__.py [new file with mode: 0644]
test/ext/test_babelplugin.py [new file with mode: 0644]
test/ext/test_linguaplugin.py [new file with mode: 0644]
test/foo/__init__.py [new file with mode: 0644]
test/foo/test_ns.py [new file with mode: 0644]
test/sample_module_namespace.py [new file with mode: 0644]
test/templates/badbom.html [new file with mode: 0644]
test/templates/bom.html [new file with mode: 0644]
test/templates/bommagic.html [new file with mode: 0644]
test/templates/chs_unicode.html [new file with mode: 0644]
test/templates/chs_unicode_py3k.html [new file with mode: 0644]
test/templates/chs_utf8.html [new file with mode: 0644]
test/templates/cmd_good.mako [new file with mode: 0644]
test/templates/cmd_runtime.mako [new file with mode: 0644]
test/templates/cmd_syntax.mako [new file with mode: 0644]
test/templates/crlf.html [new file with mode: 0644]
test/templates/foo/modtest.html.py [new file with mode: 0644]
test/templates/gettext.mako [new file with mode: 0644]
test/templates/gettext_cp1251.mako [new file with mode: 0644]
test/templates/gettext_utf8.mako [new file with mode: 0644]
test/templates/index.html [new file with mode: 0644]
test/templates/internationalization.html [new file with mode: 0644]
test/templates/modtest.html [new file with mode: 0644]
test/templates/othersubdir/foo.html [new file with mode: 0644]
test/templates/read_unicode.html [new file with mode: 0644]
test/templates/read_unicode_py3k.html [new file with mode: 0644]
test/templates/runtimeerr.html [new file with mode: 0644]
test/templates/runtimeerr_py3k.html [new file with mode: 0644]
test/templates/subdir/foo/modtest.html.py [new file with mode: 0644]
test/templates/subdir/incl.html [new file with mode: 0644]
test/templates/subdir/index.html [new file with mode: 0644]
test/templates/subdir/modtest.html [new file with mode: 0644]
test/templates/unicode.html [new file with mode: 0644]
test/templates/unicode_arguments.html [new file with mode: 0644]
test/templates/unicode_arguments_py3k.html [new file with mode: 0644]
test/templates/unicode_code.html [new file with mode: 0644]
test/templates/unicode_code_py3k.html [new file with mode: 0644]
test/templates/unicode_expr.html [new file with mode: 0644]
test/templates/unicode_expr_py3k.html [new file with mode: 0644]
test/templates/unicode_runtime_error.html [new file with mode: 0644]
test/templates/unicode_syntax_error.html [new file with mode: 0644]
test/test_ast.py [new file with mode: 0644]
test/test_block.py [new file with mode: 0644]
test/test_cache.py [new file with mode: 0644]
test/test_call.py [new file with mode: 0644]
test/test_cmd.py [new file with mode: 0644]
test/test_decorators.py [new file with mode: 0644]
test/test_def.py [new file with mode: 0644]
test/test_exceptions.py [new file with mode: 0644]
test/test_filters.py [new file with mode: 0644]
test/test_inheritance.py [new file with mode: 0644]
test/test_lexer.py [new file with mode: 0644]
test/test_lookup.py [new file with mode: 0644]
test/test_loop.py [new file with mode: 0644]
test/test_lru.py [new file with mode: 0644]
test/test_namespace.py [new file with mode: 0644]
test/test_pygen.py [new file with mode: 0644]
test/test_runtime.py [new file with mode: 0644]
test/test_template.py [new file with mode: 0644]
test/test_tgplugin.py [new file with mode: 0644]
test/test_util.py [new file with mode: 0644]
test/util.py [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..f942ad9
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,15 @@
+=====
+MOVED
+=====
+
+Please see:
+
+    /docs/changelog.html
+
+    /docs/build/changelog.rst
+
+or
+
+    https://docs.makotemplates.org/en/latest/changelog.html
+
+for the current CHANGES.
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..86543fc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+This is the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>.
+Mako is a trademark of Michael Bayer.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..f6e0a5b
--- /dev/null
@@ -0,0 +1,11 @@
+# any kind of "*" pulls in __init__.pyc files,
+# so all extensions are explicit.
+
+recursive-include doc *.html *.css *.txt *.js *.png *.py Makefile *.rst *.mako
+recursive-include examples *.py *.xml *.mako *.myt *.kid *.tmpl
+recursive-include test *.py *.html *.mako
+
+include README* LICENSE distribute_setup.py ez_setup.py CHANGES*
+
+prune doc/build/output
+
diff --git a/Mako.egg-info/PKG-INFO b/Mako.egg-info/PKG-INFO
new file mode 100644 (file)
index 0000000..3122d63
--- /dev/null
@@ -0,0 +1,71 @@
+Metadata-Version: 1.1
+Name: Mako
+Version: 1.0.6
+Summary: A super-fast templating language that borrows the  best ideas from the existing templating languages.
+Home-page: http://www.makotemplates.org/
+Author: Mike Bayer
+Author-email: mike@zzzcomputing.com
+License: MIT
+Description: =========================
+        Mako Templates for Python
+        =========================
+        
+        Mako is a template library written in Python. It provides a familiar, non-XML 
+        syntax which compiles into Python modules for maximum performance. Mako's 
+        syntax and API borrows from the best ideas of many others, including Django
+        templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded 
+        Python (i.e. Python Server Page) language, which refines the familiar ideas
+        of componentized layout and inheritance to produce one of the most 
+        straightforward and flexible models available, while also maintaining close 
+        ties to Python calling and scoping semantics.
+        
+        Nutshell
+        ========
+        
+        ::
+        
+            <%inherit file="base.html"/>
+            <%
+                rows = [[v for v in range(0,10)] for row in range(0,10)]
+            %>
+            <table>
+                % for row in rows:
+                    ${makerow(row)}
+                % endfor
+            </table>
+        
+            <%def name="makerow(row)">
+                <tr>
+                % for name in row:
+                    <td>${name}</td>\
+                % endfor
+                </tr>
+            </%def>
+        
+        Philosophy
+        ===========
+        
+        Python is a great scripting language. Don't reinvent the wheel...your templates can handle it !
+        
+        Documentation
+        ==============
+        
+        See documentation for Mako at http://www.makotemplates.org/docs/
+        
+        License
+        ========
+        
+        Mako is licensed under an MIT-style license (see LICENSE).
+        Other incorporated projects may be licensed under different licenses.
+        All licenses allow for non-commercial and commercial use.
+        
+Keywords: templates
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
diff --git a/Mako.egg-info/SOURCES.txt b/Mako.egg-info/SOURCES.txt
new file mode 100644 (file)
index 0000000..1ed4eaf
--- /dev/null
@@ -0,0 +1,191 @@
+CHANGES
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+Mako.egg-info/PKG-INFO
+Mako.egg-info/SOURCES.txt
+Mako.egg-info/dependency_links.txt
+Mako.egg-info/entry_points.txt
+Mako.egg-info/not-zip-safe
+Mako.egg-info/requires.txt
+Mako.egg-info/top_level.txt
+doc/caching.html
+doc/changelog.html
+doc/defs.html
+doc/filtering.html
+doc/genindex.html
+doc/index.html
+doc/inheritance.html
+doc/namespaces.html
+doc/runtime.html
+doc/search.html
+doc/searchindex.js
+doc/syntax.html
+doc/unicode.html
+doc/usage.html
+doc/_sources/caching.txt
+doc/_sources/changelog.txt
+doc/_sources/defs.txt
+doc/_sources/filtering.txt
+doc/_sources/index.txt
+doc/_sources/inheritance.txt
+doc/_sources/namespaces.txt
+doc/_sources/runtime.txt
+doc/_sources/syntax.txt
+doc/_sources/unicode.txt
+doc/_sources/usage.txt
+doc/_static/basic.css
+doc/_static/changelog.css
+doc/_static/classic.css
+doc/_static/comment-bright.png
+doc/_static/comment-close.png
+doc/_static/comment.png
+doc/_static/default.css
+doc/_static/docs.css
+doc/_static/doctools.js
+doc/_static/down-pressed.png
+doc/_static/down.png
+doc/_static/file.png
+doc/_static/jquery-1.11.1.js
+doc/_static/jquery.js
+doc/_static/makoLogo.png
+doc/_static/minus.png
+doc/_static/plus.png
+doc/_static/pygments.css
+doc/_static/searchtools.js
+doc/_static/sidebar.js
+doc/_static/site.css
+doc/_static/sphinx_paramlinks.css
+doc/_static/underscore-1.3.1.js
+doc/_static/underscore.js
+doc/_static/up-pressed.png
+doc/_static/up.png
+doc/_static/websupport.js
+doc/build/Makefile
+doc/build/caching.rst
+doc/build/changelog.rst
+doc/build/conf.py
+doc/build/defs.rst
+doc/build/filtering.rst
+doc/build/index.rst
+doc/build/inheritance.rst
+doc/build/namespaces.rst
+doc/build/requirements.txt
+doc/build/runtime.rst
+doc/build/syntax.rst
+doc/build/unicode.rst
+doc/build/usage.rst
+doc/build/builder/__init__.py
+doc/build/builder/builders.py
+doc/build/builder/util.py
+doc/build/static/docs.css
+doc/build/static/makoLogo.png
+doc/build/static/site.css
+doc/build/templates/base.mako
+doc/build/templates/genindex.mako
+doc/build/templates/layout.mako
+doc/build/templates/page.mako
+doc/build/templates/rtd_layout.mako
+doc/build/templates/search.mako
+examples/bench/basic.py
+examples/bench/cheetah/footer.tmpl
+examples/bench/cheetah/header.tmpl
+examples/bench/cheetah/template.tmpl
+examples/bench/django/templatetags/__init__.py
+examples/bench/django/templatetags/bench.py
+examples/bench/kid/base.kid
+examples/bench/kid/template.kid
+examples/bench/myghty/base.myt
+examples/bench/myghty/template.myt
+examples/wsgi/run_wsgi.py
+mako/__init__.py
+mako/_ast_util.py
+mako/ast.py
+mako/cache.py
+mako/cmd.py
+mako/codegen.py
+mako/compat.py
+mako/exceptions.py
+mako/filters.py
+mako/lexer.py
+mako/lookup.py
+mako/parsetree.py
+mako/pygen.py
+mako/pyparser.py
+mako/runtime.py
+mako/template.py
+mako/util.py
+mako/ext/__init__.py
+mako/ext/autohandler.py
+mako/ext/babelplugin.py
+mako/ext/beaker_cache.py
+mako/ext/extract.py
+mako/ext/linguaplugin.py
+mako/ext/preprocessors.py
+mako/ext/pygmentplugin.py
+mako/ext/turbogears.py
+test/__init__.py
+test/sample_module_namespace.py
+test/test_ast.py
+test/test_block.py
+test/test_cache.py
+test/test_call.py
+test/test_cmd.py
+test/test_decorators.py
+test/test_def.py
+test/test_exceptions.py
+test/test_filters.py
+test/test_inheritance.py
+test/test_lexer.py
+test/test_lookup.py
+test/test_loop.py
+test/test_lru.py
+test/test_namespace.py
+test/test_pygen.py
+test/test_runtime.py
+test/test_template.py
+test/test_tgplugin.py
+test/test_util.py
+test/util.py
+test/ext/__init__.py
+test/ext/test_babelplugin.py
+test/ext/test_linguaplugin.py
+test/foo/__init__.py
+test/foo/test_ns.py
+test/templates/badbom.html
+test/templates/bom.html
+test/templates/bommagic.html
+test/templates/chs_unicode.html
+test/templates/chs_unicode_py3k.html
+test/templates/chs_utf8.html
+test/templates/cmd_good.mako
+test/templates/cmd_runtime.mako
+test/templates/cmd_syntax.mako
+test/templates/crlf.html
+test/templates/gettext.mako
+test/templates/gettext_cp1251.mako
+test/templates/gettext_utf8.mako
+test/templates/index.html
+test/templates/internationalization.html
+test/templates/modtest.html
+test/templates/read_unicode.html
+test/templates/read_unicode_py3k.html
+test/templates/runtimeerr.html
+test/templates/runtimeerr_py3k.html
+test/templates/unicode.html
+test/templates/unicode_arguments.html
+test/templates/unicode_arguments_py3k.html
+test/templates/unicode_code.html
+test/templates/unicode_code_py3k.html
+test/templates/unicode_expr.html
+test/templates/unicode_expr_py3k.html
+test/templates/unicode_runtime_error.html
+test/templates/unicode_syntax_error.html
+test/templates/foo/modtest.html.py
+test/templates/othersubdir/foo.html
+test/templates/subdir/incl.html
+test/templates/subdir/index.html
+test/templates/subdir/modtest.html
+test/templates/subdir/foo/modtest.html.py
\ No newline at end of file
diff --git a/Mako.egg-info/dependency_links.txt b/Mako.egg-info/dependency_links.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/Mako.egg-info/entry_points.txt b/Mako.egg-info/entry_points.txt
new file mode 100644 (file)
index 0000000..3b15006
--- /dev/null
@@ -0,0 +1,20 @@
+
+      [python.templating.engines]
+      mako = mako.ext.turbogears:TGPlugin
+
+      [pygments.lexers]
+      mako = mako.ext.pygmentplugin:MakoLexer
+      html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
+      xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
+      js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
+      css+mako = mako.ext.pygmentplugin:MakoCssLexer
+
+      [babel.extractors]
+      mako = mako.ext.babelplugin:extract
+
+      [lingua.extractors]
+      mako = mako.ext.linguaplugin:LinguaMakoExtractor
+
+      [console_scripts]
+      mako-render = mako.cmd:cmdline
+      
\ No newline at end of file
diff --git a/Mako.egg-info/not-zip-safe b/Mako.egg-info/not-zip-safe
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/Mako.egg-info/requires.txt b/Mako.egg-info/requires.txt
new file mode 100644 (file)
index 0000000..4083f59
--- /dev/null
@@ -0,0 +1 @@
+MarkupSafe>=0.9.2
diff --git a/Mako.egg-info/top_level.txt b/Mako.egg-info/top_level.txt
new file mode 100644 (file)
index 0000000..2951cdd
--- /dev/null
@@ -0,0 +1 @@
+mako
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644 (file)
index 0000000..3122d63
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,71 @@
+Metadata-Version: 1.1
+Name: Mako
+Version: 1.0.6
+Summary: A super-fast templating language that borrows the  best ideas from the existing templating languages.
+Home-page: http://www.makotemplates.org/
+Author: Mike Bayer
+Author-email: mike@zzzcomputing.com
+License: MIT
+Description: =========================
+        Mako Templates for Python
+        =========================
+        
+        Mako is a template library written in Python. It provides a familiar, non-XML 
+        syntax which compiles into Python modules for maximum performance. Mako's 
+        syntax and API borrows from the best ideas of many others, including Django
+        templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded 
+        Python (i.e. Python Server Page) language, which refines the familiar ideas
+        of componentized layout and inheritance to produce one of the most 
+        straightforward and flexible models available, while also maintaining close 
+        ties to Python calling and scoping semantics.
+        
+        Nutshell
+        ========
+        
+        ::
+        
+            <%inherit file="base.html"/>
+            <%
+                rows = [[v for v in range(0,10)] for row in range(0,10)]
+            %>
+            <table>
+                % for row in rows:
+                    ${makerow(row)}
+                % endfor
+            </table>
+        
+            <%def name="makerow(row)">
+                <tr>
+                % for name in row:
+                    <td>${name}</td>\
+                % endfor
+                </tr>
+            </%def>
+        
+        Philosophy
+        ===========
+        
+        Python is a great scripting language. Don't reinvent the wheel...your templates can handle it !
+        
+        Documentation
+        ==============
+        
+        See documentation for Mako at http://www.makotemplates.org/docs/
+        
+        License
+        ========
+        
+        Mako is licensed under an MIT-style license (see LICENSE).
+        Other incorporated projects may be licensed under different licenses.
+        All licenses allow for non-commercial and commercial use.
+        
+Keywords: templates
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..8da9d69
--- /dev/null
@@ -0,0 +1,52 @@
+=========================
+Mako Templates for Python
+=========================
+
+Mako is a template library written in Python. It provides a familiar, non-XML 
+syntax which compiles into Python modules for maximum performance. Mako's 
+syntax and API borrows from the best ideas of many others, including Django
+templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded 
+Python (i.e. Python Server Page) language, which refines the familiar ideas
+of componentized layout and inheritance to produce one of the most 
+straightforward and flexible models available, while also maintaining close 
+ties to Python calling and scoping semantics.
+
+Nutshell
+========
+
+::
+
+    <%inherit file="base.html"/>
+    <%
+        rows = [[v for v in range(0,10)] for row in range(0,10)]
+    %>
+    <table>
+        % for row in rows:
+            ${makerow(row)}
+        % endfor
+    </table>
+
+    <%def name="makerow(row)">
+        <tr>
+        % for name in row:
+            <td>${name}</td>\
+        % endfor
+        </tr>
+    </%def>
+
+Philosophy
+===========
+
+Python is a great scripting language. Don't reinvent the wheel...your templates can handle it !
+
+Documentation
+==============
+
+See documentation for Mako at http://www.makotemplates.org/docs/
+
+License
+========
+
+Mako is licensed under an MIT-style license (see LICENSE).
+Other incorporated projects may be licensed under different licenses.
+All licenses allow for non-commercial and commercial use.
diff --git a/doc/_sources/caching.txt b/doc/_sources/caching.txt
new file mode 100644 (file)
index 0000000..bfe4f41
--- /dev/null
@@ -0,0 +1,387 @@
+.. _caching_toplevel:
+
+=======
+Caching
+=======
+
+Any template or component can be cached using the ``cache``
+argument to the ``<%page>``, ``<%def>`` or ``<%block>`` directives:
+
+.. sourcecode:: mako
+
+    <%page cached="True"/>
+
+    template text
+
+The above template, after being executed the first time, will
+store its content within a cache that by default is scoped
+within memory. Subsequent calls to the template's :meth:`~.Template.render`
+method will return content directly from the cache. When the
+:class:`.Template` object itself falls out of scope, its corresponding
+cache is garbage collected along with the template.
+
+The caching system requires that a cache backend be installed; this
+includes either the `Beaker <http://beaker.readthedocs.org/>`_ package
+or the `dogpile.cache <http://dogpilecache.readthedocs.org>`_, as well as
+any other third-party caching libraries that feature Mako integration.
+
+By default, caching will attempt to make use of Beaker.
+To use dogpile.cache, the
+``cache_impl`` argument must be set; see this argument in the
+section :ref:`cache_arguments`.
+
+In addition to being available on the ``<%page>`` tag, the caching flag and all
+its options can be used with the ``<%def>`` tag as well:
+
+.. sourcecode:: mako
+
+    <%def name="mycomp" cached="True" cache_timeout="60">
+        other text
+    </%def>
+
+... and equivalently with the ``<%block>`` tag, anonymous or named:
+
+.. sourcecode:: mako
+
+    <%block cached="True" cache_timeout="60">
+        other text
+    </%block>
+
+
+.. _cache_arguments:
+
+Cache Arguments
+===============
+
+Mako has two cache arguments available on tags that are
+available in all cases.   The rest of the arguments
+available are specific to a backend.
+
+The two generic tags arguments are:
+
+* ``cached="True"`` - enable caching for this ``<%page>``,
+  ``<%def>``, or ``<%block>``.
+* ``cache_key`` - the "key" used to uniquely identify this content
+  in the cache.   Usually, this key is chosen automatically
+  based on the name of the rendering callable (i.e. ``body``
+  when used in ``<%page>``, the name of the def when using ``<%def>``,
+  the explicit or internally-generated name when using ``<%block>``).
+  Using the ``cache_key`` parameter, the key can be overridden
+  using a fixed or programmatically generated value.
+
+  For example, here's a page
+  that caches any page which inherits from it, based on the
+  filename of the calling template:
+
+  .. sourcecode:: mako
+
+     <%page cached="True" cache_key="${self.filename}"/>
+
+     ${next.body()}
+
+     ## rest of template
+
+On a :class:`.Template` or :class:`.TemplateLookup`, the
+caching can be configured using these arguments:
+
+* ``cache_enabled`` - Setting this
+  to ``False`` will disable all caching functionality
+  when the template renders.  Defaults to ``True``.
+  e.g.:
+
+  .. sourcecode:: python
+
+      lookup = TemplateLookup(
+                      directories='/path/to/templates',
+                      cache_enabled = False
+                      )
+
+* ``cache_impl`` - The string name of the cache backend
+  to use.   This defaults to ``'beaker'``, indicating
+  that the 'beaker' backend will be used.
+
+* ``cache_args`` - A dictionary of cache parameters that
+  will be consumed by the cache backend.   See
+  :ref:`beaker_backend` and :ref:`dogpile.cache_backend` for examples.
+
+
+Backend-Specific Cache Arguments
+--------------------------------
+
+The ``<%page>``, ``<%def>``, and ``<%block>`` tags
+accept any named argument that starts with the prefix ``"cache_"``.
+Those arguments are then packaged up and passed along to the
+underlying caching implementation, minus the ``"cache_"`` prefix.
+
+The actual arguments understood are determined by the backend.
+
+* :ref:`beaker_backend` - Includes arguments understood by
+  Beaker.
+* :ref:`dogpile.cache_backend` - Includes arguments understood by
+  dogpile.cache.
+
+.. _beaker_backend:
+
+Using the Beaker Cache Backend
+------------------------------
+
+When using Beaker, new implementations will want to make usage
+of **cache regions** so that cache configurations can be maintained
+externally to templates.  These configurations live under
+named "regions" that can be referred to within templates themselves.
+
+.. versionadded:: 0.6.0
+   Support for Beaker cache regions.
+
+For example, suppose we would like two regions.  One is a "short term"
+region that will store content in a memory-based dictionary,
+expiring after 60 seconds.   The other is a Memcached region,
+where values should expire in five minutes.   To configure
+our :class:`.TemplateLookup`, first we get a handle to a
+:class:`beaker.cache.CacheManager`:
+
+.. sourcecode:: python
+
+    from beaker.cache import CacheManager
+
+    manager = CacheManager(cache_regions={
+        'short_term':{
+            'type': 'memory',
+            'expire': 60
+        },
+        'long_term':{
+            'type': 'ext:memcached',
+            'url': '127.0.0.1:11211',
+            'expire': 300
+        }
+    })
+
+    lookup = TemplateLookup(
+                    directories=['/path/to/templates'],
+                    module_directory='/path/to/modules',
+                    cache_impl='beaker',
+                    cache_args={
+                        'manager':manager
+                    }
+            )
+
+Our templates can then opt to cache data in one of either region,
+using the ``cache_region`` argument.   Such as using ``short_term``
+at the ``<%page>`` level:
+
+.. sourcecode:: mako
+
+    <%page cached="True" cache_region="short_term">
+
+    ## ...
+
+Or, ``long_term`` at the ``<%block>`` level:
+
+.. sourcecode:: mako
+
+    <%block name="header" cached="True" cache_region="long_term">
+        other text
+    </%block>
+
+The Beaker backend also works without regions.   There are a
+variety of arguments that can be passed to the ``cache_args``
+dictionary, which are also allowable in templates via the
+``<%page>``, ``<%block>``,
+and ``<%def>`` tags specific to those sections.   The values
+given override those specified at the  :class:`.TemplateLookup`
+or :class:`.Template` level.
+
+With the possible exception
+of ``cache_timeout``, these arguments are probably better off
+staying at the template configuration level.  Each argument
+specified as ``cache_XYZ`` in a template tag is specified
+without the ``cache_`` prefix in the ``cache_args`` dictionary:
+
+* ``cache_timeout`` - number of seconds in which to invalidate the
+  cached data.  After this timeout, the content is re-generated
+  on the next call.  Available as ``timeout`` in the ``cache_args``
+  dictionary.
+* ``cache_type`` - type of caching. ``'memory'``, ``'file'``, ``'dbm'``, or
+  ``'ext:memcached'`` (note that  the string ``memcached`` is
+  also accepted by the dogpile.cache Mako plugin, though not by Beaker itself).
+  Available as ``type`` in the ``cache_args`` dictionary.
+* ``cache_url`` - (only used for ``memcached`` but required) a single
+  IP address or a semi-colon separated list of IP address of
+  memcache servers to use.  Available as ``url`` in the ``cache_args``
+  dictionary.
+* ``cache_dir`` - in the case of the ``'file'`` and ``'dbm'`` cache types,
+  this is the filesystem directory with which to store data
+  files. If this option is not present, the value of
+  ``module_directory`` is used (i.e. the directory where compiled
+  template modules are stored). If neither option is available
+  an exception is thrown.  Available as ``dir`` in the
+  ``cache_args`` dictionary.
+
+.. _dogpile.cache_backend:
+
+Using the dogpile.cache Backend
+-------------------------------
+
+`dogpile.cache`_ is a new replacement for Beaker.   It provides
+a modernized, slimmed down interface and is generally easier to use
+than Beaker.   As of this writing it has not yet been released.  dogpile.cache
+includes its own Mako cache plugin -- see :mod:`dogpile.cache.plugins.mako_cache` in the
+dogpile.cache documentation.
+
+Programmatic Cache Access
+=========================
+
+The :class:`.Template`, as well as any template-derived :class:`.Namespace`, has
+an accessor called ``cache`` which returns the :class:`.Cache` object
+for that template. This object is a facade on top of the underlying
+:class:`.CacheImpl` object, and provides some very rudimental
+capabilities, such as the ability to get and put arbitrary
+values:
+
+.. sourcecode:: mako
+
+    <%
+        local.cache.set("somekey", type="memory", "somevalue")
+    %>
+
+Above, the cache associated with the ``local`` namespace is
+accessed and a key is placed within a memory cache.
+
+More commonly, the ``cache`` object is used to invalidate cached
+sections programmatically:
+
+.. sourcecode:: python
+
+    template = lookup.get_template('/sometemplate.html')
+
+    # invalidate the "body" of the template
+    template.cache.invalidate_body()
+
+    # invalidate an individual def
+    template.cache.invalidate_def('somedef')
+
+    # invalidate an arbitrary key
+    template.cache.invalidate('somekey')
+
+You can access any special method or attribute of the :class:`.CacheImpl`
+itself using the :attr:`impl <.Cache.impl>` attribute:
+
+.. sourcecode:: python
+
+    template.cache.impl.do_something_special()
+
+Note that using implementation-specific methods will mean you can't
+swap in a different kind of :class:`.CacheImpl` implementation at a
+later time.
+
+.. _cache_plugins:
+
+Cache Plugins
+=============
+
+The mechanism used by caching can be plugged in
+using a :class:`.CacheImpl` subclass.    This class implements
+the rudimental methods Mako needs to implement the caching
+API.   Mako includes the :class:`.BeakerCacheImpl` class to
+provide the default implementation.  A :class:`.CacheImpl` class
+is acquired by Mako using a ``pkg_resources`` entrypoint, using
+the name given as the ``cache_impl`` argument to :class:`.Template`
+or :class:`.TemplateLookup`.    This entry point can be
+installed via the standard `setuptools`/``setup()`` procedure, underneath
+the `EntryPoint` group named ``"mako.cache"``.  It can also be
+installed at runtime via a convenience installer :func:`.register_plugin`
+which accomplishes essentially the same task.
+
+An example plugin that implements a local dictionary cache:
+
+.. sourcecode:: python
+
+    from mako.cache import Cacheimpl, register_plugin
+
+    class SimpleCacheImpl(CacheImpl):
+        def __init__(self, cache):
+            super(SimpleCacheImpl, self).__init__(cache)
+            self._cache = {}
+
+        def get_or_create(self, key, creation_function, **kw):
+            if key in self._cache:
+                return self._cache[key]
+            else:
+                self._cache[key] = value = creation_function()
+                return value
+
+        def set(self, key, value, **kwargs):
+            self._cache[key] = value
+
+        def get(self, key, **kwargs):
+            return self._cache.get(key)
+
+        def invalidate(self, key, **kwargs):
+            self._cache.pop(key, None)
+
+    # optional - register the class locally
+    register_plugin("simple", __name__, "SimpleCacheImpl")
+
+Enabling the above plugin in a template would look like:
+
+.. sourcecode:: python
+
+    t = Template("mytemplate",
+                 file="mytemplate.html",
+                 cache_impl='simple')
+
+Guidelines for Writing Cache Plugins
+------------------------------------
+
+* The :class:`.CacheImpl` is created on a per-:class:`.Template` basis.  The
+  class should ensure that only data for the parent :class:`.Template` is
+  persisted or returned by the cache methods.    The actual :class:`.Template`
+  is available via the ``self.cache.template`` attribute.   The ``self.cache.id``
+  attribute, which is essentially the unique modulename of the template, is
+  a good value to use in order to represent a unique namespace of keys specific
+  to the template.
+* Templates only use the :meth:`.CacheImpl.get_or_create()` method
+  in an implicit fashion.  The :meth:`.CacheImpl.set`,
+  :meth:`.CacheImpl.get`, and :meth:`.CacheImpl.invalidate` methods are
+  only used in response to direct programmatic access to the corresponding
+  methods on the :class:`.Cache` object.
+* :class:`.CacheImpl` will be accessed in a multithreaded fashion if the
+  :class:`.Template` itself is used multithreaded.  Care should be taken
+  to ensure caching implementations are threadsafe.
+* A library like `Dogpile <http://pypi.python.org/pypi/dogpile.core>`_, which
+  is a minimal locking system derived from Beaker, can be used to help
+  implement the :meth:`.CacheImpl.get_or_create` method in a threadsafe
+  way that can maximize effectiveness across multiple threads as well
+  as processes. :meth:`.CacheImpl.get_or_create` is the
+  key method used by templates.
+* All arguments passed to ``**kw`` come directly from the parameters
+  inside the ``<%def>``, ``<%block>``, or ``<%page>`` tags directly,
+  minus the ``"cache_"`` prefix, as strings, with the exception of
+  the argument ``cache_timeout``, which is passed to the plugin
+  as the name ``timeout`` with the value converted to an integer.
+  Arguments present in ``cache_args`` on :class:`.Template` or
+  :class:`.TemplateLookup` are passed directly, but are superseded
+  by those present in the most specific template tag.
+* The directory where :class:`.Template` places module files can
+  be acquired using the accessor ``self.cache.template.module_directory``.
+  This directory can be a good place to throw cache-related work
+  files, underneath a prefix like ``_my_cache_work`` so that name
+  conflicts with generated modules don't occur.
+
+API Reference
+=============
+
+.. autoclass:: mako.cache.Cache
+    :members:
+    :show-inheritance:
+
+.. autoclass:: mako.cache.CacheImpl
+    :members:
+    :show-inheritance:
+
+.. autofunction:: mako.cache.register_plugin
+
+.. autoclass:: mako.ext.beaker_cache.BeakerCacheImpl
+    :members:
+    :show-inheritance:
+
diff --git a/doc/_sources/changelog.txt b/doc/_sources/changelog.txt
new file mode 100644 (file)
index 0000000..7d110f3
--- /dev/null
@@ -0,0 +1,2126 @@
+=========
+Changelog
+=========
+
+1.0
+===
+
+.. changelog::
+    :version: 1.0.6
+    :released: Wed Nov 9 2016
+
+    .. change::
+        :tags: feature
+
+      Added new parameter :paramref:`.Template.include_error_handler` .
+      This works like :paramref:`.Template.error_handler` but indicates the
+      handler should take place when this template is included within another
+      template via the ``<%include>`` tag.  Pull request courtesy
+      Huayi Zhang.
+
+.. changelog::
+    :version: 1.0.5
+    :released: Wed Nov 2 2016
+
+    .. change::
+        :tags: bug
+
+      Updated the Sphinx documentation builder to work with recent
+      versions of Sphinx.
+
+.. changelog::
+    :version: 1.0.4
+    :released: Thu Mar 10 2016
+
+    .. change::
+        :tags: feature, test
+
+      The default test runner is now py.test.  Running "python setup.py test"
+      will make use of py.test instead of nose.  nose still works as a test
+      runner as well, however.
+
+    .. change::
+        :tags: bug, lexer
+        :pullreq: github:19
+
+      Major improvements to lexing of intricate Python sections which may
+      contain complex backslash sequences, as well as support for the bitwise
+      operator (e.g. pipe symbol) inside of expression sections distinct
+      from the Mako "filter" operator, provided the operator is enclosed
+      within parentheses or brackets.  Pull request courtesy Daniel Martin.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:16
+
+      Added new method :meth:`.Template.list_defs`.   Pull request courtesy
+      Jonathan Vanasco.
+
+.. changelog::
+    :version: 1.0.3
+    :released: Tue Oct 27 2015
+
+    .. change::
+        :tags: bug, babel
+        :pullreq: bitbucket:21
+
+      Fixed an issue where the Babel plugin would not handle a translation
+      symbol that contained non-ascii characters.  Pull request courtesy
+      Roman Imankulov.
+
+.. changelog::
+    :version: 1.0.2
+    :released: Wed Aug 26 2015
+
+    .. change::
+        :tags: bug, installation
+        :tickets: 249
+
+      The "universal wheel" marker is removed from setup.cfg, because
+      our setup.py currently makes use of conditional dependencies.
+      In :ticket:`249`, the discussion is ongoing on how to correct our
+      setup.cfg / setup.py fully so that we can handle the per-version
+      dependency changes while still maintaining optimal wheel settings,
+      so this issue is not yet fully resolved.
+
+    .. change::
+        :tags: bug, py3k
+        :tickets: 250
+
+      Repair some calls within the ast module that no longer work on Python3.5;
+      additionally replace the use of ``inspect.getargspec()`` under
+      Python 3 (seems to be called from the TG plugin) to avoid deprecation
+      warnings.
+
+    .. change::
+        :tags: bug
+        :pullreq: bitbucket:18
+
+      Update the Lingua translation extraction plugin to correctly
+      handle templates mixing Python control statements (such as if,
+      for and while) with template fragments. Pull request courtesy
+      Laurent Daverio.
+
+    .. change::
+        :tags: feature
+        :tickets: 236
+
+      Added ``STOP_RENDERING`` keyword for returning/exiting from a
+      template early, which is a synonym for an empty string ``""``.
+      Previously, the docs suggested a bare
+      ``return``, but this could cause ``None`` to appear in the
+      rendered template result.
+
+      .. seealso::
+
+        :ref:`syntax_exiting_early`
+
+.. changelog::
+    :version: 1.0.1
+    :released: Thu Jan 22 2015
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:9
+
+      Added support for Lingua, a translation extraction system as an
+      alternative to Babel.  Pull request courtesy Wichert Akkerman.
+
+    .. change::
+        :tags: bug, py3k
+        :pullreq: bitbucket:11
+
+      Modernized the examples/wsgi/run_wsgi.py file for Py3k.
+      Pull requset courtesy Cody Taylor.
+
+.. changelog::
+    :version: 1.0.0
+    :released: Sun Jun 8 2014
+
+    .. change::
+        :tags: bug, py2k
+        :pullreq: bitbucket:8
+
+      Improved the error re-raise operation when a custom
+      :paramref:`.Template.error_handler` is used that does not handle
+      the exception; the original stack trace etc. is now preserved.
+      Pull request courtesy Manfred Haltner.
+
+    .. change::
+        :tags: bug, py2k, filters
+        :pullreq: bitbucket:7
+
+      Added an html_escape filter that works in "non unicode" mode.
+      Previously, when using ``disable_unicode=True``, the ``u`` filter
+      would fail to handle non-ASCII bytes properly.  Pull request
+      courtesy George Xie.
+
+    .. change::
+        :tags: general
+
+      Compatibility changes; in order to modernize the codebase, Mako
+      is now dropping support for Python 2.4 and Python 2.5 altogether.
+      The source base is now targeted at Python 2.6 and forwards.
+
+    .. change::
+        :tags: feature
+
+      Template modules now generate a JSON "metadata" structure at the bottom
+      of the source file which includes parseable information about the
+      templates' source file, encoding etc. as well as a mapping of module
+      source lines to template lines, thus replacing the "# SOURCE LINE"
+      markers throughout the source code.  The structure also indicates those
+      lines that are explicitly not part of the template's source; the goal
+      here is to allow better integration with coverage and other tools.
+
+    .. change::
+        :tags: bug, py3k
+
+      Fixed bug in ``decode.<encoding>`` filter where a non-string object
+      would not be correctly interpreted in Python 3.
+
+    .. change::
+        :tags: bug, py3k
+        :tickets: 227
+
+      Fixed bug in Python parsing logic which would fail on Python 3
+      when a "try/except" targeted a tuple of exception types, rather
+      than a single exception.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:5
+
+      mako-render is now implemented as a setuptools entrypoint script;
+      a standalone mako.cmd.cmdline() callable is now available, and the
+      system also uses argparse now instead of optparse.  Pull request
+      courtesy Derek Harland.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:4
+
+      The mako-render script will now catch exceptions and run them
+      into the text error handler, and exit with a non-zero exit code.
+      Pull request courtesy Derek Harland.
+
+    .. change::
+        :tags: bug
+        :pullreq: bitbucket:2
+
+      A rework of the mako-render script allows the script to run
+      correctly when given a file pathname that is outside of the current
+      directory, e.g. ``mako-render ../some_template.mako``.  In this case,
+      the "template root" defaults to the directory in which the template
+      is located, instead of ".".  The script also accepts a new argument
+      ``--template-dir`` which can be specified multiple times to establish
+      template lookup directories.  Standard input for templates also works
+      now too.  Pull request courtesy Derek Harland.
+
+    .. change::
+        :tags: feature, py3k
+        :pullreq: github:7
+
+      Support is added for Python 3 "keyword only" arguments, as used in
+      defs.  Pull request courtesy Eevee.
+
+
+0.9
+===
+
+.. changelog::
+    :version: 0.9.1
+    :released: Thu Dec 26 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 225
+
+      Fixed bug in Babel plugin where translator comments
+      would be lost if intervening text nodes were encountered.
+      Fix courtesy Ned Batchelder.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed TGPlugin.render method to support unicode template
+      names in Py2K - courtesy Vladimir Magamedov.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed an AST issue that was preventing correct operation
+      under alpha versions of Python 3.4.  Pullreq courtesy Zer0-.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Changed the format of the "source encoding" header output
+      by the code generator to use the format ``# -*- coding:%s -*-``
+      instead of ``# -*- encoding:%s -*-``; the former is more common
+      and compatible with emacs.  Courtesy Martin Geisler.
+
+    .. change::
+        :tags: bug
+        :tickets: 224
+
+      Fixed issue where an old lexer rule prevented a template line
+      which looked like "#*" from being correctly parsed.
+
+.. changelog::
+    :version: 0.9.0
+    :released: Tue Aug 27 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 219
+
+      The Context.locals_() method becomes a private underscored
+      method, as this method has a specific internal use. The purpose
+      of Context.kwargs has been clarified, in that it only delivers
+      top level keyword arguments originally passed to template.render().
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed the babel plugin to properly interpret ${} sections
+      inside of a "call" tag, i.e. <%self:some_tag attr="${_('foo')}"/>.
+      Code that's subject to babel escapes in here needs to be
+      specified as a Python expression, not a literal.  This change
+      is backwards incompatible vs. code that is relying upon a _('')
+      translation to be working within a call tag.
+
+    .. change::
+        :tags: bug
+        :tickets: 187
+
+      The Babel plugin has been repaired to work on Python 3.
+
+    .. change::
+        :tags: bug
+        :tickets: 207
+
+      Using <%namespace import="*" module="somemodule"/> now
+      skips over module elements that are not explcitly callable,
+      avoiding TypeError when trying to produce partials.
+
+    .. change::
+        :tags: bug
+        :tickets: 190
+
+      Fixed Py3K bug where a "lambda" expression was not
+      interpreted correctly within a template tag; also
+      fixed in Py2.4.
+
+0.8
+===
+
+.. changelog::
+    :version: 0.8.1
+    :released: Fri May 24 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 216
+
+      Changed setup.py to skip installing markupsafe
+      if Python version is < 2.6 or is between 3.0 and
+      less than 3.3, as Markupsafe now only supports 2.6->2.X,
+      3.3->3.X.
+
+    .. change::
+        :tags: bug
+        :tickets: 214
+
+      Fixed regression where "entity" filter wasn't
+      converted for py3k properly (added tests.)
+
+    .. change::
+        :tags: bug
+        :tickets: 212
+
+      Fixed bug where mako-render script wasn't
+      compatible with Py3k.
+
+    .. change::
+        :tags: bug
+        :tickets: 213
+
+      Cleaned up all the various deprecation/
+      file warnings when running the tests under
+      various Pythons with warnings turned on.
+
+.. changelog::
+    :version: 0.8.0
+    :released: Wed Apr 10 2013
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Performance improvement to the
+      "legacy" HTML escape feature, used for XML
+      escaping and when markupsafe isn't present,
+      courtesy George Xie.
+
+    .. change::
+        :tags: bug
+        :tickets: 209
+
+      Fixed bug whereby an exception in Python 3
+      against a module compiled to the filesystem would
+      fail trying to produce a RichTraceback due to the
+      content being in bytes.
+
+    .. change::
+        :tags: bug
+        :tickets: 208
+
+      Change default for compile()->reserved_names
+      from tuple to frozenset, as this is expected to be
+      a set by default.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Code has been reworked to support Python 2.4->
+      Python 3.xx in place.  2to3 no longer needed.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added lexer_cls argument to Template,
+      TemplateLookup, allows alternate Lexer classes
+      to be used.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added future_imports parameter to Template
+      and TemplateLookup, renders the __future__ header
+      with desired capabilities at the top of the generated
+      template module.  Courtesy Ben Trofatter.
+
+0.7
+===
+
+.. changelog::
+    :version: 0.7.3
+    :released: Wed Nov 7 2012
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      legacy_html_escape function, used when
+      Markupsafe isn't installed, was using an inline-compiled
+      regexp which causes major slowdowns on Python 3.3;
+      is now precompiled.
+
+    .. change::
+        :tags: bug
+        :tickets: 201
+
+      AST supporting now supports tuple-packed
+      function arguments inside pure-python def
+      or lambda expressions.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed Py3K bug in the Babel extension.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed the "filter" attribute of the
+      <%text> tag so that it pulls locally specified
+      identifiers from the context the same
+      way as that of <%block> and <%filter>.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed bug in plugin loader to correctly
+      raise exception when non-existent plugin
+      is specified.
+
+.. changelog::
+    :version: 0.7.2
+    :released: Fri Jul 20 2012
+
+    .. change::
+        :tags: bug
+        :tickets: 193
+
+      Fixed regression in 0.7.1 where AST
+      parsing for Py2.4 was broken.
+
+.. changelog::
+    :version: 0.7.1
+    :released: Sun Jul 8 2012
+
+    .. change::
+        :tags: feature
+        :tickets: 146
+
+      Control lines with no bodies will
+      now succeed, as "pass" is added for these
+      when no statements are otherwise present.
+      Courtesy Ben Trofatter
+
+    .. change::
+        :tags: bug
+        :tickets: 192
+
+      Fixed some long-broken scoping behavior
+      involving variables declared in defs and such,
+      which only became apparent when
+      the strict_undefined flag was turned on.
+
+    .. change::
+        :tags: bug
+        :tickets: 191
+
+      Can now use strict_undefined at the
+      same time args passed to def() are used
+      by other elements of the <%def> tag.
+
+.. changelog::
+    :version: 0.7.0
+    :released: Fri Mar 30 2012
+
+    .. change::
+        :tags: feature
+        :tickets: 125
+
+      Added new "loop" variable to templates,
+      is provided within a % for block to provide
+      info about the loop such as index, first/last,
+      odd/even, etc.  A migration path is also provided
+      for legacy templates via the "enable_loop" argument
+      available on Template, TemplateLookup, and <%page>.
+      Thanks to Ben Trofatter for all
+      the work on this
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added a real check for "reserved"
+      names, that is names which are never pulled
+      from the context and cannot be passed to
+      the template.render() method.  Current names
+      are "context", "loop", "UNDEFINED".
+
+    .. change::
+        :tags: feature
+        :tickets: 95
+
+      The html_error_template() will now
+      apply Pygments highlighting to the source
+      code displayed in the traceback, if Pygments
+      if available.  Courtesy Ben Trofatter
+
+    .. change::
+        :tags: feature
+        :tickets: 147
+
+      Added support for context managers,
+      i.e. "% with x as e:/ % endwith" support.
+      Courtesy Ben Trofatter
+
+    .. change::
+        :tags: feature
+        :tickets: 185
+
+      Added class-level flag to CacheImpl
+      "pass_context"; when True, the keyword argument
+      'context' will be passed to get_or_create()
+      containing the Mako Context object.
+
+    .. change::
+        :tags: bug
+        :tickets: 182
+
+      Fixed some Py3K resource warnings due
+      to filehandles being implicitly closed.
+
+    .. change::
+        :tags: bug
+        :tickets: 186
+
+      Fixed endless recursion bug when
+      nesting multiple def-calls with content.
+      Thanks to Jeff Dairiki.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added Jinja2 to the example
+      benchmark suite, courtesy Vincent Férotin
+
+Older Versions
+==============
+
+.. changelog::
+    :version: 0.6.2
+    :released: Thu Feb 2 2012
+
+    .. change::
+        :tags: bug
+        :tickets: 86, 20
+
+      The ${{"foo":"bar"}} parsing issue is fixed!!
+      The legendary Eevee has slain the dragon!.  Also fixes quoting issue
+      at.
+
+.. changelog::
+    :version: 0.6.1
+    :released: Sat Jan 28 2012
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Added special compatibility for the 0.5.0
+      Cache() constructor, which was preventing file
+      version checks and not allowing Mako 0.6 to
+      recompile the module files.
+
+.. changelog::
+    :version: 0.6.0
+    :released: Sat Jan 21 2012
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Template caching has been converted into a plugin
+      system, whereby the usage of Beaker is just the
+      default plugin.   Template and TemplateLookup
+      now accept a string "cache_impl" parameter which
+      refers to the name of a cache plugin, defaulting
+      to the name 'beaker'.  New plugins can be
+      registered as pkg_resources entrypoints under
+      the group "mako.cache", or registered directly
+      using mako.cache.register_plugin().  The
+      core plugin is the mako.cache.CacheImpl
+      class.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added support for Beaker cache regions
+      in templates.   Usage of regions should be considered
+      as superseding the very obsolete idea of passing in
+      backend options, timeouts, etc. within templates.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      The 'put' method on Cache is now
+      'set'.  'put' is there for backwards compatibility.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      The <%def>, <%block> and <%page> tags now accept
+      any argument named "cache_*", and the key
+      minus the "cache_" prefix will be passed as keyword
+      arguments to the CacheImpl methods.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Template and TemplateLookup now accept an argument
+      cache_args, which refers to a dictionary containing
+      cache parameters.  The cache_dir, cache_url, cache_type,
+      cache_timeout arguments are deprecated (will probably
+      never be removed, however) and can be passed
+      now as cache_args={'url':<some url>, 'type':'memcached',
+      'timeout':50, 'dir':'/path/to/some/directory'}
+
+    .. change::
+        :tags: feature/bug
+        :tickets: 180
+
+      Can now refer to context variables
+      within extra arguments to <%block>, <%def>, i.e.
+      <%block name="foo" cache_key="${somekey}">.
+      Filters can also be used in this way, i.e.
+      <%def name="foo()" filter="myfilter">
+      then template.render(myfilter=some_callable)
+
+    .. change::
+        :tags: feature
+        :tickets: 178
+
+      Added "--var name=value" option to the mako-render
+      script, allows passing of kw to the template from
+      the command line.
+
+    .. change::
+        :tags: feature
+        :tickets: 181
+
+      Added module_writer argument to Template,
+      TemplateLookup, allows a callable to be passed which
+      takes over the writing of the template's module source
+      file, so that special environment-specific steps
+      can be taken.
+
+    .. change::
+        :tags: bug
+        :tickets: 142
+
+      The exception message in the html_error_template
+      is now escaped with the HTML filter.
+
+    .. change::
+        :tags: bug
+        :tickets: 173
+
+      Added "white-space:pre" style to html_error_template()
+      for code blocks so that indentation is preserved
+
+    .. change::
+        :tags: bug
+        :tickets: 175
+
+      The "benchmark" example is now Python 3 compatible
+      (even though several of those old template libs aren't
+      available on Py3K, so YMMV)
+
+
+.. changelog::
+    :version: 0.5.0
+    :released: Wed Sep 28 2011
+
+    .. change::
+        :tags:
+        :tickets: 174
+
+      A Template is explicitly disallowed
+      from having a url that normalizes to relative outside
+      of the root.   That is, if the Lookup is based
+      at /home/mytemplates, an include that would place
+      the ultimate template at
+      /home/mytemplates/../some_other_directory,
+      i.e. outside of /home/mytemplates,
+      is disallowed.   This usage was never intended
+      despite the lack of an explicit check.
+      The main issue this causes
+      is that module files can be written outside
+      of the module root (or raise an error, if file perms aren't
+      set up), and can also lead to the same template being
+      cached in the lookup under multiple, relative roots.
+      TemplateLookup instead has always supported multiple
+      file roots for this purpose.
+
+
+.. changelog::
+    :version: 0.4.2
+    :released: Fri Aug 5 2011
+
+    .. change::
+        :tags:
+        :tickets: 170
+
+      Fixed bug regarding <%call>/def calls w/ content
+      whereby the identity of the "caller" callable
+      inside the <%def> would be corrupted by the
+      presence of another <%call> in the same block.
+
+    .. change::
+        :tags:
+        :tickets: 169
+
+      Fixed the babel plugin to accommodate <%block>
+
+.. changelog::
+    :version: 0.4.1
+    :released: Wed Apr 6 2011
+
+    .. change::
+        :tags:
+        :tickets: 164
+
+      New tag: <%block>.  A variant on <%def> that
+      evaluates its contents in-place.
+      Can be named or anonymous,
+      the named version is intended for inheritance
+      layouts where any given section can be
+      surrounded by the <%block> tag in order for
+      it to become overrideable by inheriting
+      templates, without the need to specify a
+      top-level <%def> plus explicit call.
+      Modified scoping and argument rules as well as a
+      more strictly enforced usage scheme make it ideal
+      for this purpose without at all replacing most
+      other things that defs are still good for.
+      Lots of new docs.
+
+    .. change::
+        :tags:
+        :tickets: 165
+
+      a slight adjustment to the "highlight" logic
+      for generating template bound stacktraces.
+      Will stick to known template source lines
+      without any extra guessing.
+
+.. changelog::
+    :version: 0.4.0
+    :released: Sun Mar 6 2011
+
+    .. change::
+        :tags:
+        :tickets:
+
+      A 20% speedup for a basic two-page
+      inheritance setup rendering
+      a table of escaped data
+      (see http://techspot.zzzeek.org/2010/11/19/quick-mako-vs.-jinja-speed-test/).
+      A few configurational changes which
+      affect those in the I-don't-do-unicode
+      camp should be noted below.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The FastEncodingBuffer is now used
+      by default instead of cStringIO or StringIO,
+      regardless of whether output_encoding
+      is set to None or not.  FEB is faster than
+      both.  Only StringIO allows bytestrings
+      of unknown encoding to pass right
+      through, however - while it is of course
+      not recommended to send bytestrings of unknown
+      encoding to the output stream, this
+      mode of usage can be re-enabled by
+      setting the flag bytestring_passthrough
+      to True.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      disable_unicode mode requires that
+      output_encoding be set to None - it also
+      forces the bytestring_passthrough flag
+      to True.
+
+    .. change::
+        :tags:
+        :tickets: 156
+
+      the <%namespace> tag raises an error
+      if the 'template' and 'module' attributes
+      are specified at the same time in
+      one tag.  A different class is used
+      for each case which allows a reduction in
+      runtime conditional logic and function
+      call overhead.
+
+    .. change::
+        :tags:
+        :tickets: 159
+
+      the keys() in the Context, as well as
+      it's internal _data dictionary, now
+      include just what was specified to
+      render() as well as Mako builtins
+      'caller', 'capture'.  The contents
+      of __builtin__ are no longer copied.
+      Thanks to Daniel Lopez for pointing
+      this out.
+
+
+.. changelog::
+    :version: 0.3.6
+    :released: Sat Nov 13 2010
+
+    .. change::
+        :tags:
+        :tickets: 126
+
+      Documentation is on Sphinx.
+
+    .. change::
+        :tags:
+        :tickets: 154
+
+      Beaker is now part of "extras" in
+      setup.py instead of "install_requires".
+      This to produce a lighter weight install
+      for those who don't use the caching
+      as well as to conform to Pyramid
+      deployment practices.
+
+    .. change::
+        :tags:
+        :tickets: 153
+
+      The Beaker import (or attempt thereof)
+      is delayed until actually needed;
+      this to remove the performance penalty
+      from startup, particularly for
+      "single execution" environments
+      such as shell scripts.
+
+    .. change::
+        :tags:
+        :tickets: 155
+
+      Patch to lexer to not generate an empty
+      '' write in the case of backslash-ended
+      lines.
+
+    .. change::
+        :tags:
+        :tickets: 148
+
+      Fixed missing **extra collection in
+      setup.py which prevented setup.py
+      from running 2to3 on install.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      New flag on Template, TemplateLookup -
+      strict_undefined=True, will cause
+      variables not found in the context to
+      raise a NameError immediately, instead of
+      defaulting to the UNDEFINED value.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The range of Python identifiers that
+      are considered "undefined", meaning they
+      are pulled from the context, has been
+      trimmed back to not include variables
+      declared inside of expressions (i.e. from
+      list comprehensions), as well as
+      in the argument list of lambdas.  This
+      to better support the strict_undefined
+      feature.  The change should be
+      fully backwards-compatible but involved
+      a little bit of tinkering in the AST code,
+      which hadn't really been touched for
+      a couple of years, just FYI.
+
+.. changelog::
+    :version: 0.3.5
+    :released: Sun Oct 24 2010
+
+    .. change::
+        :tags:
+        :tickets: 141
+
+      The <%namespace> tag allows expressions
+      for the `file` argument, i.e. with ${}.
+      The `context` variable, if needed,
+      must be referenced explicitly.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      ${} expressions embedded in tags,
+      such as <%foo:bar x="${...}">, now
+      allow multiline Python expressions.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed previously non-covered regular
+      expression, such that using a ${} expression
+      inside of a tag element that doesn't allow
+      them raises a CompileException instead of
+      silently failing.
+
+    .. change::
+        :tags:
+        :tickets: 151
+
+      Added a try/except around "import markupsafe".
+      This to support GAE which can't run markupsafe. No idea whatsoever if the
+      install_requires in setup.py also breaks GAE,
+      couldn't get an answer on this.
+
+.. changelog::
+    :version: 0.3.4
+    :released: Tue Jun 22 2010
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Now using MarkupSafe for HTML escaping,
+      i.e. in place of cgi.escape().  Faster
+      C-based implementation and also escapes
+      single quotes for additional security.
+      Supports the __html__ attribute for
+      the given expression as well.
+
+      When using "disable_unicode" mode,
+      a pure Python HTML escaper function
+      is used which also quotes single quotes.
+
+      Note that Pylons by default doesn't
+      use Mako's filter - check your
+      environment.py file.
+
+    .. change::
+        :tags:
+        :tickets: 137
+
+      Fixed call to "unicode.strip" in
+      exceptions.text_error_template which
+      is not Py3k compatible.
+
+.. changelog::
+    :version: 0.3.3
+    :released: Mon May 31 2010
+
+    .. change::
+        :tags:
+        :tickets: 135
+
+      Added conditional to RichTraceback
+      such that if no traceback is passed
+      and sys.exc_info() has been reset,
+      the formatter just returns blank
+      for the "traceback" portion.
+
+    .. change::
+        :tags:
+        :tickets: 131
+
+      Fixed sometimes incorrect usage of
+      exc.__class__.__name__
+      in html/text error templates when using
+      Python 2.4
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed broken @property decorator on
+      template.last_modified
+
+    .. change::
+        :tags:
+        :tickets: 132
+
+      Fixed error formatting when a stacktrace
+      line contains no line number, as in when
+      inside an eval/exec-generated function.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      When a .py is being created, the tempfile
+      where the source is stored temporarily is
+      now made in the same directory as that of
+      the .py file.  This ensures that the two
+      files share the same filesystem, thus
+      avoiding cross-filesystem synchronization
+      issues.  Thanks to Charles Cazabon.
+
+.. changelog::
+    :version: 0.3.2
+    :released: Thu Mar 11 2010
+
+    .. change::
+        :tags:
+        :tickets: 116
+
+      Calling a def from the top, via
+      template.get_def(...).render() now checks the
+      argument signature the same way as it did in
+      0.2.5, so that TypeError is not raised.
+      reopen of
+
+.. changelog::
+    :version: 0.3.1
+    :released: Sun Mar 7 2010
+
+    .. change::
+        :tags:
+        :tickets: 129
+
+      Fixed incorrect dir name in setup.py
+
+.. changelog::
+    :version: 0.3.0
+    :released: Fri Mar 5 2010
+
+    .. change::
+        :tags:
+        :tickets: 123
+
+      Python 2.3 support is dropped.
+
+    .. change::
+        :tags:
+        :tickets: 119
+
+      Python 3 support is added ! See README.py3k
+      for installation and testing notes.
+
+    .. change::
+        :tags:
+        :tickets: 127
+
+      Unit tests now run with nose.
+
+    .. change::
+        :tags:
+        :tickets: 99
+
+      Source code escaping has been simplified.
+      In particular, module source files are now
+      generated with the Python "magic encoding
+      comment", and source code is passed through
+      mostly unescaped, except for that code which
+      is regenerated from parsed Python source.
+      This fixes usage of unicode in
+      <%namespace:defname> tags.
+
+    .. change::
+        :tags:
+        :tickets: 122
+
+      RichTraceback(), html_error_template().render(),
+      text_error_template().render() now accept "error"
+      and "traceback" as optional arguments, and
+      these are now actually used.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The exception output generated when
+      format_exceptions=True will now be as a Python
+      unicode if it occurred during render_unicode(),
+      or an encoded string if during render().
+
+    .. change::
+        :tags:
+        :tickets: 112
+
+      A percent sign can be emitted as the first
+      non-whitespace character on a line by escaping
+      it as in "%%".
+
+    .. change::
+        :tags:
+        :tickets: 94
+
+      Template accepts empty control structure, i.e.
+      % if: %endif, etc.
+
+    .. change::
+        :tags:
+        :tickets: 116
+
+      The <%page args> tag can now be used in a base
+      inheriting template - the full set of render()
+      arguments are passed down through the inherits
+      chain.  Undeclared arguments go into **pageargs
+      as usual.
+
+    .. change::
+        :tags:
+        :tickets: 109
+
+      defs declared within a <%namespace> section, an
+      uncommon feature, have been improved.  The defs
+      no longer get doubly-rendered in the body() scope,
+      and now allow local variable assignment without
+      breakage.
+
+    .. change::
+        :tags:
+        :tickets: 128
+
+      Windows paths are handled correctly if a Template
+      is passed only an absolute filename (i.e. with c:
+      drive etc.)  and no URI - the URI is converted
+      to a forward-slash path and module_directory
+      is treated as a windows path.
+
+    .. change::
+        :tags:
+        :tickets: 73
+
+      TemplateLookup raises TopLevelLookupException for
+      a given path that is a directory, not a filename,
+      instead of passing through to the template to
+      generate IOError.
+
+
+.. changelog::
+    :version: 0.2.6
+    :released:
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fix mako function decorators to preserve the
+      original function's name in all cases. Patch
+      from Scott Torborg.
+
+    .. change::
+        :tags:
+        :tickets: 118
+
+      Support the <%namespacename:defname> syntax in
+      the babel extractor.
+
+    .. change::
+        :tags:
+        :tickets: 88
+
+      Further fixes to unicode handling of .py files with the
+      html_error_template.
+
+.. changelog::
+    :version: 0.2.5
+    :released: Mon Sep  7 2009
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Added a "decorator" kw argument to <%def>,
+      allows custom decoration functions to wrap
+      rendering callables.  Mainly intended for
+      custom caching algorithms, not sure what
+      other uses there may be (but there may be).
+      Examples are in the "filtering" docs.
+
+    .. change::
+        :tags:
+        :tickets: 101
+
+      When Mako creates subdirectories in which
+      to store templates, it uses the more
+      permissive mode of 0775 instead of 0750,
+      helping out with certain multi-process
+      scenarios. Note that the mode is always
+      subject to the restrictions of the existing
+      umask.
+
+    .. change::
+        :tags:
+        :tickets: 104
+
+      Fixed namespace.__getattr__() to raise
+      AttributeError on attribute not found
+      instead of RuntimeError.
+
+    .. change::
+        :tags:
+        :tickets: 97
+
+      Added last_modified accessor to Template,
+      returns the time.time() when the module
+      was created.
+
+    .. change::
+        :tags:
+        :tickets: 102
+
+      Fixed lexing support for whitespace
+      around '=' sign in defs.
+
+    .. change::
+        :tags:
+        :tickets: 108
+
+      Removed errant "lower()" in the lexer which
+      was causing tags to compile with
+      case-insensitive names, thus messing up
+      custom <%call> names.
+
+    .. change::
+        :tags:
+        :tickets: 110
+
+      added "mako.__version__" attribute to
+      the base module.
+
+.. changelog::
+    :version: 0.2.4
+    :released: Tue Dec 23 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed compatibility with Jython 2.5b1.
+
+.. changelog::
+    :version: 0.2.3
+    :released: Sun Nov 23 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      the <%namespacename:defname> syntax described at
+      http://techspot.zzzeek.org/?p=28 has now
+      been added as a built in syntax, and is recommended
+      as a more modern syntax versus <%call expr="expression">.
+      The %call tag itself will always remain,
+      with <%namespacename:defname> presenting a more HTML-like
+      alternative to calling defs, both plain and
+      nested.  Many examples of the new syntax are in the
+      "Calling a def with embedded content" section
+      of the docs.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added support for Jython 2.5.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      cache module now uses Beaker's CacheManager
+      object directly, so that all cache types are included.
+      memcached is available as both "ext:memcached" and
+      "memcached", the latter for backwards compatibility.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "cache" accessor to Template, Namespace.
+      e.g.  ${local.cache.get('somekey')} or
+      template.cache.invalidate_body()
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "cache_enabled=True" flag to Template,
+      TemplateLookup.  Setting this to False causes cache
+      operations to "pass through" and execute every time;
+      this flag should be integrated in Pylons with its own
+      cache_enabled configuration setting.
+
+    .. change::
+        :tags:
+        :tickets: 92
+
+      the Cache object now supports invalidate_def(name),
+      invalidate_body(), invalidate_closure(name),
+      invalidate(key), which will remove the given key
+      from the cache, if it exists.  The cache arguments
+      (i.e. storage type) are derived from whatever has
+      been already persisted for that template.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      For cache changes to work fully, Beaker 1.1 is required.
+      1.0.1 and up will work as well with the exception of
+      cache expiry.  Note that Beaker 1.1 is **required**
+      for applications which use dynamically generated keys,
+      since previous versions will permanently store state in memory
+      for each individual key, thus consuming all available
+      memory for an arbitrarily large number of distinct
+      keys.
+
+    .. change::
+        :tags:
+        :tickets: 93
+
+      fixed bug whereby an <%included> template with
+      <%page> args named the same as a __builtin__ would not
+      honor the default value specified in <%page>
+
+    .. change::
+        :tags:
+        :tickets: 88
+
+      fixed the html_error_template not handling tracebacks from
+      normal .py files with a magic encoding comment
+
+    .. change::
+        :tags:
+        :tickets:
+
+      RichTraceback() now accepts an optional traceback object
+      to be used in place of sys.exc_info()[2].  html_error_template()
+      and text_error_template() accept an optional
+      render()-time argument "traceback" which is passed to the
+      RichTraceback object.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added ModuleTemplate class, which allows the construction
+      of a Template given a Python module generated by a previous
+      Template.   This allows Python modules alone to be used
+      as templates with no compilation step.   Source code
+      and template source are optional but allow error reporting
+      to work correctly.
+
+    .. change::
+        :tags:
+        :tickets: 90
+
+      fixed Python 2.3 compat. in mako.pyparser
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix Babel 0.9.3 compatibility; stripping comment tags is now
+      optional (and enabled by default).
+
+.. changelog::
+    :version: 0.2.2
+    :released: Mon Jun 23 2008
+
+    .. change::
+        :tags:
+        :tickets: 87
+
+      cached blocks now use the current context when rendering
+      an expired section, instead of the original context
+      passed in
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed a critical issue regarding caching, whereby
+      a cached block would raise an error when called within a
+      cache-refresh operation that was initiated after the
+      initiating template had completed rendering.
+
+.. changelog::
+    :version: 0.2.1
+    :released: Mon Jun 16 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed bug where 'output_encoding' parameter would prevent
+      render_unicode() from returning a unicode object.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      bumped magic number, which forces template recompile for
+      this version (fixes incompatible compile symbols from 0.1
+      series).
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added a few docs for cache options, specifically those that
+      help with memcached.
+
+.. changelog::
+    :version: 0.2.0
+    :released: Tue Jun  3 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Speed improvements (as though we needed them, but people
+      contributed and there you go):
+
+    .. change::
+        :tags:
+        :tickets: 77
+
+      added "bytestring passthru" mode, via
+      `disable_unicode=True` argument passed to Template or
+      TemplateLookup. All unicode-awareness and filtering is
+      turned off, and template modules are generated with
+      the appropriate magic encoding comment. In this mode,
+      template expressions can only receive raw bytestrings
+      or Unicode objects which represent straight ASCII, and
+      render_unicode() may not be used if multibyte
+      characters are present. When enabled, speed
+      improvement around 10-20%. (courtesy
+      anonymous guest)
+
+    .. change::
+        :tags:
+        :tickets: 76
+
+      inlined the "write" function of Context into a local
+      template variable. This affords a 12-30% speedup in
+      template render time. (idea courtesy same anonymous
+      guest)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      New Features, API changes:
+
+    .. change::
+        :tags:
+        :tickets: 62
+
+      added "attr" accessor to namespaces. Returns
+      attributes configured as module level attributes, i.e.
+      within <%! %> sections.  i.e.:
+
+      # somefile.html
+      <%!
+          foo = 27
+      %>
+
+      # some other template
+      <%namespace name="myns" file="somefile.html"/>
+      ${myns.attr.foo}
+
+      The slight backwards incompatibility here is, you
+      can't have namespace defs named "attr" since the
+      "attr" descriptor will occlude it.
+
+    .. change::
+        :tags:
+        :tickets: 78
+
+      cache_key argument can now render arguments passed
+      directly to the %page or %def, i.e. <%def
+      name="foo(x)" cached="True" cache_key="${x}"/>
+
+    .. change::
+        :tags:
+        :tickets:
+
+      some functions on Context are now private:
+      _push_buffer(), _pop_buffer(),
+      caller_stack._push_frame(), caller_stack._pop_frame().
+
+    .. change::
+        :tags:
+        :tickets: 56, 81
+
+      added a runner script "mako-render" which renders
+      standard input as a template to stdout
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 83, 84
+
+      can now use most names from __builtins__ as variable
+      names without explicit declaration (i.e. 'id',
+      'exception', 'range', etc.)
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 84
+
+      can also use builtin names as local variable names
+      (i.e. dict, locals) (came from fix for)
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 68
+
+      fixed bug in python generation when variable names are
+      used with identifiers like "else", "finally", etc.
+      inside them
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 69
+
+      fixed codegen bug which occured when using <%page>
+      level caching, combined with an expression-based
+      cache_key, combined with the usage of <%namespace
+      import="*"/> - fixed lexer exceptions not cleaning up
+      temporary files, which could lead to a maximum number
+      of file descriptors used in the process
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 71
+
+      fixed issue with inline format_exceptions that was
+      producing blank exception pages when an inheriting
+      template is present
+
+    .. change::
+        :tags: bugfixes
+        :tickets:
+
+      format_exceptions will apply the encoding options of
+      html_error_template() to the buffered output
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 75
+
+      rewrote the "whitespace adjuster" function to work
+      with more elaborate combinations of quotes and
+      comments
+
+
+.. changelog::
+    :version: 0.1.10
+    :released:
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed propagation of 'caller' such that nested %def calls
+      within a <%call> tag's argument list propigates 'caller'
+      to the %call function itself (propigates to the inner
+      calls too, this is a slight side effect which previously
+      existed anyway)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed bug where local.get_namespace() could put an
+      incorrect "self" in the current context
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed another namespace bug where the namespace functions
+      did not have access to the correct context containing
+      their 'self' and 'parent'
+
+.. changelog::
+    :version: 0.1.9
+    :released:
+
+    .. change::
+        :tags:
+        :tickets: 47
+
+      filters.Decode filter can also accept a non-basestring
+      object and will call str() + unicode() on it
+
+    .. change::
+        :tags:
+        :tickets: 53
+
+      comments can be placed at the end of control lines,
+      i.e. if foo: # a comment,, thanks to
+      Paul Colomiets
+
+    .. change::
+        :tags:
+        :tickets: 16
+
+      fixed expressions and page tag arguments and with embedded
+      newlines in CRLF templates, follow up to, thanks
+      Eric Woroshow
+
+    .. change::
+        :tags:
+        :tickets: 51
+
+      added an IOError catch for source file not found in RichTraceback
+      exception reporter
+
+.. changelog::
+    :version: 0.1.8
+    :released: Tue Jun 26 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      variable names declared in render methods by internal
+      codegen prefixed by "__M_" to prevent name collisions
+      with user code
+
+    .. change::
+        :tags:
+        :tickets: 45
+
+      added a Babel (http://babel.edgewall.org/) extractor entry
+      point, allowing extraction of gettext messages directly from
+      mako templates via Babel
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to turbogears plugin to work with dot-separated names
+      (i.e. load_template('foo.bar')).  also takes file extension
+      as a keyword argument (default is 'mak').
+
+    .. change::
+        :tags:
+        :tickets: 35
+
+      more tg fix:  fixed, allowing string-based
+      templates with tgplugin even if non-compatible args were sent
+
+.. changelog::
+    :version: 0.1.7
+    :released: Wed Jun 13 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      one small fix to the unit tests to support python 2.3
+
+    .. change::
+        :tags:
+        :tickets:
+
+      a slight hack to how cache.py detects Beaker's memcached,
+      works around unexplained import behavior observed on some
+      python 2.3 installations
+
+.. changelog::
+    :version: 0.1.6
+    :released: Fri May 18 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      caching is now supplied directly by Beaker, which has
+      all of MyghtyUtils merged into it now.  The latest Beaker
+      (0.7.1) also fixes a bug related to how Mako was using the
+      cache API.
+
+    .. change::
+        :tags:
+        :tickets: 34
+
+      fix to module_directory path generation when the path is "./"
+
+    .. change::
+        :tags:
+        :tickets: 35
+
+      TGPlugin passes options to string-based templates
+
+    .. change::
+        :tags:
+        :tickets: 28
+
+      added an explicit stack frame step to template runtime, which
+      allows much simpler and hopefully bug-free tracking of 'caller',
+      fixes
+
+    .. change::
+        :tags:
+        :tickets:
+
+      if plain Python defs are used with <%call>, a decorator
+      @runtime.supports_callable exists to ensure that the "caller"
+      stack is properly handled for the def.
+
+    .. change::
+        :tags:
+        :tickets: 37
+
+      fix to RichTraceback and exception reporting to get template
+      source code as a unicode object
+
+    .. change::
+        :tags:
+        :tickets: 39
+
+      html_error_template includes options "full=True", "css=True"
+      which control generation of HTML tags, CSS
+
+    .. change::
+        :tags:
+        :tickets: 40
+
+      added the 'encoding_errors' parameter to Template/TemplateLookup
+      for specifying the error handler associated with encoding to
+      'output_encoding'
+
+    .. change::
+        :tags:
+        :tickets: 37
+
+      the Template returned by html_error_template now defaults to
+      output_encoding=sys.getdefaultencoding(),
+      encoding_errors='htmlentityreplace'
+
+    .. change::
+        :tags:
+        :tickets:
+
+      control lines, i.e. % lines, support backslashes to continue long
+      lines (#32)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed codegen bug when defining <%def> within <%call> within <%call>
+
+    .. change::
+        :tags:
+        :tickets:
+
+      leading utf-8 BOM in template files is honored according to pep-0263
+
+.. changelog::
+    :version: 0.1.5
+    :released: Sat Mar 31 2007
+
+    .. change::
+        :tags:
+        :tickets: 26
+
+      AST expression generation - added in just about everything
+      expression-wise from the AST module
+
+    .. change::
+        :tags:
+        :tickets: 27
+
+      AST parsing, properly detects imports of the form "import foo.bar"
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to lexing of <%docs> tag nested in other tags
+
+    .. change::
+        :tags:
+        :tickets: 29
+
+      fix to context-arguments inside of <%include> tag which broke
+      during 0.1.4
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "n" filter, disables *all* filters normally applied to an expression
+      via <%page> or default_filters (but not those within the filter)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added buffer_filters argument, defines filters applied to the return value
+      of buffered/cached/filtered %defs, after all filters defined with the %def
+      itself have been applied.  allows the creation of default expression filters
+      that let the output of return-valued %defs "opt out" of that filtering
+      via passing special attributes or objects.
+
+.. changelog::
+    :version: 0.1.4
+    :released: Sat Mar 10 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      got defs-within-defs to be cacheable
+
+    .. change::
+        :tags:
+        :tickets: 23
+
+      fixes to code parsing/whitespace adjusting where plain python comments
+      may contain quote characters
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to variable scoping for identifiers only referenced within
+      functions
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added a path normalization step to lookup so URIs like
+      "/foo/bar/../etc/../foo" pre-process the ".." tokens before checking
+      the filesystem
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed/improved "caller" semantics so that undefined caller is
+      "UNDEFINED", propigates __nonzero__ method so it evaulates to False if
+      not present, True otherwise. this way you can say % if caller:\n
+      ${caller.body()}\n% endif
+
+    .. change::
+        :tags:
+        :tickets:
+
+      <%include> has an "args" attribute that can pass arguments to the
+      called template (keyword arguments only, must be declared in that
+      page's <%page> tag.)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      <%include> plus arguments is also programmatically available via
+      self.include_file(<filename>, **kwargs)
+
+    .. change::
+        :tags:
+        :tickets: 24
+
+      further escaping added for multibyte expressions in %def, %call
+      attributes
+
+.. changelog::
+    :version: 0.1.3
+    :released: Wed Feb 21 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      ***Small Syntax Change*** - the single line comment character is now
+      *two* hash signs, i.e. "## this is a comment".  This avoids a common
+      collection with CSS selectors.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      the magic "coding" comment (i.e. # coding:utf-8) will still work with
+      either one "#" sign or two for now; two is preferred going forward, i.e.
+      ## coding:<someencoding>.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      new multiline comment form: "<%doc> a comment </%doc>"
+
+    .. change::
+        :tags:
+        :tickets:
+
+      UNDEFINED evaluates to False
+
+    .. change::
+        :tags:
+        :tickets:
+
+      improvement to scoping of "caller" variable when using <%call> tag
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added lexer error for unclosed control-line (%) line
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "preprocessor" argument to Template, TemplateLookup - is a single
+      callable or list of callables which will be applied to the template text
+      before lexing.  given the text as an argument, returns the new text.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added mako.ext.preprocessors package, contains one preprocessor so far:
+      'convert_comments', which will convert single # comments to the new ##
+      format
+
+.. changelog::
+    :version: 0.1.2
+    :released: Thu Feb  1 2007
+
+    .. change::
+        :tags:
+        :tickets: 11
+
+      fix to parsing of code/expression blocks to insure that non-ascii
+      characters, combined with a template that indicates a non-standard
+      encoding, are expanded into backslash-escaped glyphs before being AST
+      parsed
+
+    .. change::
+        :tags:
+        :tickets:
+
+      all template lexing converts the template to unicode first, to
+      immediately catch any encoding issues and ensure internal unicode
+      representation.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added module_filename argument to Template to allow specification of a
+      specific module file
+
+    .. change::
+        :tags:
+        :tickets: 14
+
+      added modulename_callable to TemplateLookup to allow a function to
+      determine module filenames (takes filename, uri arguments). used for
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added optional input_encoding flag to Template, to allow sending a
+      unicode() object with no magic encoding comment
+
+    .. change::
+        :tags:
+        :tickets:
+
+      "expression_filter" argument in <%page> applies only to expressions
+
+    .. change::
+        :tags: "unicode"
+        :tickets:
+
+      added "default_filters" argument to Template, TemplateLookup. applies only
+      to expressions, gets prepended to "expression_filter" arg from <%page>.
+      defaults to, so that all expressions get stringified into u''
+      by default (this is what Mako already does). By setting to [], expressions
+      are passed through raw.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "imports" argument to Template, TemplateLookup. so you can predefine
+      a list of import statements at the top of the template. can be used in
+      conjunction with default_filters.
+
+    .. change::
+        :tags:
+        :tickets: 16
+
+      support for CRLF templates...whoops ! welcome to all the windows users.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      small fix to local variable propigation for locals that are conditionally
+      declared
+
+    .. change::
+        :tags:
+        :tickets:
+
+      got "top level" def calls to work, i.e. template.get_def("somedef").render()
+
+.. changelog::
+    :version: 0.1.1
+    :released: Sun Jan 14 2007
+
+    .. change::
+        :tags:
+        :tickets: 8
+
+      buffet plugin supports string-based templates, allows ToscaWidgets to work
+
+    .. change::
+        :tags:
+        :tickets:
+
+      AST parsing fixes: fixed TryExcept identifier parsing
+
+    .. change::
+        :tags:
+        :tickets:
+
+      removed textmate tmbundle from contrib and into separate SVN location;
+      windows users cant handle those files, setuptools not very good at
+      "pruning" certain directories
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix so that "cache_timeout" parameter is propigated
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to expression filters so that string conversion (actually unicode)
+      properly occurs before filtering
+
+    .. change::
+        :tags:
+        :tickets:
+
+      better error message when a lookup is attempted with a template that has no
+      lookup
+
+    .. change::
+        :tags:
+        :tickets:
+
+      implemented "module" attribute for namespace
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to code generation to correctly track multiple defs with the same name
+
+    .. change::
+        :tags:
+        :tickets: 9
+
+      "directories" can be passed to TemplateLookup as a scalar in which case it
+      gets converted to a list
diff --git a/doc/_sources/defs.txt b/doc/_sources/defs.txt
new file mode 100644 (file)
index 0000000..314e9b9
--- /dev/null
@@ -0,0 +1,622 @@
+.. _defs_toplevel:
+
+===============
+Defs and Blocks
+===============
+
+``<%def>`` and ``<%block>`` are two tags that both demarcate any block of text
+and/or code.   They both exist within generated Python as a callable function,
+i.e., a Python ``def``.   They differ in their scope and calling semantics.
+Whereas ``<%def>`` provides a construct that is very much like a named Python
+``def``, the ``<%block>`` is more layout oriented.
+
+Using Defs
+==========
+
+The ``<%def>`` tag requires a ``name`` attribute, where the ``name`` references
+a Python function signature:
+
+.. sourcecode:: mako
+
+    <%def name="hello()">
+        hello world
+    </%def>
+
+To invoke the ``<%def>``, it is normally called as an expression:
+
+.. sourcecode:: mako
+
+    the def:  ${hello()}
+
+If the ``<%def>`` is not nested inside of another ``<%def>``,
+it's known as a **top level def** and can be accessed anywhere in
+the template, including above where it was defined.
+
+All defs, top level or not, have access to the current
+contextual namespace in exactly the same way their containing
+template does. Suppose the template below is executed with the
+variables ``username`` and ``accountdata`` inside the context:
+
+.. sourcecode:: mako
+
+    Hello there ${username}, how are ya.  Lets see what your account says:
+
+    ${account()}
+
+    <%def name="account()">
+        Account for ${username}:<br/>
+
+        % for row in accountdata:
+            Value: ${row}<br/>
+        % endfor
+    </%def>
+
+The ``username`` and ``accountdata`` variables are present
+within the main template body as well as the body of the
+``account()`` def.
+
+Since defs are just Python functions, you can define and pass
+arguments to them as well:
+
+.. sourcecode:: mako
+
+    ${account(accountname='john')}
+
+    <%def name="account(accountname, type='regular')">
+        account name: ${accountname}, type: ${type}
+    </%def>
+
+When you declare an argument signature for your def, they are
+required to follow normal Python conventions (i.e., all
+arguments are required except keyword arguments with a default
+value). This is in contrast to using context-level variables,
+which evaluate to ``UNDEFINED`` if you reference a name that
+does not exist.
+
+Calling Defs from Other Files
+-----------------------------
+
+Top level ``<%def>``\ s are **exported** by your template's
+module, and can be called from the outside; including from other
+templates, as well as normal Python code. Calling a ``<%def>``
+from another template is something like using an ``<%include>``
+-- except you are calling a specific function within the
+template, not the whole template.
+
+The remote ``<%def>`` call is also a little bit like calling
+functions from other modules in Python. There is an "import"
+step to pull the names from another template into your own
+template; then the function or functions are available.
+
+To import another template, use the ``<%namespace>`` tag:
+
+.. sourcecode:: mako
+
+    <%namespace name="mystuff" file="mystuff.html"/>
+
+The above tag adds a local variable ``mystuff`` to the current
+scope.
+
+Then, just call the defs off of ``mystuff``:
+
+.. sourcecode:: mako
+
+    ${mystuff.somedef(x=5,y=7)}
+
+The ``<%namespace>`` tag also supports some of the other
+semantics of Python's ``import`` statement, including pulling
+names into the local variable space, or using ``*`` to represent
+all names, using the ``import`` attribute:
+
+.. sourcecode:: mako
+
+    <%namespace file="mystuff.html" import="foo, bar"/>
+
+This is just a quick intro to the concept of a **namespace**,
+which is a central Mako concept that has its own chapter in
+these docs. For more detail and examples, see
+:ref:`namespaces_toplevel`.
+
+Calling Defs Programmatically
+-----------------------------
+
+You can call defs programmatically from any :class:`.Template` object
+using the :meth:`~.Template.get_def()` method, which returns a :class:`.DefTemplate`
+object. This is a :class:`.Template` subclass which the parent
+:class:`.Template` creates, and is usable like any other template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    template = Template("""
+        <%def name="hi(name)">
+            hi ${name}!
+        </%def>
+
+        <%def name="bye(name)">
+            bye ${name}!
+        </%def>
+    """)
+
+    print(template.get_def("hi").render(name="ed"))
+    print(template.get_def("bye").render(name="ed"))
+
+Defs within Defs
+----------------
+
+The def model follows regular Python rules for closures.
+Declaring ``<%def>`` inside another ``<%def>`` declares it
+within the parent's **enclosing scope**:
+
+.. sourcecode:: mako
+
+    <%def name="mydef()">
+        <%def name="subdef()">
+            a sub def
+        </%def>
+
+        i'm the def, and the subcomponent is ${subdef()}
+    </%def>
+
+Just like Python, names that exist outside the inner ``<%def>``
+exist inside it as well:
+
+.. sourcecode:: mako
+
+    <%
+        x = 12
+    %>
+    <%def name="outer()">
+        <%
+            y = 15
+        %>
+        <%def name="inner()">
+            inner, x is ${x}, y is ${y}
+        </%def>
+
+        outer, x is ${x}, y is ${y}
+    </%def>
+
+Assigning to a name inside of a def declares that name as local
+to the scope of that def (again, like Python itself). This means
+the following code will raise an error:
+
+.. sourcecode:: mako
+
+    <%
+        x = 10
+    %>
+    <%def name="somedef()">
+        ## error !
+        somedef, x is ${x}
+        <%
+            x = 27
+        %>
+    </%def>
+
+...because the assignment to ``x`` declares ``x`` as local to the
+scope of ``somedef``, rendering the "outer" version unreachable
+in the expression that tries to render it.
+
+.. _defs_with_content:
+
+Calling a Def with Embedded Content and/or Other Defs
+-----------------------------------------------------
+
+A flip-side to def within def is a def call with content. This
+is where you call a def, and at the same time declare a block of
+content (or multiple blocks) that can be used by the def being
+called. The main point of such a call is to create custom,
+nestable tags, just like any other template language's
+custom-tag creation system -- where the external tag controls the
+execution of the nested tags and can communicate state to them.
+Only with Mako, you don't have to use any external Python
+modules, you can define arbitrarily nestable tags right in your
+templates.
+
+To achieve this, the target def is invoked using the form
+``<%namespacename:defname>`` instead of the normal ``${}``
+syntax. This syntax, introduced in Mako 0.2.3, is functionally
+equivalent to another tag known as ``%call``, which takes the form
+``<%call expr='namespacename.defname(args)'>``. While ``%call``
+is available in all versions of Mako, the newer style is
+probably more familiar looking. The ``namespace`` portion of the
+call is the name of the **namespace** in which the def is
+defined -- in the most simple cases, this can be ``local`` or
+``self`` to reference the current template's namespace (the
+difference between ``local`` and ``self`` is one of inheritance
+-- see :ref:`namespaces_builtin` for details).
+
+When the target def is invoked, a variable ``caller`` is placed
+in its context which contains another namespace containing the
+body and other defs defined by the caller. The body itself is
+referenced by the method ``body()``. Below, we build a ``%def``
+that operates upon ``caller.body()`` to invoke the body of the
+custom tag:
+
+.. sourcecode:: mako
+
+    <%def name="buildtable()">
+        <table>
+            <tr><td>
+                ${caller.body()}
+            </td></tr>
+        </table>
+    </%def>
+
+    <%self:buildtable>
+        I am the table body.
+    </%self:buildtable>
+
+This produces the output (whitespace formatted):
+
+.. sourcecode:: html
+
+    <table>
+        <tr><td>
+            I am the table body.
+        </td></tr>
+    </table>
+
+Using the older ``%call`` syntax looks like:
+
+.. sourcecode:: mako
+
+    <%def name="buildtable()">
+        <table>
+            <tr><td>
+                ${caller.body()}
+            </td></tr>
+        </table>
+    </%def>
+
+    <%call expr="buildtable()">
+        I am the table body.
+    </%call>
+
+The ``body()`` can be executed multiple times or not at all.
+This means you can use def-call-with-content to build iterators,
+conditionals, etc:
+
+.. sourcecode:: mako
+
+    <%def name="lister(count)">
+        % for x in range(count):
+            ${caller.body()}
+        % endfor
+    </%def>
+
+    <%self:lister count="${3}">
+        hi
+    </%self:lister>
+
+Produces:
+
+.. sourcecode:: html
+
+    hi
+    hi
+    hi
+
+Notice above we pass ``3`` as a Python expression, so that it
+remains as an integer.
+
+A custom "conditional" tag:
+
+.. sourcecode:: mako
+
+    <%def name="conditional(expression)">
+        % if expression:
+            ${caller.body()}
+        % endif
+    </%def>
+
+    <%self:conditional expression="${4==4}">
+        i'm the result
+    </%self:conditional>
+
+Produces:
+
+.. sourcecode:: html
+
+    i'm the result
+
+But that's not all. The ``body()`` function also can handle
+arguments, which will augment the local namespace of the body
+callable. The caller must define the arguments which it expects
+to receive from its target def using the ``args`` attribute,
+which is a comma-separated list of argument names. Below, our
+``<%def>`` calls the ``body()`` of its caller, passing in an
+element of data from its argument:
+
+.. sourcecode:: mako
+
+    <%def name="layoutdata(somedata)">
+        <table>
+        % for item in somedata:
+            <tr>
+            % for col in item:
+                <td>${caller.body(col=col)}</td>
+            % endfor
+            </tr>
+        % endfor
+        </table>
+    </%def>
+
+    <%self:layoutdata somedata="${[[1,2,3],[4,5,6],[7,8,9]]}" args="col">\
+    Body data: ${col}\
+    </%self:layoutdata>
+
+Produces:
+
+.. sourcecode:: html
+
+    <table>
+        <tr>
+            <td>Body data: 1</td>
+            <td>Body data: 2</td>
+            <td>Body data: 3</td>
+        </tr>
+        <tr>
+            <td>Body data: 4</td>
+            <td>Body data: 5</td>
+            <td>Body data: 6</td>
+        </tr>
+        <tr>
+            <td>Body data: 7</td>
+            <td>Body data: 8</td>
+            <td>Body data: 9</td>
+        </tr>
+    </table>
+
+You don't have to stick to calling just the ``body()`` function.
+The caller can define any number of callables, allowing the
+``<%call>`` tag to produce whole layouts:
+
+.. sourcecode:: mako
+
+    <%def name="layout()">
+        ## a layout def
+        <div class="mainlayout">
+            <div class="header">
+                ${caller.header()}
+            </div>
+
+            <div class="sidebar">
+                ${caller.sidebar()}
+            </div>
+
+            <div class="content">
+                ${caller.body()}
+            </div>
+        </div>
+    </%def>
+
+    ## calls the layout def
+    <%self:layout>
+        <%def name="header()">
+            I am the header
+        </%def>
+        <%def name="sidebar()">
+            <ul>
+                <li>sidebar 1</li>
+                <li>sidebar 2</li>
+            </ul>
+        </%def>
+
+            this is the body
+    </%self:layout>
+
+The above layout would produce:
+
+.. sourcecode:: html
+
+    <div class="mainlayout">
+        <div class="header">
+        I am the header
+        </div>
+
+        <div class="sidebar">
+        <ul>
+            <li>sidebar 1</li>
+            <li>sidebar 2</li>
+        </ul>
+        </div>
+
+        <div class="content">
+        this is the body
+        </div>
+    </div>
+
+The number of things you can do with ``<%call>`` and/or the
+``<%namespacename:defname>`` calling syntax is enormous. You can
+create form widget libraries, such as an enclosing ``<FORM>``
+tag and nested HTML input elements, or portable wrapping schemes
+using ``<div>`` or other elements. You can create tags that
+interpret rows of data, such as from a database, providing the
+individual columns of each row to a ``body()`` callable which
+lays out the row any way it wants. Basically anything you'd do
+with a "custom tag" or tag library in some other system, Mako
+provides via ``<%def>`` tags and plain Python callables which are
+invoked via ``<%namespacename:defname>`` or ``<%call>``.
+
+.. _blocks:
+
+Using Blocks
+============
+
+The ``<%block>`` tag introduces some new twists on the
+``<%def>`` tag which make it more closely tailored towards layout.
+
+.. versionadded:: 0.4.1
+
+An example of a block:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block>
+                this is a block.
+            </%block>
+        </body>
+    </html>
+
+In the above example, we define a simple block.  The block renders its content in the place
+that it's defined.  Since the block is called for us, it doesn't need a name and the above
+is referred to as an **anonymous block**.  So the output of the above template will be:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+                this is a block.
+        </body>
+    </html>
+
+So in fact the above block has absolutely no effect.  Its usefulness comes when we start
+using modifiers.  Such as, we can apply a filter to our block:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block filter="h">
+                <html>this is some escaped html.</html>
+            </%block>
+        </body>
+    </html>
+
+or perhaps a caching directive:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block cached="True" cache_timeout="60">
+                This content will be cached for 60 seconds.
+            </%block>
+        </body>
+    </html>
+
+Blocks also work in iterations, conditionals, just like defs:
+
+.. sourcecode:: mako
+
+    % if some_condition:
+        <%block>condition is met</%block>
+    % endif
+
+While the block renders at the point it is defined in the template,
+the underlying function is present in the generated Python code only
+once, so there's no issue with placing a block inside of a loop or
+similar. Anonymous blocks are defined as closures in the local
+rendering body, so have access to local variable scope:
+
+.. sourcecode:: mako
+
+    % for i in range(1, 4):
+        <%block>i is ${i}</%block>
+    % endfor
+
+Using Named Blocks
+------------------
+
+Possibly the more important area where blocks are useful is when we
+do actually give them names. Named blocks are tailored to behave
+somewhat closely to Jinja2's block tag, in that they define an area
+of a layout which can be overridden by an inheriting template. In
+sharp contrast to the ``<%def>`` tag, the name given to a block is
+global for the entire template regardless of how deeply it's nested:
+
+.. sourcecode:: mako
+
+    <html>
+    <%block name="header">
+        <head>
+            <title>
+                <%block name="title">Title</%block>
+            </title>
+        </head>
+    </%block>
+    <body>
+        ${next.body()}
+    </body>
+    </html>
+
+The above example has two named blocks "``header``" and "``title``", both of which can be referred to
+by an inheriting template. A detailed walkthrough of this usage can be found at :ref:`inheritance_toplevel`.
+
+Note above that named blocks don't have any argument declaration the way defs do. They still implement themselves
+as Python functions, however, so they can be invoked additional times beyond their initial definition:
+
+.. sourcecode:: mako
+
+    <div name="page">
+        <%block name="pagecontrol">
+            <a href="">previous page</a> |
+            <a href="">next page</a>
+        </%block>
+
+        <table>
+            ## some content
+        </table>
+
+        ${pagecontrol()}
+    </div>
+
+The content referenced by ``pagecontrol`` above will be rendered both above and below the ``<table>`` tags.
+
+To keep things sane, named blocks have restrictions that defs do not:
+
+* The ``<%block>`` declaration cannot have any argument signature.
+* The name of a ``<%block>`` can only be defined once in a template -- an error is raised if two blocks of the same
+  name occur anywhere in a single template, regardless of nesting.  A similar error is raised if a top level def
+  shares the same name as that of a block.
+* A named ``<%block>`` cannot be defined within a ``<%def>``, or inside the body of a "call", i.e.
+  ``<%call>`` or ``<%namespacename:defname>`` tag.  Anonymous blocks can, however.
+
+Using Page Arguments in Named Blocks
+------------------------------------
+
+A named block is very much like a top level def. It has a similar
+restriction to these types of defs in that arguments passed to the
+template via the ``<%page>`` tag aren't automatically available.
+Using arguments with the ``<%page>`` tag is described in the section
+:ref:`namespaces_body`, and refers to scenarios such as when the
+``body()`` method of a template is called from an inherited template passing
+arguments, or the template is invoked from an ``<%include>`` tag
+with arguments. To allow a named block to share the same arguments
+passed to the page, the ``args`` attribute can be used:
+
+.. sourcecode:: mako
+
+    <%page args="post"/>
+
+    <a name="${post.title}" />
+
+    <span class="post_prose">
+        <%block name="post_prose" args="post">
+            ${post.content}
+        </%block>
+    </span>
+
+Where above, if the template is called via a directive like
+``<%include file="post.mako" args="post=post" />``, the ``post``
+variable is available both in the main body as well as the
+``post_prose`` block.
+
+Similarly, the ``**pageargs`` variable is present, in named blocks only,
+for those arguments not explicit in the ``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%block name="post_prose">
+        ${pageargs['post'].content}
+    </%block>
+
+The ``args`` attribute is only allowed with named blocks. With
+anonymous blocks, the Python function is always rendered in the same
+scope as the call itself, so anything available directly outside the
+anonymous block is available inside as well.
diff --git a/doc/_sources/filtering.txt b/doc/_sources/filtering.txt
new file mode 100644 (file)
index 0000000..3bcb25a
--- /dev/null
@@ -0,0 +1,344 @@
+.. _filtering_toplevel:
+
+=======================
+Filtering and Buffering
+=======================
+
+Expression Filtering
+====================
+
+As described in the chapter :ref:`syntax_toplevel`, the "``|``" operator can be
+applied to a "``${}``" expression to apply escape filters to the
+output:
+
+.. sourcecode:: mako
+
+    ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``.
+
+The built-in escape flags are:
+
+* ``u`` : URL escaping, provided by
+  ``urllib.quote_plus(string.encode('utf-8'))``
+* ``h`` : HTML escaping, provided by
+  ``markupsafe.escape(string)``
+
+  .. versionadded:: 0.3.4
+     Prior versions use ``cgi.escape(string, True)``.
+
+* ``x`` : XML escaping
+* ``trim`` : whitespace trimming, provided by ``string.strip()``
+* ``entity`` : produces HTML entity references for applicable
+  strings, derived from ``htmlentitydefs``
+* ``unicode`` (``str`` on Python 3): produces a Python unicode
+  string (this function is applied by default)
+* ``decode.<some encoding>``: decode input into a Python
+  unicode with the specified encoding
+* ``n`` : disable all default filtering; only filters specified
+  in the local expression tag will be applied.
+
+To apply more than one filter, separate them by a comma:
+
+.. sourcecode:: mako
+
+    ${" <tag>some value</tag> " | h,trim}
+
+The above produces ``&lt;tag&gt;some value&lt;/tag&gt;``, with
+no leading or trailing whitespace. The HTML escaping function is
+applied first, the "trim" function second.
+
+Naturally, you can make your own filters too. A filter is just a
+Python function that accepts a single string argument, and
+returns the filtered result. The expressions after the ``|``
+operator draw upon the local namespace of the template in which
+they appear, meaning you can define escaping functions locally:
+
+.. sourcecode:: mako
+
+    <%!
+        def myescape(text):
+            return "<TAG>" + text + "</TAG>"
+    %>
+
+    Here's some tagged text: ${"text" | myescape}
+
+Or from any Python module:
+
+.. sourcecode:: mako
+
+    <%!
+        import myfilters
+    %>
+
+    Here's some tagged text: ${"text" | myfilters.tagfilter}
+
+A page can apply a default set of filters to all expression tags
+using the ``expression_filter`` argument to the ``%page`` tag:
+
+.. sourcecode:: mako
+
+    <%page expression_filter="h"/>
+
+    Escaped text:  ${"<html>some html</html>"}
+
+Result:
+
+.. sourcecode:: html
+
+    Escaped text: &lt;html&gt;some html&lt;/html&gt;
+
+.. _filtering_default_filters:
+
+The ``default_filters`` Argument
+--------------------------------
+
+In addition to the ``expression_filter`` argument, the
+``default_filters`` argument to both :class:`.Template` and
+:class:`.TemplateLookup` can specify filtering for all expression tags
+at the programmatic level. This array-based argument, when given
+its default argument of ``None``, will be internally set to
+``["unicode"]`` (or ``["str"]`` on Python 3), except when
+``disable_unicode=True`` is set in which case it defaults to
+``["str"]``:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=['unicode'])
+
+To replace the usual ``unicode``/``str`` function with a
+specific encoding, the ``decode`` filter can be substituted:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=['decode.utf8'])
+
+To disable ``default_filters`` entirely, set it to an empty
+list:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=[])
+
+Any string name can be added to ``default_filters`` where it
+will be added to all expressions as a filter. The filters are
+applied from left to right, meaning the leftmost filter is
+applied first.
+
+.. sourcecode:: python
+
+    t = Template(templatetext, default_filters=['unicode', 'myfilter'])
+
+To ease the usage of ``default_filters`` with custom filters,
+you can also add imports (or other code) to all templates using
+the ``imports`` argument:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'],
+                       default_filters=['unicode', 'myfilter'],
+                       imports=['from mypackage import myfilter'])
+
+The above will generate templates something like this:
+
+.. sourcecode:: python
+
+    # ....
+    from mypackage import myfilter
+
+    def render_body(context):
+        context.write(myfilter(unicode("some text")))
+
+Turning off Filtering with the ``n`` Filter
+-------------------------------------------
+
+In all cases the special ``n`` filter, used locally within an
+expression, will **disable** all filters declared in the
+``<%page>`` tag as well as in ``default_filters``. Such as:
+
+.. sourcecode:: mako
+
+    ${'myexpression' | n}
+
+will render ``myexpression`` with no filtering of any kind, and:
+
+.. sourcecode:: mako
+
+    ${'myexpression' | n,trim}
+
+will render ``myexpression`` using the ``trim`` filter only.
+
+Filtering Defs and Blocks
+=========================
+
+The ``%def`` and ``%block`` tags have an argument called ``filter`` which will apply the
+given list of filter functions to the output of the ``%def``:
+
+.. sourcecode:: mako
+
+    <%def name="foo()" filter="h, trim">
+        <b>this is bold</b>
+    </%def>
+
+When the ``filter`` attribute is applied to a def as above, the def
+is automatically **buffered** as well. This is described next.
+
+Buffering
+=========
+
+One of Mako's central design goals is speed. To this end, all of
+the textual content within a template and its various callables
+is by default piped directly to the single buffer that is stored
+within the :class:`.Context` object. While this normally is easy to
+miss, it has certain side effects. The main one is that when you
+call a def using the normal expression syntax, i.e.
+``${somedef()}``, it may appear that the return value of the
+function is the content it produced, which is then delivered to
+your template just like any other expression substitution,
+except that normally, this is not the case; the return value of
+``${somedef()}`` is simply the empty string ``''``. By the time
+you receive this empty string, the output of ``somedef()`` has
+been sent to the underlying buffer.
+
+You may not want this effect, if for example you are doing
+something like this:
+
+.. sourcecode:: mako
+
+    ${" results " + somedef() + " more results "}
+
+If the ``somedef()`` function produced the content "``somedef's
+results``", the above template would produce this output:
+
+.. sourcecode:: html
+
+    somedef's results results more results
+
+This is because ``somedef()`` fully executes before the
+expression returns the results of its concatenation; the
+concatenation in turn receives just the empty string as its
+middle expression.
+
+Mako provides two ways to work around this. One is by applying
+buffering to the ``%def`` itself:
+
+.. sourcecode:: mako
+
+    <%def name="somedef()" buffered="True">
+        somedef's results
+    </%def>
+
+The above definition will generate code similar to this:
+
+.. sourcecode:: python
+
+    def somedef():
+        context.push_buffer()
+        try:
+            context.write("somedef's results")
+        finally:
+            buf = context.pop_buffer()
+        return buf.getvalue()
+
+So that the content of ``somedef()`` is sent to a second buffer,
+which is then popped off the stack and its value returned. The
+speed hit inherent in buffering the output of a def is also
+apparent.
+
+Note that the ``filter`` argument on ``%def`` also causes the def to
+be buffered. This is so that the final content of the ``%def`` can
+be delivered to the escaping function in one batch, which
+reduces method calls and also produces more deterministic
+behavior for the filtering function itself, which can possibly
+be useful for a filtering function that wishes to apply a
+transformation to the text as a whole.
+
+The other way to buffer the output of a def or any Mako callable
+is by using the built-in ``capture`` function. This function
+performs an operation similar to the above buffering operation
+except it is specified by the caller.
+
+.. sourcecode:: mako
+
+    ${" results " + capture(somedef) + " more results "}
+
+Note that the first argument to the ``capture`` function is
+**the function itself**, not the result of calling it. This is
+because the ``capture`` function takes over the job of actually
+calling the target function, after setting up a buffered
+environment. To send arguments to the function, just send them
+to ``capture`` instead:
+
+.. sourcecode:: mako
+
+    ${capture(somedef, 17, 'hi', use_paging=True)}
+
+The above call is equivalent to the unbuffered call:
+
+.. sourcecode:: mako
+
+    ${somedef(17, 'hi', use_paging=True)}
+
+Decorating
+==========
+
+.. versionadded:: 0.2.5
+
+Somewhat like a filter for a ``%def`` but more flexible, the ``decorator``
+argument to ``%def`` allows the creation of a function that will
+work in a similar manner to a Python decorator. The function can
+control whether or not the function executes. The original
+intent of this function is to allow the creation of custom cache
+logic, but there may be other uses as well.
+
+``decorator`` is intended to be used with a regular Python
+function, such as one defined in a library module. Here we'll
+illustrate the python function defined in the template for
+simplicities' sake:
+
+.. sourcecode:: mako
+
+    <%!
+        def bar(fn):
+            def decorate(context, *args, **kw):
+                context.write("BAR")
+                fn(*args, **kw)
+                context.write("BAR")
+                return ''
+            return decorate
+    %>
+
+    <%def name="foo()" decorator="bar">
+        this is foo
+    </%def>
+
+    ${foo()}
+
+The above template will return, with more whitespace than this,
+``"BAR this is foo BAR"``. The function is the render callable
+itself (or possibly a wrapper around it), and by default will
+write to the context. To capture its output, use the :func:`.capture`
+callable in the ``mako.runtime`` module (available in templates
+as just ``runtime``):
+
+.. sourcecode:: mako
+
+    <%!
+        def bar(fn):
+            def decorate(context, *args, **kw):
+                return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR"
+            return decorate
+    %>
+
+    <%def name="foo()" decorator="bar">
+        this is foo
+    </%def>
+
+    ${foo()}
+
+The decorator can be used with top-level defs as well as nested
+defs, and blocks too. Note that when calling a top-level def from the
+:class:`.Template` API, i.e. ``template.get_def('somedef').render()``,
+the decorator has to write the output to the ``context``, i.e.
+as in the first example. The return value gets discarded.
diff --git a/doc/_sources/index.txt b/doc/_sources/index.txt
new file mode 100644 (file)
index 0000000..3104ca9
--- /dev/null
@@ -0,0 +1,23 @@
+Table of Contents
+=================
+
+.. toctree::
+    :maxdepth: 2
+
+    usage
+    syntax
+    defs
+    runtime
+    namespaces
+    inheritance
+    filtering
+    unicode
+    caching
+    changelog
+
+Indices and Tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/doc/_sources/inheritance.txt b/doc/_sources/inheritance.txt
new file mode 100644 (file)
index 0000000..5b29574
--- /dev/null
@@ -0,0 +1,647 @@
+.. _inheritance_toplevel:
+
+===========
+Inheritance
+===========
+
+.. note::  Most of the inheritance examples here take advantage of a feature that's
+    new in Mako as of version 0.4.1 called the "block".  This tag is very similar to
+    the "def" tag but is more streamlined for usage with inheritance.  Note that
+    all of the examples here which use blocks can also use defs instead.  Contrasting
+    usages will be illustrated.
+
+Using template inheritance, two or more templates can organize
+themselves into an **inheritance chain**, where content and
+functions from all involved templates can be intermixed. The
+general paradigm of template inheritance is this: if a template
+``A`` inherits from template ``B``, then template ``A`` agrees
+to send the executional control to template ``B`` at runtime
+(``A`` is called the **inheriting** template). Template ``B``,
+the **inherited** template, then makes decisions as to what
+resources from ``A`` shall be executed.
+
+In practice, it looks like this. Here's a hypothetical inheriting
+template, ``index.html``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%block name="header">
+        this is some header content
+    </%block>
+
+    this is the body content.
+
+And ``base.html``, the inherited template:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header"/>
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+Here is a breakdown of the execution:
+
+#. When ``index.html`` is rendered, control immediately passes to
+   ``base.html``.
+#. ``base.html`` then renders the top part of an HTML document,
+   then invokes the ``<%block name="header">`` block.  It invokes the
+   underlying ``header()`` function off of a built-in namespace
+   called ``self`` (this namespace was first introduced in the
+   :doc:`Namespaces chapter <namespaces>` in :ref:`namespace_self`). Since
+   ``index.html`` is the topmost template and also defines a block
+   called ``header``, it's this ``header`` block that ultimately gets
+   executed -- instead of the one that's present in ``base.html``.
+#. Control comes back to ``base.html``. Some more HTML is
+   rendered.
+#. ``base.html`` executes ``self.body()``. The ``body()``
+   function on all template-based namespaces refers to the main
+   body of the template, therefore the main body of
+   ``index.html`` is rendered.
+#. When ``<%block name="header">`` is encountered in ``index.html``
+   during the ``self.body()`` call, a conditional is checked -- does the
+   current inherited template, i.e. ``base.html``, also define this block? If yes,
+   the ``<%block>`` is **not** executed here -- the inheritance
+   mechanism knows that the parent template is responsible for rendering
+   this block (and in fact it already has).  In other words a block
+   only renders in its *basemost scope*.
+#. Control comes back to ``base.html``. More HTML is rendered,
+   then the ``<%block name="footer">`` expression is invoked.
+#. The ``footer`` block is only defined in ``base.html``, so being
+   the topmost definition of ``footer``, it's the one that
+   executes. If ``index.html`` also specified ``footer``, then
+   its version would **override** that of the base.
+#. ``base.html`` finishes up rendering its HTML and the template
+   is complete, producing:
+
+   .. sourcecode:: html
+
+        <html>
+            <body>
+                <div class="header">
+                    this is some header content
+                </div>
+
+                this is the body content.
+
+                <div class="footer">
+                    this is the footer
+                </div>
+            </body>
+        </html>
+
+...and that is template inheritance in a nutshell. The main idea
+is that the methods that you call upon ``self`` always
+correspond to the topmost definition of that method. Very much
+the way ``self`` works in a Python class, even though Mako is
+not actually using Python class inheritance to implement this
+functionality. (Mako doesn't take the "inheritance" metaphor too
+seriously; while useful to setup some commonly recognized
+semantics, a textual template is not very much like an
+object-oriented class construct in practice).
+
+Nesting Blocks
+==============
+
+The named blocks defined in an inherited template can also be nested within
+other blocks.  The name given to each block is globally accessible via any inheriting
+template.  We can add a new block ``title`` to our ``header`` block:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header">
+                    <h2>
+                        <%block name="title"/>
+                    </h2>
+                </%block>
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+The inheriting template can name either or both of ``header`` and ``title``, separately
+or nested themselves:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%block name="header">
+        this is some header content
+        ${parent.header()}
+    </%block>
+
+    <%block name="title">
+        this is the title
+    </%block>
+
+    this is the body content.
+
+Note when we overrode ``header``, we added an extra call ``${parent.header()}`` in order to invoke
+the parent's ``header`` block in addition to our own.  That's described in more detail below,
+in :ref:`parent_namespace`.
+
+Rendering a Named Block Multiple Times
+======================================
+
+Recall from the section :ref:`blocks` that a named block is just like a ``<%def>``,
+with some different usage rules.  We can call one of our named sections distinctly, for example
+a section that is used more than once, such as the title of a page:
+
+.. sourcecode:: mako
+
+    <html>
+        <head>
+            <title>${self.title()}</title>
+        </head>
+        <body>
+        <%block name="header">
+            <h2><%block name="title"/></h2>
+        </%block>
+        ${self.body()}
+        </body>
+    </html>
+
+Where above an inheriting template can define ``<%block name="title">`` just once, and it will be
+used in the base template both in the ``<title>`` section as well as the ``<h2>``.
+
+
+
+But what about Defs?
+====================
+
+The previous example used the ``<%block>`` tag to produce areas of content
+to be overridden.  Before Mako 0.4.1, there wasn't any such tag -- instead
+there was only the ``<%def>`` tag.   As it turns out, named blocks and defs are
+largely interchangeable.  The def simply doesn't call itself automatically,
+and has more open-ended naming and scoping rules that are more flexible and similar
+to Python itself, but less suited towards layout.  The first example from
+this chapter using defs would look like:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%def name="header()">
+        this is some header content
+    </%def>
+
+    this is the body content.
+
+And ``base.html``, the inherited template:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                ${self.header()}
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                ${self.footer()}
+            </div>
+        </body>
+    </html>
+
+    <%def name="header()"/>
+    <%def name="footer()">
+        this is the footer
+    </%def>
+
+Above, we illustrate that defs differ from blocks in that their definition
+and invocation are defined in two separate places, instead of at once. You can *almost* do exactly what a
+block does if you put the two together:
+
+.. sourcecode:: mako
+
+    <div class="header">
+        <%def name="header()"></%def>${self.header()}
+    </div>
+
+The ``<%block>`` is obviously more streamlined than the ``<%def>`` for this kind
+of usage.  In addition,
+the above "inline" approach with ``<%def>`` does not work with nesting:
+
+.. sourcecode:: mako
+
+    <head>
+        <%def name="header()">
+            <title>
+            ## this won't work !
+            <%def name="title()">default title</%def>${self.title()}
+            </title>
+        </%def>${self.header()}
+    </head>
+
+Where above, the ``title()`` def, because it's a def within a def, is not part of the
+template's exported namespace and will not be part of ``self``.  If the inherited template
+did define its own ``title`` def at the top level, it would be called, but the "default title"
+above is not present at all on ``self`` no matter what.  For this to work as expected
+you'd instead need to say:
+
+.. sourcecode:: mako
+
+    <head>
+        <%def name="header()">
+            <title>
+            ${self.title()}
+            </title>
+        </%def>${self.header()}
+
+        <%def name="title()"/>
+    </head>
+
+That is, ``title`` is defined outside of any other defs so that it is in the ``self`` namespace.
+It works, but the definition needs to be potentially far away from the point of render.
+
+A named block is always placed in the ``self`` namespace, regardless of nesting,
+so this restriction is lifted:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <head>
+        <%block name="header">
+            <title>
+            <%block name="title"/>
+            </title>
+        </%block>
+    </head>
+
+The above template defines ``title`` inside of ``header``, and an inheriting template can define
+one or both in **any** configuration, nested inside each other or not, in order for them to be used:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+    <%block name="title">
+        the title
+    </%block>
+    <%block name="header">
+        the header
+    </%block>
+
+So while the ``<%block>`` tag lifts the restriction of nested blocks not being available externally,
+in order to achieve this it *adds* the restriction that all block names in a single template need
+to be globally unique within the template, and additionally that a ``<%block>`` can't be defined
+inside of a ``<%def>``. It's a more restricted tag suited towards a more specific use case than ``<%def>``.
+
+Using the ``next`` Namespace to Produce Content Wrapping
+========================================================
+
+Sometimes you have an inheritance chain that spans more than two
+templates. Or maybe you don't, but you'd like to build your
+system such that extra inherited templates can be inserted in
+the middle of a chain where they would be smoothly integrated.
+If each template wants to define its layout just within its main
+body, you can't just call ``self.body()`` to get at the
+inheriting template's body, since that is only the topmost body.
+To get at the body of the *next* template, you call upon the
+namespace ``next``, which is the namespace of the template
+**immediately following** the current template.
+
+Lets change the line in ``base.html`` which calls upon
+``self.body()`` to instead call upon ``next.body()``:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header"/>
+            </div>
+
+            ${next.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+
+Lets also add an intermediate template called ``layout.html``,
+which inherits from ``base.html``:
+
+.. sourcecode:: mako
+
+    ## layout.html
+    <%inherit file="base.html"/>
+    <ul>
+        <%block name="toolbar">
+            <li>selection 1</li>
+            <li>selection 2</li>
+            <li>selection 3</li>
+        </%block>
+    </ul>
+    <div class="mainlayout">
+        ${next.body()}
+    </div>
+
+And finally change ``index.html`` to inherit from
+``layout.html`` instead:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="layout.html"/>
+
+    ## .. rest of template
+
+In this setup, each call to ``next.body()`` will render the body
+of the next template in the inheritance chain (which can be
+written as ``base.html -> layout.html -> index.html``). Control
+is still first passed to the bottommost template ``base.html``,
+and ``self`` still references the topmost definition of any
+particular def.
+
+The output we get would be:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+            <div class="header">
+                this is some header content
+            </div>
+
+            <ul>
+                <li>selection 1</li>
+                <li>selection 2</li>
+                <li>selection 3</li>
+            </ul>
+
+            <div class="mainlayout">
+            this is the body content.
+            </div>
+
+            <div class="footer">
+                this is the footer
+            </div>
+        </body>
+    </html>
+
+So above, we have the ``<html>``, ``<body>`` and
+``header``/``footer`` layout of ``base.html``, we have the
+``<ul>`` and ``mainlayout`` section of ``layout.html``, and the
+main body of ``index.html`` as well as its overridden ``header``
+def. The ``layout.html`` template is inserted into the middle of
+the chain without ``base.html`` having to change anything.
+Without the ``next`` namespace, only the main body of
+``index.html`` could be used; there would be no way to call
+``layout.html``'s body content.
+
+.. _parent_namespace:
+
+Using the ``parent`` Namespace to Augment Defs
+==============================================
+
+Lets now look at the other inheritance-specific namespace, the
+opposite of ``next`` called ``parent``. ``parent`` is the
+namespace of the template **immediately preceding** the current
+template. What's useful about this namespace is that
+defs or blocks can call upon their overridden versions.
+This is not as hard as it sounds and
+is very much like using the ``super`` keyword in Python. Lets
+modify ``index.html`` to augment the list of selections provided
+by the ``toolbar`` function in ``layout.html``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="layout.html"/>
+
+    <%block name="header">
+        this is some header content
+    </%block>
+
+    <%block name="toolbar">
+        ## call the parent's toolbar first
+        ${parent.toolbar()}
+        <li>selection 4</li>
+        <li>selection 5</li>
+    </%block>
+
+    this is the body content.
+
+Above, we implemented a ``toolbar()`` function, which is meant
+to override the definition of ``toolbar`` within the inherited
+template ``layout.html``. However, since we want the content
+from that of ``layout.html`` as well, we call it via the
+``parent`` namespace whenever we want it's content, in this case
+before we add our own selections. So the output for the whole
+thing is now:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+            <div class="header">
+                this is some header content
+            </div>
+
+            <ul>
+                <li>selection 1</li>
+                <li>selection 2</li>
+                <li>selection 3</li>
+                <li>selection 4</li>
+                <li>selection 5</li>
+            </ul>
+
+            <div class="mainlayout">
+            this is the body content.
+            </div>
+
+            <div class="footer">
+                this is the footer
+            </div>
+        </body>
+    </html>
+
+and you're now a template inheritance ninja!
+
+Using ``<%include>`` with Template Inheritance
+==============================================
+
+A common source of confusion is the behavior of the ``<%include>`` tag,
+often in conjunction with its interaction within template inheritance.
+Key to understanding the ``<%include>`` tag is that it is a *dynamic*, e.g.
+runtime, include, and not a static include.   The ``<%include>`` is only processed
+as the template renders, and not at inheritance setup time.   When encountered,
+the referenced template is run fully as an entirely separate template with no
+linkage to any current inheritance structure.
+
+If the tag were on the other hand a *static* include, this would allow source
+within the included template to interact within the same inheritance context
+as the calling template, but currently Mako has no static include facility.
+
+In practice, this means that ``<%block>`` elements defined in an ``<%include>``
+file will not interact with corresponding ``<%block>`` elements in the calling
+template.
+
+A common mistake is along these lines:
+
+.. sourcecode:: mako
+
+    ## partials.mako
+    <%block name="header">
+        Global Header
+    </%block>
+
+    ## parent.mako
+    <%include file="partials.mako">
+
+    ## child.mako
+    <%inherit file="parent.mako">
+    <%block name="header">
+        Custom Header
+    </%block>
+
+Above, one might expect that the ``"header"`` block declared in ``child.mako``
+might be invoked, as a result of it overriding the same block present in
+``parent.mako`` via the include for ``partials.mako``.  But this is not the case.
+Instead, ``parent.mako`` will invoke ``partials.mako``, which then invokes
+``"header"`` in ``partials.mako``, and then is finished rendering.  Nothing
+from ``child.mako`` will render; there is no interaction between the ``"header"``
+block in ``child.mako`` and the ``"header"`` block in ``partials.mako``.
+
+Instead, ``parent.mako`` must explicitly state the inheritance structure.
+In order to call upon specific elements of ``partials.mako``, we will call upon
+it as a namespace:
+
+.. sourcecode:: mako
+
+    ## partials.mako
+    <%block name="header">
+        Global Header
+    </%block>
+
+    ## parent.mako
+    <%namespace name="partials" file="partials.mako"/>
+    <%block name="header">
+        ${partials.header()}
+    </%block>
+
+    ## child.mako
+    <%inherit file="parent.mako">
+    <%block name="header">
+        Custom Header
+    </%block>
+
+Where above, ``parent.mako`` states the inheritance structure that ``child.mako``
+is to participate within.  ``partials.mako`` only defines defs/blocks that can be
+used on a per-name basis.
+
+Another scenario is below, which results in both ``"SectionA"`` blocks being rendered for the ``child.mako`` document:
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ${self.body()}
+    <%block name="SectionA">
+        base.mako
+    </%block>
+
+    ## parent.mako
+    <%inherit file="base.mako">
+    <%include file="child.mako">
+
+    ## child.mako
+    <%block name="SectionA">
+        child.mako
+    </%block>
+
+The resolution is similar; instead of using ``<%include>``, we call upon the blocks
+of ``child.mako`` using a namespace:
+
+.. sourcecode:: mako
+
+    ## parent.mako
+    <%inherit file="base.mako">
+    <%namespace name="child" file="child.mako">
+
+    <%block name="SectionA">
+        ${child.SectionA()}
+    </%block>
+
+
+.. _inheritance_attr:
+
+Inheritable Attributes
+======================
+
+The :attr:`attr <.Namespace.attr>` accessor of the :class:`.Namespace` object
+allows access to module level variables declared in a template. By accessing
+``self.attr``, you can access regular attributes from the
+inheritance chain as declared in ``<%! %>`` sections. Such as:
+
+.. sourcecode:: mako
+
+    <%!
+        class_ = "grey"
+    %>
+
+    <div class="${self.attr.class_}">
+        ${self.body()}
+    </div>
+
+If an inheriting template overrides ``class_`` to be
+``"white"``, as in:
+
+.. sourcecode:: mako
+
+    <%!
+        class_ = "white"
+    %>
+    <%inherit file="parent.html"/>
+
+    This is the body
+
+you'll get output like:
+
+.. sourcecode:: html
+
+    <div class="white">
+        This is the body
+    </div>
+
+.. seealso::
+
+    :ref:`namespace_attr_for_includes` - a more sophisticated example using
+    :attr:`.Namespace.attr`.
diff --git a/doc/_sources/namespaces.txt b/doc/_sources/namespaces.txt
new file mode 100644 (file)
index 0000000..1453b80
--- /dev/null
@@ -0,0 +1,475 @@
+.. _namespaces_toplevel:
+
+==========
+Namespaces
+==========
+
+Namespaces are used to organize groups of defs into
+categories, and also to "import" defs from other files.
+
+If the file ``components.html`` defines these two defs:
+
+.. sourcecode:: mako
+
+    ## components.html
+    <%def name="comp1()">
+        this is comp1
+    </%def>
+
+    <%def name="comp2(x)">
+        this is comp2, x is ${x}
+    </%def>
+
+you can make another file, for example ``index.html``, that
+pulls those two defs into a namespace called ``comp``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%namespace name="comp" file="components.html"/>
+
+    Here's comp1:  ${comp.comp1()}
+    Here's comp2:  ${comp.comp2(x=5)}
+
+The ``comp`` variable above is an instance of
+:class:`.Namespace`, a **proxy object** which delivers
+method calls to the underlying template callable using the
+current context.
+
+``<%namespace>`` also provides an ``import`` attribute which can
+be used to pull the names into the local namespace, removing the
+need to call it via the "``.``" operator. When ``import`` is used, the
+``name`` attribute is optional.
+
+.. sourcecode:: mako
+
+    <%namespace file="components.html" import="comp1, comp2"/>
+
+    Heres comp1:  ${comp1()}
+    Heres comp2:  ${comp2(x=5)}
+
+``import`` also supports the "``*``" operator:
+
+.. sourcecode:: mako
+
+    <%namespace file="components.html" import="*"/>
+
+    Heres comp1:  ${comp1()}
+    Heres comp2:  ${comp2(x=5)}
+
+The names imported by the ``import`` attribute take precedence
+over any names that exist within the current context.
+
+.. note:: In current versions of Mako, usage of ``import='*'`` is
+   known to decrease performance of the template. This will be
+   fixed in a future release.
+
+The ``file`` argument allows expressions -- if looking for
+context variables, the ``context`` must be named explicitly:
+
+.. sourcecode:: mako
+
+    <%namespace name="dyn" file="${context['namespace_name']}"/>
+
+Ways to Call Namespaces
+=======================
+
+There are essentially four ways to call a function from a
+namespace.
+
+The "expression" format, as described previously. Namespaces are
+just Python objects with functions on them, and can be used in
+expressions like any other function:
+
+.. sourcecode:: mako
+
+    ${mynamespace.somefunction('some arg1', 'some arg2', arg3='some arg3', arg4='some arg4')}
+
+Synonymous with the "expression" format is the "custom tag"
+format, when a "closed" tag is used. This format, introduced in
+Mako 0.2.3, allows the usage of a "custom" Mako tag, with the
+function arguments passed in using named attributes:
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="some arg1" arg2="some arg2" arg3="some arg3" arg4="some arg4"/>
+
+When using tags, the values of the arguments are taken as
+literal strings by default. To embed Python expressions as
+arguments, use the embedded expression format:
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="${someobject.format()}" arg2="${somedef(5, 12)}"/>
+
+The "custom tag" format is intended mainly for namespace
+functions which recognize body content, which in Mako is known
+as a "def with embedded content":
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="some argument" args="x, y">
+        Some record: ${x}, ${y}
+    </%mynamespace:somefunction>
+
+The "classic" way to call defs with embedded content is the ``<%call>`` tag:
+
+.. sourcecode:: mako
+
+    <%call expr="mynamespace.somefunction(arg1='some argument')" args="x, y">
+        Some record: ${x}, ${y}
+    </%call>
+
+For information on how to construct defs that embed content from
+the caller, see :ref:`defs_with_content`.
+
+.. _namespaces_python_modules:
+
+Namespaces from Regular Python Modules
+======================================
+
+Namespaces can also import regular Python functions from
+modules. These callables need to take at least one argument,
+``context``, an instance of :class:`.Context`. A module file
+``some/module.py`` might contain the callable:
+
+.. sourcecode:: python
+
+    def my_tag(context):
+        context.write("hello world")
+        return ''
+
+A template can use this module via:
+
+.. sourcecode:: mako
+
+    <%namespace name="hw" module="some.module"/>
+
+    ${hw.my_tag()}
+
+Note that the ``context`` argument is not needed in the call;
+the :class:`.Namespace` tag creates a locally-scoped callable which
+takes care of it. The ``return ''`` is so that the def does not
+dump a ``None`` into the output stream -- the return value of any
+def is rendered after the def completes, in addition to whatever
+was passed to :meth:`.Context.write` within its body.
+
+If your def is to be called in an "embedded content" context,
+that is as described in :ref:`defs_with_content`, you should use
+the :func:`.supports_caller` decorator, which will ensure that Mako
+will ensure the correct "caller" variable is available when your
+def is called, supporting embedded content:
+
+.. sourcecode:: python
+
+    from mako.runtime import supports_caller
+
+    @supports_caller
+    def my_tag(context):
+        context.write("<div>")
+        context['caller'].body()
+        context.write("</div>")
+        return ''
+
+Capturing of output is available as well, using the
+outside-of-templates version of the :func:`.capture` function,
+which accepts the "context" as its first argument:
+
+.. sourcecode:: python
+
+    from mako.runtime import supports_caller, capture
+
+    @supports_caller
+    def my_tag(context):
+        return "<div>%s</div>" % \
+                capture(context, context['caller'].body, x="foo", y="bar")
+
+Declaring Defs in Namespaces
+============================
+
+The ``<%namespace>`` tag supports the definition of ``<%def>``\ s
+directly inside the tag. These defs become part of the namespace
+like any other function, and will override the definitions
+pulled in from a remote template or module:
+
+.. sourcecode:: mako
+
+    ## define a namespace
+    <%namespace name="stuff">
+        <%def name="comp1()">
+            comp1
+        </%def>
+    </%namespace>
+
+    ## then call it
+    ${stuff.comp1()}
+
+.. _namespaces_body:
+
+The ``body()`` Method
+=====================
+
+Every namespace that is generated from a template contains a
+method called ``body()``. This method corresponds to the main
+body of the template, and plays its most important roles when
+using inheritance relationships as well as
+def-calls-with-content.
+
+Since the ``body()`` method is available from a namespace just
+like all the other defs defined in a template, what happens if
+you send arguments to it? By default, the ``body()`` method
+accepts no positional arguments, and for usefulness in
+inheritance scenarios will by default dump all keyword arguments
+into a dictionary called ``pageargs``. But if you actually want
+to get at the keyword arguments, Mako recommends you define your
+own argument signature explicitly. You do this via using the
+``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%page args="x, y, someval=8, scope='foo', **kwargs"/>
+
+A template which defines the above signature requires that the
+variables ``x`` and ``y`` are defined, defines default values
+for ``someval`` and ``scope``, and sets up ``**kwargs`` to
+receive all other keyword arguments. If ``**kwargs`` or similar
+is not present, the argument ``**pageargs`` gets tacked on by
+Mako. When the template is called as a top-level template (i.e.
+via :meth:`~.Template.render`) or via the ``<%include>`` tag, the
+values for these arguments will be pulled from the ``Context``.
+In all other cases, i.e. via calling the ``body()`` method, the
+arguments are taken as ordinary arguments from the method call.
+So above, the body might be called as:
+
+.. sourcecode:: mako
+
+    ${self.body(5, y=10, someval=15, delta=7)}
+
+The :class:`.Context` object also supplies a :attr:`~.Context.kwargs`
+accessor, for cases when you'd like to pass along the top level context
+arguments to a ``body()`` callable:
+
+.. sourcecode:: mako
+
+    ${next.body(**context.kwargs)}
+
+The usefulness of calls like the above become more apparent when
+one works with inheriting templates. For more information on
+this, as well as the meanings of the names ``self`` and
+``next``, see :ref:`inheritance_toplevel`.
+
+.. _namespaces_builtin:
+
+Built-in Namespaces
+===================
+
+The namespace is so great that Mako gives your template one (or
+two) for free. The names of these namespaces are ``local`` and
+``self``. Other built-in namespaces include ``parent`` and
+``next``, which are optional and are described in
+:ref:`inheritance_toplevel`.
+
+.. _namespace_local:
+
+``local``
+---------
+
+The ``local`` namespace is basically the namespace for the
+currently executing template. This means that all of the top
+level defs defined in your template, as well as your template's
+``body()`` function, are also available off of the ``local``
+namespace.
+
+The ``local`` namespace is also where properties like ``uri``,
+``filename``, and ``module`` and the ``get_namespace`` method
+can be particularly useful.
+
+.. _namespace_self:
+
+``self``
+--------
+
+The ``self`` namespace, in the case of a template that does not
+use inheritance, is synonymous with ``local``. If inheritance is
+used, then ``self`` references the topmost template in the
+inheritance chain, where it is most useful for providing the
+ultimate form of various "method" calls which may have been
+overridden at various points in an inheritance chain. See
+:ref:`inheritance_toplevel`.
+
+Inheritable Namespaces
+======================
+
+The ``<%namespace>`` tag includes an optional attribute
+``inheritable="True"``, which will cause the namespace to be
+attached to the ``self`` namespace. Since ``self`` is globally
+available throughout an inheritance chain (described in the next
+section), all the templates in an inheritance chain can get at
+the namespace imported in a super-template via ``self``.
+
+.. sourcecode:: mako
+
+    ## base.html
+    <%namespace name="foo" file="foo.html" inheritable="True"/>
+
+    ${next.body()}
+
+    ## somefile.html
+    <%inherit file="base.html"/>
+
+    ${self.foo.bar()}
+
+This allows a super-template to load a whole bunch of namespaces
+that its inheriting templates can get to, without them having to
+explicitly load those namespaces themselves.
+
+The ``import="*"`` part of the ``<%namespace>`` tag doesn't yet
+interact with the ``inheritable`` flag, so currently you have to
+use the explicit namespace name off of ``self``, followed by the
+desired function name. But more on this in a future release.
+
+Namespace API Usage Example - Static Dependencies
+==================================================
+
+The ``<%namespace>`` tag at runtime produces an instance of
+:class:`.Namespace`.   Programmatic access of :class:`.Namespace` can be used
+to build various kinds of scaffolding in templates and between templates.
+
+A common request is the ability for a particular template to declare
+"static includes" - meaning, the usage of a particular set of defs requires
+that certain Javascript/CSS files are present.   Using :class:`.Namespace` as the
+object that holds together the various templates present, we can build a variety
+of such schemes.   In particular, the :class:`.Context` has a ``namespaces``
+attribute, which is a dictionary of all :class:`.Namespace` objects declared.
+Iterating the values of this dictionary will provide a :class:`.Namespace`
+object for each time the ``<%namespace>`` tag was used, anywhere within the
+inheritance chain.
+
+
+.. _namespace_attr_for_includes:
+
+Version One - Use :attr:`.Namespace.attr`
+-----------------------------------------
+
+The :attr:`.Namespace.attr` attribute allows us to locate any variables declared
+in the ``<%! %>`` of a template.
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ## base-most template, renders layout etc.
+    <html>
+    <head>
+    ## traverse through all namespaces present,
+    ## look for an attribute named 'includes'
+    % for ns in context.namespaces.values():
+        % for incl in getattr(ns.attr, 'includes', []):
+            ${incl}
+        % endfor
+    % endfor
+    </head>
+    <body>
+    ${next.body()}
+    </body
+    </html>
+
+    ## library.mako
+    ## library functions.
+    <%!
+        includes = [
+            '<link rel="stylesheet" type="text/css" href="mystyle.css"/>',
+            '<script type="text/javascript" src="functions.js"></script>'
+        ]
+    %>
+
+    <%def name="mytag()">
+        <form>
+            ${caller.body()}
+        </form>
+    </%def>
+
+    ## index.mako
+    ## calling template.
+    <%inherit file="base.mako"/>
+    <%namespace name="foo" file="library.mako"/>
+
+    <%foo:mytag>
+        a form
+    </%foo:mytag>
+
+
+Above, the file ``library.mako`` declares an attribute ``includes`` inside its global ``<%! %>`` section.
+``index.mako`` includes this template using the ``<%namespace>`` tag.  The base template ``base.mako``, which is the inherited parent of ``index.mako`` and is reponsible for layout, then locates this attribute and iterates through its contents to produce the includes that are specific to ``library.mako``.
+
+Version Two - Use a specific named def
+-----------------------------------------
+
+In this version, we put the includes into a ``<%def>`` that
+follows a naming convention.
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ## base-most template, renders layout etc.
+    <html>
+    <head>
+    ## traverse through all namespaces present,
+    ## look for a %def named 'includes'
+    % for ns in context.namespaces.values():
+        % if hasattr(ns, 'includes'):
+            ${ns.includes()}
+        % endif
+    % endfor
+    </head>
+    <body>
+    ${next.body()}
+    </body
+    </html>
+
+    ## library.mako
+    ## library functions.
+
+    <%def name="includes()">
+        <link rel="stylesheet" type="text/css" href="mystyle.css"/>
+        <script type="text/javascript" src="functions.js"></script>
+    </%def>
+
+    <%def name="mytag()">
+        <form>
+            ${caller.body()}
+        </form>
+    </%def>
+
+
+    ## index.mako
+    ## calling template.
+    <%inherit file="base.mako"/>
+    <%namespace name="foo" file="library.mako"/>
+
+    <%foo:mytag>
+        a form
+    </%foo:mytag>
+
+In this version, ``library.mako`` declares a ``<%def>`` named ``includes``.   The example works
+identically to the previous one, except that ``base.mako`` looks for defs named ``include``
+on each namespace it examines.
+
+API Reference
+=============
+
+.. autoclass:: mako.runtime.Namespace
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.TemplateNamespace
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.ModuleNamespace
+    :show-inheritance:
+    :members:
+
+.. autofunction:: mako.runtime.supports_caller
+
+.. autofunction:: mako.runtime.capture
+
diff --git a/doc/_sources/runtime.txt b/doc/_sources/runtime.txt
new file mode 100644 (file)
index 0000000..17c9b99
--- /dev/null
@@ -0,0 +1,448 @@
+.. _runtime_toplevel:
+
+============================
+The Mako Runtime Environment
+============================
+
+This section describes a little bit about the objects and
+built-in functions that are available in templates.
+
+.. _context:
+
+Context
+=======
+
+The :class:`.Context` is the central object that is created when
+a template is first executed, and is responsible for handling
+all communication with the outside world.  Within the template
+environment, it is available via the :ref:`reserved name <reserved_names>`
+``context``.  The :class:`.Context` includes two
+major components, one of which is the output buffer, which is a
+file-like object such as Python's ``StringIO`` or similar, and
+the other a dictionary of variables that can be freely
+referenced within a template; this dictionary is a combination
+of the arguments sent to the :meth:`~.Template.render` function and
+some built-in variables provided by Mako's runtime environment.
+
+The Buffer
+----------
+
+The buffer is stored within the :class:`.Context`, and writing
+to it is achieved by calling the :meth:`~.Context.write` method
+-- in a template this looks like ``context.write('some string')``.
+You usually don't need to care about this, as all text within a template, as
+well as all expressions provided by ``${}``, automatically send
+everything to this method. The cases you might want to be aware
+of its existence are if you are dealing with various
+filtering/buffering scenarios, which are described in
+:ref:`filtering_toplevel`, or if you want to programmatically
+send content to the output stream, such as within a ``<% %>``
+block.
+
+.. sourcecode:: mako
+
+    <%
+        context.write("some programmatic text")
+    %>
+
+The actual buffer may or may not be the original buffer sent to
+the :class:`.Context` object, as various filtering/caching
+scenarios may "push" a new buffer onto the context's underlying
+buffer stack. For this reason, just stick with
+``context.write()`` and content will always go to the topmost
+buffer.
+
+.. _context_vars:
+
+Context Variables
+-----------------
+
+When your template is compiled into a Python module, the body
+content is enclosed within a Python function called
+``render_body``. Other top-level defs defined in the template are
+defined within their own function bodies which are named after
+the def's name with the prefix ``render_`` (i.e. ``render_mydef``).
+One of the first things that happens within these functions is
+that all variable names that are referenced within the function
+which are not defined in some other way (i.e. such as via
+assignment, module level imports, etc.) are pulled from the
+:class:`.Context` object's dictionary of variables. This is how you're
+able to freely reference variable names in a template which
+automatically correspond to what was passed into the current
+:class:`.Context`.
+
+* **What happens if I reference a variable name that is not in
+  the current context?** - The value you get back is a special
+  value called ``UNDEFINED``, or if the ``strict_undefined=True`` flag
+  is used a ``NameError`` is raised. ``UNDEFINED`` is just a simple global
+  variable with the class :class:`mako.runtime.Undefined`. The
+  ``UNDEFINED`` object throws an error when you call ``str()`` on
+  it, which is what happens if you try to use it in an
+  expression.
+* **UNDEFINED makes it hard for me to find what name is missing** - An alternative
+  is to specify the option ``strict_undefined=True``
+  to the :class:`.Template` or :class:`.TemplateLookup`.  This will cause
+  any non-present variables to raise an immediate ``NameError``
+  which includes the name of the variable in its message
+  when :meth:`~.Template.render` is called -- ``UNDEFINED`` is not used.
+
+  .. versionadded:: 0.3.6
+
+* **Why not just return None?** Using ``UNDEFINED``, or
+  raising a ``NameError`` is more
+  explicit and allows differentiation between a value of ``None``
+  that was explicitly passed to the :class:`.Context` and a value that
+  wasn't present at all.
+* **Why raise an exception when you call str() on it ? Why not
+  just return a blank string?** - Mako tries to stick to the
+  Python philosophy of "explicit is better than implicit". In
+  this case, it's decided that the template author should be made
+  to specifically handle a missing value rather than
+  experiencing what may be a silent failure. Since ``UNDEFINED``
+  is a singleton object just like Python's ``True`` or ``False``,
+  you can use the ``is`` operator to check for it:
+
+  .. sourcecode:: mako
+
+        % if someval is UNDEFINED:
+            someval is: no value
+        % else:
+            someval is: ${someval}
+        % endif
+
+Another facet of the :class:`.Context` is that its dictionary of
+variables is **immutable**. Whatever is set when
+:meth:`~.Template.render` is called is what stays. Of course, since
+its Python, you can hack around this and change values in the
+context's internal dictionary, but this will probably will not
+work as well as you'd think. The reason for this is that Mako in
+many cases creates copies of the :class:`.Context` object, which
+get sent to various elements of the template and inheriting
+templates used in an execution. So changing the value in your
+local :class:`.Context` will not necessarily make that value
+available in other parts of the template's execution. Examples
+of where Mako creates copies of the :class:`.Context` include
+within top-level def calls from the main body of the template
+(the context is used to propagate locally assigned variables
+into the scope of defs; since in the template's body they appear
+as inlined functions, Mako tries to make them act that way), and
+within an inheritance chain (each template in an inheritance
+chain has a different notion of ``parent`` and ``next``, which
+are all stored in unique :class:`.Context` instances).
+
+* **So what if I want to set values that are global to everyone
+  within a template request?** - All you have to do is provide a
+  dictionary to your :class:`.Context` when the template first
+  runs, and everyone can just get/set variables from that. Lets
+  say its called ``attributes``.
+
+  Running the template looks like:
+
+  .. sourcecode:: python
+
+      output = template.render(attributes={})
+
+  Within a template, just reference the dictionary:
+
+  .. sourcecode:: mako
+
+      <%
+          attributes['foo'] = 'bar'
+      %>
+      'foo' attribute is: ${attributes['foo']}
+
+* **Why can't "attributes" be a built-in feature of the
+  Context?** - This is an area where Mako is trying to make as
+  few decisions about your application as it possibly can.
+  Perhaps you don't want your templates to use this technique of
+  assigning and sharing data, or perhaps you have a different
+  notion of the names and kinds of data structures that should
+  be passed around. Once again Mako would rather ask the user to
+  be explicit.
+
+Context Methods and Accessors
+-----------------------------
+
+Significant members of :class:`.Context` include:
+
+* ``context[key]`` / ``context.get(key, default=None)`` -
+  dictionary-like accessors for the context. Normally, any
+  variable you use in your template is automatically pulled from
+  the context if it isn't defined somewhere already. Use the
+  dictionary accessor and/or ``get`` method when you want a
+  variable that *is* already defined somewhere else, such as in
+  the local arguments sent to a ``%def`` call. If a key is not
+  present, like a dictionary it raises ``KeyError``.
+* ``keys()`` - all the names defined within this context.
+* ``kwargs`` - this returns a **copy** of the context's
+  dictionary of variables. This is useful when you want to
+  propagate the variables in the current context to a function
+  as keyword arguments, i.e.:
+
+  .. sourcecode:: mako
+
+        ${next.body(**context.kwargs)}
+
+* ``write(text)`` - write some text to the current output
+  stream.
+* ``lookup`` - returns the :class:`.TemplateLookup` instance that is
+  used for all file-lookups within the current execution (even
+  though individual :class:`.Template` instances can conceivably have
+  different instances of a :class:`.TemplateLookup`, only the
+  :class:`.TemplateLookup` of the originally-called :class:`.Template` gets
+  used in a particular execution).
+
+.. _loop_context:
+
+The Loop Context
+================
+
+Within ``% for`` blocks, the :ref:`reserved name<reserved_names>` ``loop``
+is available.  ``loop`` tracks the progress of
+the ``for`` loop and makes it easy to use the iteration state to control
+template behavior:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for a in ("one", "two", "three"):
+        <li>Item ${loop.index}: ${a}</li>
+    % endfor
+    </ul>
+
+.. versionadded:: 0.7
+
+Iterations
+----------
+
+Regardless of the type of iterable you're looping over, ``loop`` always tracks
+the 0-indexed iteration count (available at ``loop.index``), its parity
+(through the ``loop.even`` and ``loop.odd`` bools), and ``loop.first``, a bool
+indicating whether the loop is on its first iteration.  If your iterable
+provides a ``__len__`` method, ``loop`` also provides access to
+a count of iterations remaining at ``loop.reverse_index`` and ``loop.last``,
+a bool indicating whether the loop is on its last iteration; accessing these
+without ``__len__`` will raise a ``TypeError``.
+
+Cycling
+-------
+
+Cycling is available regardless of whether the iterable you're using provides
+a ``__len__`` method.  Prior to Mako 0.7, you might have generated a simple
+zebra striped list using ``enumerate``:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for i, item in enumerate(('spam', 'ham', 'eggs')):
+      <li class="${'odd' if i % 2 else 'even'}">${item}</li>
+    % endfor
+    </ul>
+
+With ``loop.cycle``, you get the same results with cleaner code and less prep work:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for item in ('spam', 'ham', 'eggs'):
+      <li class="${loop.cycle('even', 'odd')}">${item}</li>
+    % endfor
+    </ul>
+
+Both approaches produce output like the following:
+
+.. sourcecode:: html
+
+    <ul>
+      <li class="even">spam</li>
+      <li class="odd">ham</li>
+      <li class="even">eggs</li>
+    </ul>
+
+Parent Loops
+------------
+
+Loop contexts can also be transparently nested, and the Mako runtime will do
+the right thing and manage the scope for you.  You can access the parent loop
+context through ``loop.parent``.
+
+This allows you to reach all the way back up through the loop stack by
+chaining ``parent`` attribute accesses, i.e. ``loop.parent.parent....`` as
+long as the stack depth isn't exceeded.  For example, you can use the parent
+loop to make a checkered table:
+
+.. sourcecode:: mako
+
+    <table>
+    % for consonant in 'pbj':
+      <tr>
+      % for vowel in 'iou':
+        <td class="${'black' if (loop.parent.even == loop.even) else 'red'}">
+          ${consonant + vowel}t
+        </td>
+      % endfor
+      </tr>
+    % endfor
+    </table>
+
+.. sourcecode:: html
+
+    <table>
+      <tr>
+        <td class="black">
+          pit
+        </td>
+        <td class="red">
+          pot
+        </td>
+        <td class="black">
+          put
+        </td>
+      </tr>
+      <tr>
+        <td class="red">
+          bit
+        </td>
+        <td class="black">
+          bot
+        </td>
+        <td class="red">
+          but
+        </td>
+      </tr>
+      <tr>
+        <td class="black">
+          jit
+        </td>
+        <td class="red">
+          jot
+        </td>
+        <td class="black">
+          jut
+        </td>
+      </tr>
+    </table>
+
+.. _migrating_loop:
+
+Migrating Legacy Templates that Use the Word "loop"
+---------------------------------------------------
+
+.. versionchanged:: 0.7
+   The ``loop`` name is now :ref:`reserved <reserved_names>` in Mako,
+   which means a template that refers to a variable named ``loop``
+   won't function correctly when used in Mako 0.7.
+
+To ease the transition for such systems, the feature can be disabled across the board for
+all templates, then re-enabled on a per-template basis for those templates which wish
+to make use of the new system.
+
+First, the ``enable_loop=False`` flag is passed to either the :class:`.TemplateLookup`
+or :class:`.Template` object in use:
+
+.. sourcecode:: python
+
+    lookup = TemplateLookup(directories=['/docs'], enable_loop=False)
+
+or:
+
+.. sourcecode:: python
+
+    template = Template("some template", enable_loop=False)
+
+An individual template can make usage of the feature when ``enable_loop`` is set to
+``False`` by switching it back on within the ``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%page enable_loop="True"/>
+
+    % for i in collection:
+        ${i} ${loop.index}
+    % endfor
+
+Using the above scheme, it's safe to pass the name ``loop`` to the :meth:`.Template.render`
+method as well as to freely make usage of a variable named ``loop`` within a template, provided
+the ``<%page>`` tag doesn't override it.  New templates that want to use the ``loop`` context
+can then set up ``<%page enable_loop="True"/>`` to use the new feature without affecting
+old templates.
+
+All the Built-in Names
+======================
+
+A one-stop shop for all the names Mako defines. Most of these
+names are instances of :class:`.Namespace`, which are described
+in the next section, :ref:`namespaces_toplevel`. Also, most of
+these names other than ``context``, ``UNDEFINED``, and ``loop`` are
+also present *within* the :class:`.Context` itself.   The names
+``context``, ``loop`` and ``UNDEFINED`` themselves can't be passed
+to the context and can't be substituted -- see the section :ref:`reserved_names`.
+
+* ``context`` - this is the :class:`.Context` object, introduced
+  at :ref:`context`.
+* ``local`` - the namespace of the current template, described
+  in :ref:`namespaces_builtin`.
+* ``self`` - the namespace of the topmost template in an
+  inheritance chain (if any, otherwise the same as ``local``),
+  mostly described in :ref:`inheritance_toplevel`.
+* ``parent`` - the namespace of the parent template in an
+  inheritance chain (otherwise undefined); see
+  :ref:`inheritance_toplevel`.
+* ``next`` - the namespace of the next template in an
+  inheritance chain (otherwise undefined); see
+  :ref:`inheritance_toplevel`.
+* ``caller`` - a "mini" namespace created when using the
+  ``<%call>`` tag to define a "def call with content"; described
+  in :ref:`defs_with_content`.
+* ``loop`` - this provides access to :class:`.LoopContext` objects when
+  they are requested within ``% for`` loops, introduced at :ref:`loop_context`.
+* ``capture`` - a function that calls a given def and captures
+  its resulting content into a string, which is returned. Usage
+  is described in :ref:`filtering_toplevel`.
+* ``UNDEFINED`` - a global singleton that is applied to all
+  otherwise uninitialized template variables that were not
+  located within the :class:`.Context` when rendering began,
+  unless the :class:`.Template` flag ``strict_undefined``
+  is set to ``True``. ``UNDEFINED`` is
+  an instance of :class:`.Undefined`, and raises an
+  exception when its ``__str__()`` method is called.
+* ``pageargs`` - this is a dictionary which is present in a
+  template which does not define any ``**kwargs`` section in its
+  ``<%page>`` tag. All keyword arguments sent to the ``body()``
+  function of a template (when used via namespaces) go here by
+  default unless otherwise defined as a page argument. If this
+  makes no sense, it shouldn't; read the section
+  :ref:`namespaces_body`.
+
+.. _reserved_names:
+
+Reserved Names
+--------------
+
+Mako has a few names that are considered to be "reserved" and can't be used
+as variable names.
+
+.. versionchanged:: 0.7
+   Mako raises an error if these words are found passed to the template
+   as context arguments, whereas in previous versions they'd be silently
+   ignored or lead to other error messages.
+
+* ``context`` - see :ref:`context`.
+* ``UNDEFINED`` - see :ref:`context_vars`.
+* ``loop`` - see :ref:`loop_context`.  Note this can be disabled for legacy templates
+  via the ``enable_loop=False`` argument; see :ref:`migrating_loop`.
+
+API Reference
+=============
+
+.. autoclass:: mako.runtime.Context
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.LoopContext
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.Undefined
+    :show-inheritance:
+
diff --git a/doc/_sources/syntax.txt b/doc/_sources/syntax.txt
new file mode 100644 (file)
index 0000000..e3dd7db
--- /dev/null
@@ -0,0 +1,486 @@
+.. _syntax_toplevel:
+
+======
+Syntax
+======
+
+A Mako template is parsed from a text stream containing any kind
+of content, XML, HTML, email text, etc. The template can further
+contain Mako-specific directives which represent variable and/or
+expression substitutions, control structures (i.e. conditionals
+and loops), server-side comments, full blocks of Python code, as
+well as various tags that offer additional functionality. All of
+these constructs compile into real Python code. This means that
+you can leverage the full power of Python in almost every aspect
+of a Mako template.
+
+Expression Substitution
+=======================
+
+The simplest expression is just a variable substitution. The
+syntax for this is the ``${}`` construct, which is inspired by
+Perl, Genshi, JSP EL, and others:
+
+.. sourcecode:: mako
+
+    this is x: ${x}
+
+Above, the string representation of ``x`` is applied to the
+template's output stream. If you're wondering where ``x`` comes
+from, it's usually from the :class:`.Context` supplied to the
+template's rendering function. If ``x`` was not supplied to the
+template and was not otherwise assigned locally, it evaluates to
+a special value ``UNDEFINED``. More on that later.
+
+The contents within the ``${}`` tag are evaluated by Python
+directly, so full expressions are OK:
+
+.. sourcecode:: mako
+
+    pythagorean theorem:  ${pow(x,2) + pow(y,2)}
+
+The results of the expression are evaluated into a string result
+in all cases before being rendered to the output stream, such as
+the above example where the expression produces a numeric
+result.
+
+Expression Escaping
+===================
+
+Mako includes a number of built-in escaping mechanisms,
+including HTML, URI and XML escaping, as well as a "trim"
+function. These escapes can be added to an expression
+substitution using the ``|`` operator:
+
+.. sourcecode:: mako
+
+    ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``. The ``u`` name indicates URL
+escaping, whereas ``h`` represents HTML escaping, ``x``
+represents XML escaping, and ``trim`` applies a trim function.
+
+Read more about built-in filtering functions, including how to
+make your own filter functions, in :ref:`filtering_toplevel`.
+
+Control Structures
+==================
+
+A control structure refers to all those things that control the
+flow of a program -- conditionals (i.e. ``if``/``else``), loops (like
+``while`` and ``for``), as well as things like ``try``/``except``. In Mako,
+control structures are written using the ``%`` marker followed
+by a regular Python control expression, and are "closed" by
+using another ``%`` marker with the tag "``end<name>``", where
+"``<name>``" is the keyword of the expression:
+
+.. sourcecode:: mako
+
+    % if x==5:
+        this is some output
+    % endif
+
+The ``%`` can appear anywhere on the line as long as no text
+precedes it; indentation is not significant. The full range of
+Python "colon" expressions are allowed here, including
+``if``/``elif``/``else``, ``while``, ``for``, and even ``def``, although
+Mako has a built-in tag for defs which is more full-featured.
+
+.. sourcecode:: mako
+
+    % for a in ['one', 'two', 'three', 'four', 'five']:
+        % if a[0] == 't':
+        its two or three
+        % elif a[0] == 'f':
+        four/five
+        % else:
+        one
+        % endif
+    % endfor
+
+The ``%`` sign can also be "escaped", if you actually want to
+emit a percent sign as the first non whitespace character on a
+line, by escaping it as in ``%%``:
+
+.. sourcecode:: mako
+
+    %% some text
+
+        %% some more text
+
+The Loop Context
+----------------
+
+The **loop context** provides additional information about a loop
+while inside of a ``% for`` structure:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for a in ("one", "two", "three"):
+        <li>Item ${loop.index}: ${a}</li>
+    % endfor
+    </ul>
+
+See :ref:`loop_context` for more information on this feature.
+
+.. versionadded:: 0.7
+
+Comments
+========
+
+Comments come in two varieties. The single line comment uses
+``##`` as the first non-space characters on a line:
+
+.. sourcecode:: mako
+
+    ## this is a comment.
+    ...text ...
+
+A multiline version exists using ``<%doc> ...text... </%doc>``:
+
+.. sourcecode:: mako
+
+    <%doc>
+        these are comments
+        more comments
+    </%doc>
+
+Newline Filters
+===============
+
+The backslash ("``\``") character, placed at the end of any
+line, will consume the newline character before continuing to
+the next line:
+
+.. sourcecode:: mako
+
+    here is a line that goes onto \
+    another line.
+
+The above text evaluates to:
+
+.. sourcecode:: text
+
+    here is a line that goes onto another line.
+
+Python Blocks
+=============
+
+Any arbitrary block of python can be dropped in using the ``<%
+%>`` tags:
+
+.. sourcecode:: mako
+
+    this is a template
+    <%
+        x = db.get_resource('foo')
+        y = [z.element for z in x if x.frobnizzle==5]
+    %>
+    % for elem in y:
+        element: ${elem}
+    % endfor
+
+Within ``<% %>``, you're writing a regular block of Python code.
+While the code can appear with an arbitrary level of preceding
+whitespace, it has to be consistently formatted with itself.
+Mako's compiler will adjust the block of Python to be consistent
+with the surrounding generated Python code.
+
+Module-level Blocks
+===================
+
+A variant on ``<% %>`` is the module-level code block, denoted
+by ``<%! %>``. Code within these tags is executed at the module
+level of the template, and not within the rendering function of
+the template. Therefore, this code does not have access to the
+template's context and is only executed when the template is
+loaded into memory (which can be only once per application, or
+more, depending on the runtime environment). Use the ``<%! %>``
+tags to declare your template's imports, as well as any
+pure-Python functions you might want to declare:
+
+.. sourcecode:: mako
+
+    <%!
+        import mylib
+        import re
+
+        def filter(text):
+            return re.sub(r'^@', '', text)
+    %>
+
+Any number of ``<%! %>`` blocks can be declared anywhere in a
+template; they will be rendered in the resulting module
+in a single contiguous block above all render callables,
+in the order in which they appear in the source template.
+
+Tags
+====
+
+The rest of what Mako offers takes place in the form of tags.
+All tags use the same syntax, which is similar to an XML tag
+except that the first character of the tag name is a ``%``
+character. The tag is closed either by a contained slash
+character, or an explicit closing tag:
+
+.. sourcecode:: mako
+
+    <%include file="foo.txt"/>
+
+    <%def name="foo" buffered="True">
+        this is a def
+    </%def>
+
+All tags have a set of attributes which are defined for each
+tag. Some of these attributes are required. Also, many
+attributes support **evaluation**, meaning you can embed an
+expression (using ``${}``) inside the attribute text:
+
+.. sourcecode:: mako
+
+    <%include file="/foo/bar/${myfile}.txt"/>
+
+Whether or not an attribute accepts runtime evaluation depends
+on the type of tag and how that tag is compiled into the
+template. The best way to find out if you can stick an
+expression in is to try it! The lexer will tell you if it's not
+valid.
+
+Heres a quick summary of all the tags:
+
+``<%page>``
+-----------
+
+This tag defines general characteristics of the template,
+including caching arguments, and optional lists of arguments
+which the template expects when invoked.
+
+.. sourcecode:: mako
+
+    <%page args="x, y, z='default'"/>
+
+Or a page tag that defines caching characteristics:
+
+.. sourcecode:: mako
+
+    <%page cached="True" cache_type="memory"/>
+
+Currently, only one ``<%page>`` tag gets used per template, the
+rest get ignored. While this will be improved in a future
+release, for now make sure you have only one ``<%page>`` tag
+defined in your template, else you may not get the results you
+want. The details of what ``<%page>`` is used for are described
+further in :ref:`namespaces_body` as well as :ref:`caching_toplevel`.
+
+``<%include>``
+--------------
+
+A tag that is familiar from other template languages, ``%include``
+is a regular joe that just accepts a file argument and calls in
+the rendered result of that file:
+
+.. sourcecode:: mako
+
+    <%include file="header.html"/>
+
+        hello world
+
+    <%include file="footer.html"/>
+
+Include also accepts arguments which are available as ``<%page>`` arguments in the receiving template:
+
+.. sourcecode:: mako
+
+    <%include file="toolbar.html" args="current_section='members', username='ed'"/>
+
+``<%def>``
+----------
+
+The ``%def`` tag defines a Python function which contains a set
+of content, that can be called at some other point in the
+template. The basic idea is simple:
+
+.. sourcecode:: mako
+
+    <%def name="myfunc(x)">
+        this is myfunc, x is ${x}
+    </%def>
+
+    ${myfunc(7)}
+
+The ``%def`` tag is a lot more powerful than a plain Python ``def``, as
+the Mako compiler provides many extra services with ``%def`` that
+you wouldn't normally have, such as the ability to export defs
+as template "methods", automatic propagation of the current
+:class:`.Context`, buffering/filtering/caching flags, and def calls
+with content, which enable packages of defs to be sent as
+arguments to other def calls (not as hard as it sounds). Get the
+full deal on what ``%def`` can do in :ref:`defs_toplevel`.
+
+``<%block>``
+------------
+
+``%block`` is a tag that is close to a ``%def``,
+except executes itself immediately in its base-most scope,
+and can also be anonymous (i.e. with no name):
+
+.. sourcecode:: mako
+
+    <%block filter="h">
+        some <html> stuff.
+    </%block>
+
+Inspired by Jinja2 blocks, named blocks offer a syntactically pleasing way
+to do inheritance:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+        <%block name="header">
+            <h2><%block name="title"/></h2>
+        </%block>
+        ${self.body()}
+        </body>
+    </html>
+
+Blocks are introduced in :ref:`blocks` and further described in :ref:`inheritance_toplevel`.
+
+.. versionadded:: 0.4.1
+
+``<%namespace>``
+----------------
+
+``%namespace`` is Mako's equivalent of Python's ``import``
+statement. It allows access to all the rendering functions and
+metadata of other template files, plain Python modules, as well
+as locally defined "packages" of functions.
+
+.. sourcecode:: mako
+
+    <%namespace file="functions.html" import="*"/>
+
+The underlying object generated by ``%namespace``, an instance of
+:class:`.mako.runtime.Namespace`, is a central construct used in
+templates to reference template-specific information such as the
+current URI, inheritance structures, and other things that are
+not as hard as they sound right here. Namespaces are described
+in :ref:`namespaces_toplevel`.
+
+``<%inherit>``
+--------------
+
+Inherit allows templates to arrange themselves in **inheritance
+chains**. This is a concept familiar in many other template
+languages.
+
+.. sourcecode:: mako
+
+    <%inherit file="base.html"/>
+
+When using the ``%inherit`` tag, control is passed to the topmost
+inherited template first, which then decides how to handle
+calling areas of content from its inheriting templates. Mako
+offers a lot of flexibility in this area, including dynamic
+inheritance, content wrapping, and polymorphic method calls.
+Check it out in :ref:`inheritance_toplevel`.
+
+``<%``\ nsname\ ``:``\ defname\ ``>``
+-------------------------------------
+
+Any user-defined "tag" can be created against
+a namespace by using a tag with a name of the form
+``<%<namespacename>:<defname>>``. The closed and open formats of such a
+tag are equivalent to an inline expression and the ``<%call>``
+tag, respectively.
+
+.. sourcecode:: mako
+
+    <%mynamespace:somedef param="some value">
+        this is the body
+    </%mynamespace:somedef>
+
+To create custom tags which accept a body, see
+:ref:`defs_with_content`.
+
+.. versionadded:: 0.2.3
+
+``<%call>``
+-----------
+
+The call tag is the "classic" form of a user-defined tag, and is
+roughly equivalent to the ``<%namespacename:defname>`` syntax
+described above. This tag is also described in :ref:`defs_with_content`.
+
+``<%doc>``
+----------
+
+The ``%doc`` tag handles multiline comments:
+
+.. sourcecode:: mako
+
+    <%doc>
+        these are comments
+        more comments
+    </%doc>
+
+Also the ``##`` symbol as the first non-space characters on a line can be used for single line comments.
+
+``<%text>``
+-----------
+
+This tag suspends the Mako lexer's normal parsing of Mako
+template directives, and returns its entire body contents as
+plain text. It is used pretty much to write documentation about
+Mako:
+
+.. sourcecode:: mako
+
+    <%text filter="h">
+        heres some fake mako ${syntax}
+        <%def name="x()">${x}</%def>
+    </%text>
+
+.. _syntax_exiting_early:
+
+Exiting Early from a Template
+=============================
+
+Sometimes you want to stop processing a template or ``<%def>``
+method in the middle and just use the text you've accumulated so
+far.  This is accomplished by using ``return`` statement inside
+a Python block.   It's a good idea for the ``return`` statement
+to return an empty string, which prevents the Python default return
+value of ``None`` from being rendered by the template.  This
+return value is for semantic purposes provided in templates via
+the ``STOP_RENDERING`` symbol:
+
+.. sourcecode:: mako
+
+    % if not len(records):
+        No records found.
+        <% return STOP_RENDERING %>
+    % endif
+
+Or perhaps:
+
+.. sourcecode:: mako
+
+    <%
+        if not len(records):
+            return STOP_RENDERING
+    %>
+
+In older versions of Mako, an empty string can be substituted for
+the ``STOP_RENDERING`` symbol:
+
+.. sourcecode:: mako
+
+    <% return '' %>
+
+.. versionadded:: 1.0.2 - added the ``STOP_RENDERING`` symbol which serves
+   as a semantic identifier for the empty string ``""`` used by a
+   Python ``return`` statement.
+
diff --git a/doc/_sources/unicode.txt b/doc/_sources/unicode.txt
new file mode 100644 (file)
index 0000000..1ba364e
--- /dev/null
@@ -0,0 +1,345 @@
+.. _unicode_toplevel:
+
+===================
+The Unicode Chapter
+===================
+
+The Python language supports two ways of representing what we
+know as "strings", i.e. series of characters. In Python 2, the
+two types are ``string`` and ``unicode``, and in Python 3 they are
+``bytes`` and ``string``. A key aspect of the Python 2 ``string`` and
+Python 3 ``bytes`` types are that they contain no information
+regarding what **encoding** the data is stored in. For this
+reason they were commonly referred to as **byte strings** on
+Python 2, and Python 3 makes this name more explicit. The
+origins of this come from Python's background of being developed
+before the Unicode standard was even available, back when
+strings were C-style strings and were just that, a series of
+bytes. Strings that had only values below 128 just happened to
+be **ASCII** strings and were printable on the console, whereas
+strings with values above 128 would produce all kinds of
+graphical characters and bells.
+
+Contrast the "byte-string" type with the "unicode/string" type.
+Objects of this latter type are created whenever you say something like
+``u"hello world"`` (or in Python 3, just ``"hello world"``). In this
+case, Python represents each character in the string internally
+using multiple bytes per character (something similar to
+UTF-16). What's important is that when using the
+``unicode``/``string`` type to store strings, Python knows the
+data's encoding; it's in its own internal format. Whereas when
+using the ``string``/``bytes`` type, it does not.
+
+When Python 2 attempts to treat a byte-string as a string, which
+means it's attempting to compare/parse its characters, to coerce
+it into another encoding, or to decode it to a unicode object,
+it has to guess what the encoding is. In this case, it will
+pretty much always guess the encoding as ``ascii``... and if the
+byte-string contains bytes above value 128, you'll get an error.
+Python 3 eliminates much of this confusion by just raising an
+error unconditionally if a byte-string is used in a
+character-aware context.
+
+There is one operation that Python *can* do with a non-ASCII
+byte-string, and it's a great source of confusion: it can dump the
+byte-string straight out to a stream or a file, with nary a care
+what the encoding is. To Python, this is pretty much like
+dumping any other kind of binary data (like an image) to a
+stream somewhere. In Python 2, it is common to see programs that
+embed all kinds of international characters and encodings into
+plain byte-strings (i.e. using ``"hello world"`` style literals)
+can fly right through their run, sending reams of strings out to
+wherever they are going, and the programmer, seeing the same
+output as was expressed in the input, is now under the illusion
+that his or her program is Unicode-compliant. In fact, their
+program has no unicode awareness whatsoever, and similarly has
+no ability to interact with libraries that *are* unicode aware.
+Python 3 makes this much less likely by defaulting to unicode as
+the storage format for strings.
+
+The "pass through encoded data" scheme is what template
+languages like Cheetah and earlier versions of Myghty do by
+default. Mako as of version 0.2 also supports this mode of
+operation when using Python 2, using the ``disable_unicode=True``
+flag. However, when using Mako in its default mode of
+unicode-aware, it requires explicitness when dealing with
+non-ASCII encodings. Additionally, if you ever need to handle
+unicode strings and other kinds of encoding conversions more
+intelligently, the usage of raw byte-strings quickly becomes a
+nightmare, since you are sending the Python interpreter
+collections of bytes for which it can make no intelligent
+decisions with regards to encoding. In Python 3 Mako only allows
+usage of native, unicode strings.
+
+In normal Mako operation, all parsed template constructs and
+output streams are handled internally as Python ``unicode``
+objects. It's only at the point of :meth:`~.Template.render` that this unicode
+stream may be rendered into whatever the desired output encoding
+is. The implication here is that the template developer must
+:ensure that :ref:`the encoding of all non-ASCII templates is explicit
+<set_template_file_encoding>` (still required in Python 3),
+that :ref:`all non-ASCII-encoded expressions are in one way or another
+converted to unicode <handling_non_ascii_expressions>`
+(not much of a burden in Python 3), and that :ref:`the output stream of the
+template is handled as a unicode stream being encoded to some
+encoding <defining_output_encoding>` (still required in Python 3).
+
+.. _set_template_file_encoding:
+
+Specifying the Encoding of a Template File
+==========================================
+
+This is the most basic encoding-related setting, and it is
+equivalent to Python's "magic encoding comment", as described in
+`pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_. Any
+template that contains non-ASCII characters requires that this
+comment be present so that Mako can decode to unicode (and also
+make usage of Python's AST parsing services). Mako's lexer will
+use this encoding in order to convert the template source into a
+``unicode`` object before continuing its parsing:
+
+.. sourcecode:: mako
+
+    ## -*- coding: utf-8 -*-
+
+    Alors vous imaginez ma surprise, au lever du jour, quand 
+    une drôle de petite voix m’a réveillé. Elle disait:
+     « S’il vous plaît… dessine-moi un mouton! »
+
+For the picky, the regular expression used is derived from that
+of the above mentioned pep:
+
+.. sourcecode:: python
+
+    #.*coding[:=]\s*([-\w.]+).*\n
+
+The lexer will convert to unicode in all cases, so that if any
+characters exist in the template that are outside of the
+specified encoding (or the default of ``ascii``), the error will
+be immediate.
+
+As an alternative, the template encoding can be specified
+programmatically to either :class:`.Template` or :class:`.TemplateLookup` via
+the ``input_encoding`` parameter:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['./'], input_encoding='utf-8')
+
+The above will assume all located templates specify ``utf-8``
+encoding, unless the template itself contains its own magic
+encoding comment, which takes precedence.
+
+.. _handling_non_ascii_expressions:
+
+Handling Expressions
+====================
+
+The next area that encoding comes into play is in expression
+constructs. By default, Mako's treatment of an expression like
+this:
+
+.. sourcecode:: mako
+
+    ${"hello world"}
+
+looks something like this:
+
+.. sourcecode:: python
+
+    context.write(unicode("hello world"))
+
+In Python 3, it's just:
+
+.. sourcecode:: python
+
+    context.write(str("hello world"))
+
+That is, **the output of all expressions is run through the
+``unicode`` built-in**. This is the default setting, and can be
+modified to expect various encodings. The ``unicode`` step serves
+both the purpose of rendering non-string expressions into
+strings (such as integers or objects which contain ``__str()__``
+methods), and to ensure that the final output stream is
+constructed as a unicode object. The main implication of this is
+that **any raw byte-strings that contain an encoding other than
+ASCII must first be decoded to a Python unicode object**. It
+means you can't say this in Python 2:
+
+.. sourcecode:: mako
+
+    ${"voix m’a réveillé."}  ## error in Python 2!
+
+You must instead say this:
+
+.. sourcecode:: mako
+
+    ${u"voix m’a réveillé."}  ## OK !
+
+Similarly, if you are reading data from a file that is streaming
+bytes, or returning data from some object that is returning a
+Python byte-string containing a non-ASCII encoding, you have to
+explicitly decode to unicode first, such as:
+
+.. sourcecode:: mako
+
+    ${call_my_object().decode('utf-8')}
+
+Note that filehandles acquired by ``open()`` in Python 3 default
+to returning "text", that is the decoding is done for you. See
+Python 3's documentation for the ``open()`` built-in for details on
+this.
+
+If you want a certain encoding applied to *all* expressions,
+override the ``unicode`` builtin with the ``decode`` built-in at the
+:class:`.Template` or :class:`.TemplateLookup` level:
+
+.. sourcecode:: python
+
+    t = Template(templatetext, default_filters=['decode.utf8'])
+
+Note that the built-in ``decode`` object is slower than the
+``unicode`` function, since unlike ``unicode`` it's not a Python
+built-in, and it also checks the type of the incoming data to
+determine if string conversion is needed first.
+
+The ``default_filters`` argument can be used to entirely customize
+the filtering process of expressions. This argument is described
+in :ref:`filtering_default_filters`.
+
+.. _defining_output_encoding:
+
+Defining Output Encoding
+========================
+
+Now that we have a template which produces a pure unicode output
+stream, all the hard work is done. We can take the output and do
+anything with it.
+
+As stated in the :doc:`"Usage" chapter <usage>`, both :class:`.Template` and
+:class:`.TemplateLookup` accept ``output_encoding`` and ``encoding_errors``
+parameters which can be used to encode the output in any Python
+supported codec:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
+
+    mytemplate = mylookup.get_template("foo.txt")
+    print(mytemplate.render())
+
+:meth:`~.Template.render` will return a ``bytes`` object in Python 3 if an output
+encoding is specified. By default it performs no encoding and
+returns a native string.
+
+:meth:`~.Template.render_unicode` will return the template output as a Python
+``unicode`` object (or ``string`` in Python 3):
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode())
+
+The above method disgards the output encoding keyword argument;
+you can encode yourself by saying:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode().encode('utf-8', 'replace'))
+
+Buffer Selection
+----------------
+
+Mako does play some games with the style of buffering used
+internally, to maximize performance. Since the buffer is by far
+the most heavily used object in a render operation, it's
+important!
+
+When calling :meth:`~.Template.render` on a template that does not specify any
+output encoding (i.e. it's ``ascii``), Python's ``cStringIO`` module,
+which cannot handle encoding of non-ASCII ``unicode`` objects
+(even though it can send raw byte-strings through), is used for
+buffering. Otherwise, a custom Mako class called
+``FastEncodingBuffer`` is used, which essentially is a super
+dumbed-down version of ``StringIO`` that gathers all strings into
+a list and uses ``u''.join(elements)`` to produce the final output
+-- it's markedly faster than ``StringIO``.
+
+.. _unicode_disabled:
+
+Saying to Heck with It: Disabling the Usage of Unicode Entirely
+===============================================================
+
+Some segments of Mako's userbase choose to make no usage of
+Unicode whatsoever, and instead would prefer the "pass through"
+approach; all string expressions in their templates return
+encoded byte-strings, and they would like these strings to pass
+right through. The only advantage to this approach is that
+templates need not use ``u""`` for literal strings; there's an
+arguable speed improvement as well since raw byte-strings
+generally perform slightly faster than unicode objects in
+Python. For these users, assuming they're sticking with Python
+2, they can hit the ``disable_unicode=True`` flag as so:
+
+.. sourcecode:: python
+
+    # -*- coding:utf-8 -*-
+    from mako.template import Template
+
+    t = Template("drôle de petite voix m’a réveillé.", disable_unicode=True, input_encoding='utf-8')
+    print(t.code)
+
+The ``disable_unicode`` mode is strictly a Python 2 thing. It is
+not supported at all in Python 3.
+
+The generated module source code will contain elements like
+these:
+
+.. sourcecode:: python
+
+    # -*- coding:utf-8 -*-
+    #  ...more generated code ...
+
+    def render_body(context,**pageargs):
+        context.caller_stack.push_frame()
+        try:
+            __M_locals = dict(pageargs=pageargs)
+            # SOURCE LINE 1
+            context.write('dr\xc3\xb4le de petite voix m\xe2\x80\x99a r\xc3\xa9veill\xc3\xa9.')
+            return ''
+        finally:
+            context.caller_stack.pop_frame()
+
+Where above that the string literal used within :meth:`.Context.write`
+is a regular byte-string.
+
+When ``disable_unicode=True`` is turned on, the ``default_filters``
+argument which normally defaults to ``["unicode"]`` now defaults
+to ``["str"]`` instead. Setting ``default_filters`` to the empty list
+``[]`` can remove the overhead of the ``str`` call. Also, in this
+mode you **cannot** safely call :meth:`~.Template.render_unicode` -- you'll get
+unicode/decode errors.
+
+The ``h`` filter (HTML escape) uses a less performant pure Python
+escape function in non-unicode mode. This because
+MarkupSafe only supports Python unicode objects for non-ASCII
+strings.
+
+.. versionchanged:: 0.3.4
+   In prior versions, it used ``cgi.escape()``, which has been replaced
+   with a function that also escapes single quotes.
+
+Rules for using ``disable_unicode=True``
+----------------------------------------
+
+* Don't use this mode unless you really, really want to and you
+  absolutely understand what you're doing.
+* Don't use this option just because you don't want to learn to
+  use Unicode properly; we aren't supporting user issues in this
+  mode of operation. We will however offer generous help for the
+  vast majority of users who stick to the Unicode program.
+* Python 3 is unicode by default, and the flag is not available
+  when running on Python 3.
+
diff --git a/doc/_sources/usage.txt b/doc/_sources/usage.txt
new file mode 100644 (file)
index 0000000..ceb8d41
--- /dev/null
@@ -0,0 +1,520 @@
+.. _usage_toplevel:
+
+=====
+Usage
+=====
+
+Basic Usage
+===========
+
+This section describes the Python API for Mako templates. If you
+are using Mako within a web framework such as Pylons, the work
+of integrating Mako's API is already done for you, in which case
+you can skip to the next section, :ref:`syntax_toplevel`.
+
+The most basic way to create a template and render it is through
+the :class:`.Template` class:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template("hello world!")
+    print(mytemplate.render())
+
+Above, the text argument to :class:`.Template` is **compiled** into a
+Python module representation. This module contains a function
+called ``render_body()``, which produces the output of the
+template. When ``mytemplate.render()`` is called, Mako sets up a
+runtime environment for the template and calls the
+``render_body()`` function, capturing the output into a buffer and
+returning its string contents.
+
+
+The code inside the ``render_body()`` function has access to a
+namespace of variables. You can specify these variables by
+sending them as additional keyword arguments to the :meth:`~.Template.render`
+method:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template("hello, ${name}!")
+    print(mytemplate.render(name="jack"))
+
+The :meth:`~.Template.render` method calls upon Mako to create a
+:class:`.Context` object, which stores all the variable names accessible
+to the template and also stores a buffer used to capture output.
+You can create this :class:`.Context` yourself and have the template
+render with it, using the :meth:`~.Template.render_context` method:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.runtime import Context
+    from StringIO import StringIO
+
+    mytemplate = Template("hello, ${name}!")
+    buf = StringIO()
+    ctx = Context(buf, name="jack")
+    mytemplate.render_context(ctx)
+    print(buf.getvalue())
+
+Using File-Based Templates
+==========================
+
+A :class:`.Template` can also load its template source code from a file,
+using the ``filename`` keyword argument:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template(filename='/docs/mytmpl.txt')
+    print(mytemplate.render())
+
+For improved performance, a :class:`.Template` which is loaded from a
+file can also cache the source code to its generated module on
+the filesystem as a regular Python module file (i.e. a ``.py``
+file). To do this, just add the ``module_directory`` argument to
+the template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template(filename='/docs/mytmpl.txt', module_directory='/tmp/mako_modules')
+    print(mytemplate.render())
+
+When the above code is rendered, a file
+``/tmp/mako_modules/docs/mytmpl.txt.py`` is created containing the
+source code for the module. The next time a :class:`.Template` with the
+same arguments is created, this module file will be
+automatically re-used.
+
+.. _usage_templatelookup:
+
+Using ``TemplateLookup``
+========================
+
+All of the examples thus far have dealt with the usage of a
+single :class:`.Template` object. If the code within those templates
+tries to locate another template resource, it will need some way
+to find them, using simple URI strings. For this need, the
+resolution of other templates from within a template is
+accomplished by the :class:`.TemplateLookup` class. This class is
+constructed given a list of directories in which to search for
+templates, as well as keyword arguments that will be passed to
+the :class:`.Template` objects it creates:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'])
+    mytemplate = Template("""<%include file="header.txt"/> hello world!""", lookup=mylookup)
+
+Above, we created a textual template which includes the file
+``"header.txt"``. In order for it to have somewhere to look for
+``"header.txt"``, we passed a :class:`.TemplateLookup` object to it, which
+will search in the directory ``/docs`` for the file ``"header.txt"``.
+
+Usually, an application will store most or all of its templates
+as text files on the filesystem. So far, all of our examples
+have been a little bit contrived in order to illustrate the
+basic concepts. But a real application would get most or all of
+its templates directly from the :class:`.TemplateLookup`, using the
+aptly named :meth:`~.TemplateLookup.get_template` method, which accepts the URI of the
+desired template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], module_directory='/tmp/mako_modules')
+
+    def serve_template(templatename, **kwargs):
+        mytemplate = mylookup.get_template(templatename)
+        print(mytemplate.render(**kwargs))
+
+In the example above, we create a :class:`.TemplateLookup` which will
+look for templates in the ``/docs`` directory, and will store
+generated module files in the ``/tmp/mako_modules`` directory. The
+lookup locates templates by appending the given URI to each of
+its search directories; so if you gave it a URI of
+``/etc/beans/info.txt``, it would search for the file
+``/docs/etc/beans/info.txt``, else raise a :class:`.TopLevelNotFound`
+exception, which is a custom Mako exception.
+
+When the lookup locates templates, it will also assign a ``uri``
+property to the :class:`.Template` which is the URI passed to the
+:meth:`~.TemplateLookup.get_template()` call. :class:`.Template` uses this URI to calculate the
+name of its module file. So in the above example, a
+``templatename`` argument of ``/etc/beans/info.txt`` will create a
+module file ``/tmp/mako_modules/etc/beans/info.txt.py``.
+
+Setting the Collection Size
+---------------------------
+
+The :class:`.TemplateLookup` also serves the important need of caching a
+fixed set of templates in memory at a given time, so that
+successive URI lookups do not result in full template
+compilations and/or module reloads on each request. By default,
+the :class:`.TemplateLookup` size is unbounded. You can specify a fixed
+size using the ``collection_size`` argument:
+
+.. sourcecode:: python
+
+    mylookup = TemplateLookup(directories=['/docs'],
+                    module_directory='/tmp/mako_modules', collection_size=500)
+
+The above lookup will continue to load templates into memory
+until it reaches a count of around 500. At that point, it will
+clean out a certain percentage of templates using a least
+recently used scheme.
+
+Setting Filesystem Checks
+-------------------------
+
+Another important flag on :class:`.TemplateLookup` is
+``filesystem_checks``. This defaults to ``True``, and says that each
+time a template is returned by the :meth:`~.TemplateLookup.get_template()` method, the
+revision time of the original template file is checked against
+the last time the template was loaded, and if the file is newer
+will reload its contents and recompile the template. On a
+production system, setting ``filesystem_checks`` to ``False`` can
+afford a small to moderate performance increase (depending on
+the type of filesystem used).
+
+.. _usage_unicode:
+
+Using Unicode and Encoding
+==========================
+
+Both :class:`.Template` and :class:`.TemplateLookup` accept ``output_encoding``
+and ``encoding_errors`` parameters which can be used to encode the
+output in any Python supported codec:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
+
+    mytemplate = mylookup.get_template("foo.txt")
+    print(mytemplate.render())
+
+When using Python 3, the :meth:`~.Template.render` method will return a ``bytes``
+object, **if** ``output_encoding`` is set. Otherwise it returns a
+``string``.
+
+Additionally, the :meth:`~.Template.render_unicode()` method exists which will
+return the template output as a Python ``unicode`` object, or in
+Python 3 a ``string``:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode())
+
+The above method disregards the output encoding keyword
+argument; you can encode yourself by saying:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode().encode('utf-8', 'replace'))
+
+Note that Mako's ability to return data in any encoding and/or
+``unicode`` implies that the underlying output stream of the
+template is a Python unicode object. This behavior is described
+fully in :ref:`unicode_toplevel`.
+
+.. _handling_exceptions:
+
+Handling Exceptions
+===================
+
+Template exceptions can occur in two distinct places. One is
+when you **lookup, parse and compile** the template, the other
+is when you **run** the template. Within the running of a
+template, exceptions are thrown normally from whatever Python
+code originated the issue. Mako has its own set of exception
+classes which mostly apply to the lookup and lexer/compiler
+stages of template construction. Mako provides some library
+routines that can be used to help provide Mako-specific
+information about any exception's stack trace, as well as
+formatting the exception within textual or HTML format. In all
+cases, the main value of these handlers is that of converting
+Python filenames, line numbers, and code samples into Mako
+template filenames, line numbers, and code samples. All lines
+within a stack trace which correspond to a Mako template module
+will be converted to be against the originating template file.
+
+To format exception traces, the :func:`.text_error_template` and
+:func:`.html_error_template` functions are provided. They make usage of
+``sys.exc_info()`` to get at the most recently thrown exception.
+Usage of these handlers usually looks like:
+
+.. sourcecode:: python
+
+    from mako import exceptions
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        print(exceptions.text_error_template().render())
+
+Or for the HTML render function:
+
+.. sourcecode:: python
+
+    from mako import exceptions
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        print(exceptions.html_error_template().render())
+
+The :func:`.html_error_template` template accepts two options:
+specifying ``full=False`` causes only a section of an HTML
+document to be rendered. Specifying ``css=False`` will disable the
+default stylesheet from being rendered.
+
+E.g.:
+
+.. sourcecode:: python
+
+    print(exceptions.html_error_template().render(full=False))
+
+The HTML render function is also available built-in to
+:class:`.Template` using the ``format_exceptions`` flag. In this case, any
+exceptions raised within the **render** stage of the template
+will result in the output being substituted with the output of
+:func:`.html_error_template`:
+
+.. sourcecode:: python
+
+    template = Template(filename="/foo/bar", format_exceptions=True)
+    print(template.render())
+
+Note that the compile stage of the above template occurs when
+you construct the :class:`.Template` itself, and no output stream is
+defined. Therefore exceptions which occur within the
+lookup/parse/compile stage will not be handled and will
+propagate normally. While the pre-render traceback usually will
+not include any Mako-specific lines anyway, it will mean that
+exceptions which occur previous to rendering and those which
+occur within rendering will be handled differently... so the
+``try``/``except`` patterns described previously are probably of more
+general use.
+
+The underlying object used by the error template functions is
+the :class:`.RichTraceback` object. This object can also be used
+directly to provide custom error views. Here's an example usage
+which describes its general API:
+
+.. sourcecode:: python
+
+    from mako.exceptions import RichTraceback
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        traceback = RichTraceback()
+        for (filename, lineno, function, line) in traceback.traceback:
+            print("File %s, line %s, in %s" % (filename, lineno, function))
+            print(line, "\n")
+        print("%s: %s" % (str(traceback.error.__class__.__name__), traceback.error))
+
+Common Framework Integrations
+=============================
+
+The Mako distribution includes a little bit of helper code for
+the purpose of using Mako in some popular web framework
+scenarios. This is a brief description of what's included.
+
+WSGI
+----
+
+A sample WSGI application is included in the distribution in the
+file ``examples/wsgi/run_wsgi.py``. This runner is set up to pull
+files from a `templates` as well as an `htdocs` directory and
+includes a rudimental two-file layout. The WSGI runner acts as a
+fully functional standalone web server, using ``wsgiutils`` to run
+itself, and propagates GET and POST arguments from the request
+into the :class:`.Context`, can serve images, CSS files and other kinds
+of files, and also displays errors using Mako's included
+exception-handling utilities.
+
+Pygments
+--------
+
+A `Pygments <http://pygments.pocoo.org>`_-compatible syntax
+highlighting module is included under :mod:`mako.ext.pygmentplugin`.
+This module is used in the generation of Mako documentation and
+also contains various `setuptools` entry points under the heading
+``pygments.lexers``, including ``mako``, ``html+mako``, ``xml+mako``
+(see the ``setup.py`` file for all the entry points).
+
+Babel
+-----
+
+Mako provides support for extracting `gettext` messages from
+templates via a `Babel`_ extractor
+entry point under ``mako.ext.babelplugin``.
+
+`Gettext` messages are extracted from all Python code sections,
+including those of control lines and expressions embedded
+in tags.
+
+`Translator
+comments <http://babel.edgewall.org/wiki/Documentation/messages.html#comments-tags-and-translator-comments-explanation>`_
+may also be extracted from Mako templates when a comment tag is
+specified to `Babel`_ (such as with
+the ``-c`` option).
+
+For example, a project ``"myproj"`` contains the following Mako
+template at ``myproj/myproj/templates/name.html``:
+
+.. sourcecode:: mako
+
+    <div id="name">
+      Name:
+      ## TRANSLATORS: This is a proper name. See the gettext
+      ## manual, section Names.
+      ${_('Francois Pinard')}
+    </div>
+
+To extract gettext messages from this template the project needs
+a Mako section in its `Babel Extraction Method Mapping
+file <http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration>`_
+(typically located at ``myproj/babel.cfg``):
+
+.. sourcecode:: cfg
+
+    # Extraction from Python source files
+
+    [python: myproj/**.py]
+
+    # Extraction from Mako templates
+
+    [mako: myproj/templates/**.html]
+    input_encoding = utf-8
+
+The Mako extractor supports an optional ``input_encoding``
+parameter specifying the encoding of the templates (identical to
+:class:`.Template`/:class:`.TemplateLookup`'s ``input_encoding`` parameter).
+
+Invoking `Babel`_'s extractor at the
+command line in the project's root directory:
+
+.. sourcecode:: sh
+
+    myproj$ pybabel extract -F babel.cfg -c "TRANSLATORS:" .
+
+will output a `gettext` catalog to `stdout` including the following:
+
+.. sourcecode:: pot
+
+    #. TRANSLATORS: This is a proper name. See the gettext
+    #. manual, section Names.
+    #: myproj/templates/name.html:5
+    msgid "Francois Pinard"
+    msgstr ""
+
+This is only a basic example:
+`Babel`_ can be invoked from ``setup.py``
+and its command line options specified in the accompanying
+``setup.cfg`` via `Babel Distutils/Setuptools
+Integration <http://babel.edgewall.org/wiki/Documentation/setup.html>`_.
+
+Comments must immediately precede a `gettext` message to be
+extracted. In the following case the ``TRANSLATORS:`` comment would
+not have been extracted:
+
+.. sourcecode:: mako
+
+    <div id="name">
+      ## TRANSLATORS: This is a proper name. See the gettext
+      ## manual, section Names.
+      Name: ${_('Francois Pinard')}
+    </div>
+
+See the `Babel User
+Guide <http://babel.edgewall.org/wiki/Documentation/index.html>`_
+for more information.
+
+.. _babel: http://babel.edgewall.org/
+
+
+API Reference
+=============
+
+.. autoclass:: mako.template.Template
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.template.DefTemplate
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.lookup.TemplateCollection
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.lookup.TemplateLookup
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.exceptions.RichTraceback
+    :show-inheritance:
+
+    .. py:attribute:: error
+
+       the exception instance.
+
+    .. py:attribute:: message
+
+       the exception error message as unicode.
+
+    .. py:attribute:: source
+
+       source code of the file where the error occurred.
+       If the error occurred within a compiled template,
+       this is the template source.
+
+    .. py:attribute:: lineno
+
+       line number where the error occurred.  If the error
+       occurred within a compiled template, the line number
+       is adjusted to that of the template source.
+
+    .. py:attribute:: records
+
+       a list of 8-tuples containing the original
+       python traceback elements, plus the
+       filename, line number, source line, and full template source
+       for the traceline mapped back to its originating source
+       template, if any for that traceline (else the fields are ``None``).
+
+    .. py:attribute:: reverse_records
+
+       the list of records in reverse
+       traceback -- a list of 4-tuples, in the same format as a regular
+       python traceback, with template-corresponding
+       traceback records replacing the originals.
+
+    .. py:attribute:: reverse_traceback
+
+       the traceback list in reverse.
+
+.. autofunction:: mako.exceptions.html_error_template
+
+.. autofunction:: mako.exceptions.text_error_template
+
diff --git a/doc/_static/basic.css b/doc/_static/basic.css
new file mode 100644 (file)
index 0000000..2b513f0
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+    clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+    width: 100%;
+    font-size: 90%;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+    float: left;
+    width: 230px;
+    margin-left: -100%;
+    font-size: 90%;
+    word-wrap: break-word;
+    overflow-wrap : break-word;
+}
+
+div.sphinxsidebar ul {
+    list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+    margin-left: 20px;
+    list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+    width: 170px;
+}
+
+img {
+    border: 0;
+    max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+    width: 100%;
+}
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+div.modindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+    -moz-hyphens: auto;
+    -ms-hyphens: auto;
+    -webkit-hyphens: auto;
+    hyphens: auto;
+}
+
+a.headerlink {
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.body p.caption {
+    text-align: inherit;
+}
+
+div.body td {
+    text-align: left;
+}
+
+.field-list ul {
+    padding-left: 1em;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+    clear: left;
+    float: left;
+    margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+    clear: right;
+    float: right;
+    margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+    text-align: left;
+}
+
+.align-center {
+    text-align: center;
+}
+
+.align-right {
+    text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+    margin: 0 0 0.5em 1em;
+    border: 1px solid #ddb;
+    padding: 7px 7px 0 7px;
+    background-color: #ffe;
+    width: 40%;
+    float: right;
+}
+
+p.sidebar-title {
+    font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+    border: 1px solid #ccc;
+    padding: 7px 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+    border: 0;
+    border-collapse: collapse;
+}
+
+table caption span.caption-number {
+    font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+table.docutils td, table.docutils th {
+    padding: 1px 8px 1px 5px;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+table.citation {
+    border-left: solid 1px gray;
+    margin-left: 1px;
+}
+
+table.citation td {
+    border-bottom: none;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure {
+    margin: 0.5em;
+    padding: 0.5em;
+}
+
+div.figure p.caption {
+    padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number {
+    font-style: italic;
+}
+
+div.figure p.caption span.caption-text {
+}
+
+
+/* -- other body styles ----------------------------------------------------- */
+
+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;
+}
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dt:target, .highlighted {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.sig-paren {
+    font-size: larger;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+.system-message {
+    background-color: #fda;
+    padding: 5px;
+    border: 3px solid red;
+}
+
+.footnote:target  {
+    background-color: #ffa;
+}
+
+.line-block {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+.line-block .line-block {
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+    font-family: sans-serif;
+}
+
+.accelerator {
+    text-decoration: underline;
+}
+
+.classifier {
+    font-style: oblique;
+}
+
+abbr, acronym {
+    border-bottom: dotted 1px;
+    cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+    overflow: auto;
+    overflow-y: hidden;  /* fixes display issues on Chrome browsers */
+}
+
+td.linenos pre {
+    padding: 5px 0px;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+div.code-block-caption {
+    padding: 2px 5px;
+    font-size: small;
+}
+
+div.code-block-caption code {
+    background-color: transparent;
+}
+
+div.code-block-caption + div > div.highlight > pre {
+    margin-top: 0;
+}
+
+div.code-block-caption span.caption-number {
+    padding: 0.1em 0.3em;
+    font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+    padding: 1em 1em 0;
+}
+
+div.literal-block-wrapper div.highlight {
+    margin: 0;
+}
+
+code.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+code.descclassname {
+    background-color: transparent;
+}
+
+code.xref, a code {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+    background-color: transparent;
+}
+
+.viewcode-link {
+    float: right;
+}
+
+.viewcode-back {
+    float: right;
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    margin: -1px -10px;
+    padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+    vertical-align: middle;
+}
+
+div.body div.math p {
+    text-align: center;
+}
+
+span.eqno {
+    float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+    div.document,
+    div.documentwrapper,
+    div.bodywrapper {
+        margin: 0 !important;
+        width: 100%;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    #top-link {
+        display: none;
+    }
+}
\ No newline at end of file
diff --git a/doc/_static/changelog.css b/doc/_static/changelog.css
new file mode 100644 (file)
index 0000000..d708ff8
--- /dev/null
@@ -0,0 +1,7 @@
+a.changeset-link {
+       visibility: hidden;
+}
+
+li:hover a.changeset-link {
+   visibility: visible;
+}
diff --git a/doc/_static/classic.css b/doc/_static/classic.css
new file mode 100644 (file)
index 0000000..d98894b
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: sans-serif;
+    font-size: 100%;
+    background-color: #11303d;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: #1c4e63;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+}
+
+div.body {
+    background-color: #ffffff;
+    color: #000000;
+    padding: 0 20px 30px 20px;
+}
+
+div.footer {
+    color: #ffffff;
+    width: 100%;
+    padding: 9px 0 9px 0;
+    text-align: center;
+    font-size: 75%;
+}
+
+div.footer a {
+    color: #ffffff;
+    text-decoration: underline;
+}
+
+div.related {
+    background-color: #133f52;
+    line-height: 30px;
+    color: #ffffff;
+}
+
+div.related a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    padding: 0;
+    color: #ffffff;
+}
+
+div.sphinxsidebar a {
+    color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:visited {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: 'Trebuchet MS', sans-serif;
+    background-color: #f2f2f2;
+    font-weight: normal;
+    color: #20435c;
+    border-bottom: 1px solid #ccc;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: #eeffcc;
+    color: #333333;
+    line-height: 120%;
+    border: 1px solid #ac9;
+    border-left: none;
+    border-right: none;
+}
+
+code {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+th {
+    background-color: #ede;
+}
+
+.warning code {
+    background: #efc2c2;
+}
+
+.note code {
+    background: #d6d6d6;
+}
+
+.viewcode-back {
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
+
+div.code-block-caption {
+    color: #efefef;
+    background-color: #1c4e63;
+}
\ No newline at end of file
diff --git a/doc/_static/comment-bright.png b/doc/_static/comment-bright.png
new file mode 100644 (file)
index 0000000..551517b
Binary files /dev/null and b/doc/_static/comment-bright.png differ
diff --git a/doc/_static/comment-close.png b/doc/_static/comment-close.png
new file mode 100644 (file)
index 0000000..09b54be
Binary files /dev/null and b/doc/_static/comment-close.png differ
diff --git a/doc/_static/comment.png b/doc/_static/comment.png
new file mode 100644 (file)
index 0000000..92feb52
Binary files /dev/null and b/doc/_static/comment.png differ
diff --git a/doc/_static/default.css b/doc/_static/default.css
new file mode 100644 (file)
index 0000000..81b9363
--- /dev/null
@@ -0,0 +1 @@
+@import url("classic.css");
diff --git a/doc/_static/docs.css b/doc/_static/docs.css
new file mode 100644 (file)
index 0000000..3d9e1c5
--- /dev/null
@@ -0,0 +1,438 @@
+/* global */
+
+body {
+  background-color: #FDFBFC;
+  margin:38px;
+  color:#333333;
+}
+
+a {
+    font-weight:normal; 
+    text-decoration:none;
+}
+
+form {
+    display:inline;
+}
+
+/* hyperlinks */
+
+a:link, a:visited, a:active {
+    color:#0000FF;
+}
+a:hover {
+    color:#700000;
+    text-decoration:underline;
+}
+
+/* paragraph links after sections.
+   These aren't visible until hovering
+   over the <h> tag, then have a 
+   "reverse video" effect over the actual
+   link
+ */
+
+a.headerlink {
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover {
+    background-color: #990000;
+    color: white;
+}
+
+
+/* Container setup */
+
+#docs-container {
+  max-width:1000px;
+}
+
+
+/* header/footer elements */
+
+#docs-header h1 {
+    font-size:20px;
+    color: #222222;
+    margin: 0;
+    padding: 0;
+}
+
+#docs-header {
+  font-family:Tahoma, Geneva,sans-serif;
+
+  font-size:.9em;
+
+}
+
+#docs-top-navigation,
+#docs-bottom-navigation {
+  font-family: Tahoma, Geneva, sans-serif;
+  background-color: #EEE;
+  border: solid 1px #CCC;
+  padding:10px;
+  font-size:.9em;
+}
+
+#docs-top-navigation {
+  margin:10px 0px 10px 0px;
+  line-height:1.2em;
+}
+
+.docs-navigation-links {
+  font-family:Tahoma, Geneva,sans-serif;
+}
+
+#docs-bottom-navigation {
+    float:right;
+    margin: 1em 0 1em 5px;
+}
+
+#docs-copyright {
+    font-size:.85em;
+    padding:5px 0px;
+}
+
+#docs-header h1,
+#docs-top-navigation h1,
+#docs-top-navigation h2 {
+  font-family:Tahoma,Geneva,sans-serif;
+  font-weight:normal;
+}
+
+#docs-top-navigation h2 {
+    margin:16px 4px 7px 5px;
+    font-size:2em;
+}
+
+#docs-search {
+    float:right;
+}
+
+#docs-top-page-control {
+  float:right;
+  width:350px;
+}
+
+#docs-top-page-control ul {
+  padding:0;
+  margin:0;
+}
+
+#docs-top-page-control li {
+    list-style-type:none;
+    padding:1px 8px;
+}
+
+
+#docs-container .version-num {
+    font-weight: bold;
+}
+
+
+/* content container, sidebar */
+
+#docs-body-container {
+  background-color:#EFEFEF;
+  border: solid 1px #CCC;
+
+}
+
+#docs-body,
+#docs-sidebar
+ {
+  /*font-family: helvetica, arial, sans-serif;
+  font-size:.9em;*/
+
+  font-family: Tahoma, Geneva, sans-serif;
+  /*font-size:.85em;*/
+  line-height:1.5em;
+
+}
+
+#docs-sidebar > ul {
+  font-size:.9em;
+}
+
+#docs-sidebar {
+  float:left;
+  width:212px;
+  padding: 10px 0 0 15px;
+  /*font-size:.85em;*/
+}
+
+#docs-sidebar h3, #docs-sidebar h4 {
+    background-color: #DDDDDD;
+    color: #222222;
+    font-family: Tahoma, Geneva,sans-serif;
+    font-size: 1.1em;
+    font-weight: normal;
+    margin: 10px 0 0 -15px;
+    padding: 5px 10px 5px 10px;
+    text-shadow: 1px 1px 0 white;
+    width:210px;
+}
+
+#docs-sidebar h3 a, #docs-sidebar h4 a {
+  color: #222222;
+}
+#docs-sidebar ul {
+  margin: 10px 10px 10px 0px;
+  padding: 0;
+  list-style: none outside none;
+}
+
+
+#docs-sidebar ul ul {
+    margin-bottom: 0;
+    margin-top: 0;
+    list-style: square outside none;
+    margin-left: 20px;
+}
+
+#docs-body {
+  background-color:#FFFFFF;
+  padding:1px 10px 10px 10px;
+}
+
+#docs-body.withsidebar {
+  margin: 0 0 0 230px;
+  border-left:3px solid #DFDFDF;
+}
+
+#docs-body h1,
+#docs-body h2,
+#docs-body h3,
+#docs-body h4 {
+  font-family:Tahoma, Geneva, sans-serif;
+}
+
+#docs-body h1 {
+  /* hide the <h1> for each content section. */
+  display:none;
+  font-size:1.8em;
+}
+
+#docs-body h2 {
+  font-size:1.6em;
+}
+
+#docs-body h3 {
+  font-size:1.4em;
+}
+
+/* SQL popup, code styles */
+
+.highlight {
+  background:none;
+}
+
+#docs-container pre {
+  font-size:1.2em;
+}
+
+#docs-container .pre {
+  font-size:1.1em;
+}
+
+#docs-container pre {
+  background-color: #f0f0f0;  
+  border: solid 1px #ccc;
+  box-shadow: 2px 2px 3px #DFDFDF;
+  padding:10px;
+  margin: 5px 0px 5px 0px;
+  overflow:auto;
+  line-height:1.3em;
+}
+
+.popup_sql, .show_sql
+{
+    background-color: #FBFBEE;
+    padding:5px 10px;
+    margin:10px -5px;
+    border:1px dashed;
+}
+
+/* the [SQL] links used to display SQL */
+#docs-container .sql_link
+{
+  font-weight:normal;
+  font-family: arial, sans-serif;
+  font-size:.9em;
+  text-transform: uppercase;
+  color:#990000;
+  border:1px solid;
+  padding:1px 2px 1px 2px;
+  margin:0px 10px 0px 15px;
+  float:right;
+  line-height:1.2em;
+}
+
+#docs-container a.sql_link, 
+#docs-container .sql_link
+{
+    text-decoration: none;
+    padding:1px 2px;
+}
+
+#docs-container a.sql_link:hover {
+    text-decoration: none;
+    color:#fff;
+    border:1px solid #900;
+    background-color: #900;
+}
+
+/* docutils-specific elements */
+
+th.field-name {
+    text-align:right;
+}
+
+div.note, div.warning, p.deprecated, div.topic  {
+    background-color:#EEFFEF;
+}
+
+
+div.admonition, div.topic, p.deprecated, p.versionadded, p.versionchanged {
+    border:1px solid #CCCCCC;
+    padding:5px 10px;
+    font-size:.9em;
+    box-shadow: 2px 2px 3px #DFDFDF;
+}
+
+div.warning .admonition-title {
+    color:#FF0000;
+}
+
+div.admonition .admonition-title, div.topic .topic-title {
+    font-weight:bold;
+}
+
+.viewcode-back, .viewcode-link {
+    float:right;
+}
+
+dl.function > dt,
+dl.attribute > dt,
+dl.classmethod > dt,
+dl.method > dt,
+dl.class > dt,
+dl.exception > dt
+{
+    background-color:#F0F0F0;
+    margin:25px -10px 10px 10px;
+    padding: 0px 10px;
+}
+
+p.versionadded span.versionmodified,
+p.versionchanged span.versionmodified,
+p.deprecated span.versionmodified {
+    background-color: #F0F0F0;
+    font-style: italic;
+}
+
+dt:target, span.highlight {
+    background-color:#FBE54E;
+}
+
+a.headerlink {
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover {
+    background-color: #00f;
+    color: white;
+}
+
+.clearboth {
+    clear:both;
+}
+
+tt.descname {
+    background-color:transparent;
+    font-size:1.2em;
+    font-weight:bold;
+}
+
+tt.descclassname {
+    background-color:transparent;
+}
+
+tt {
+    background-color:#ECF0F3;
+    padding:0 1px;
+}
+
+/* syntax highlighting overrides */
+.k, .kn {color:#0908CE;}
+.o {color:#BF0005;}
+.go {color:#804049;}
+
+
+/* special "index page" sections 
+   with specific formatting
+*/
+
+div#sqlalchemy-documentation {
+  font-size:.95em;
+}
+div#sqlalchemy-documentation em {
+  font-style:normal;
+}
+div#sqlalchemy-documentation .rubric{
+  font-size:14px;
+  background-color:#EEFFEF;
+  padding:5px;
+  border:1px solid #BFBFBF;
+}
+div#sqlalchemy-documentation a, div#sqlalchemy-documentation li {
+  padding:5px 0px;
+}
+
+div#getting-started {
+  border-bottom:1px solid;
+}
+
+div#sqlalchemy-documentation div#sqlalchemy-orm {
+  float:left;
+  width:48%;
+}
+
+div#sqlalchemy-documentation div#sqlalchemy-core {
+  float:left;
+  width:48%;
+  margin:0;
+  padding-left:10px;
+  border-left:1px solid;
+}
+
+div#dialect-documentation {
+  border-top:1px solid;
+  /*clear:left;*/
+}
diff --git a/doc/_static/doctools.js b/doc/_static/doctools.js
new file mode 100644 (file)
index 0000000..8163495
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for all documentation.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/**
+ * select a different prefix for underscore
+ */
+$u = _.noConflict();
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+if (!window.console || !console.firebug) {
+  var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
+    "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
+    "profile", "profileEnd"];
+  window.console = {};
+  for (var i = 0; i < names.length; ++i)
+    window.console[names[i]] = function() {};
+}
+ */
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+  return decodeURIComponent(x).replace(/\+/g, ' ');
+};
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+  if (typeof s == 'undefined')
+    s = document.location.search;
+  var parts = s.substr(s.indexOf('?') + 1).split('&');
+  var result = {};
+  for (var i = 0; i < parts.length; i++) {
+    var tmp = parts[i].split('=', 2);
+    var key = jQuery.urldecode(tmp[0]);
+    var value = jQuery.urldecode(tmp[1]);
+    if (key in result)
+      result[key].push(value);
+    else
+      result[key] = [value];
+  }
+  return result;
+};
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+  function highlight(node) {
+    if (node.nodeType == 3) {
+      var val = node.nodeValue;
+      var pos = val.toLowerCase().indexOf(text);
+      if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
+        var span = document.createElement("span");
+        span.className = className;
+        span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+        node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+          document.createTextNode(val.substr(pos + text.length)),
+          node.nextSibling));
+        node.nodeValue = val.substr(0, pos);
+      }
+    }
+    else if (!jQuery(node).is("button, select, textarea")) {
+      jQuery.each(node.childNodes, function() {
+        highlight(this);
+      });
+    }
+  }
+  return this.each(function() {
+    highlight(this);
+  });
+};
+
+/*
+ * backward compatibility for jQuery.browser
+ * This will be supported until firefox bug is fixed.
+ */
+if (!jQuery.browser) {
+  jQuery.uaMatch = function(ua) {
+    ua = ua.toLowerCase();
+
+    var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+      /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+      /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+      /(msie) ([\w.]+)/.exec(ua) ||
+      ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+      [];
+
+    return {
+      browser: match[ 1 ] || "",
+      version: match[ 2 ] || "0"
+    };
+  };
+  jQuery.browser = {};
+  jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
+}
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+  init : function() {
+    this.fixFirefoxAnchorBug();
+    this.highlightSearchWords();
+    this.initIndexTable();
+    
+  },
+
+  /**
+   * i18n support
+   */
+  TRANSLATIONS : {},
+  PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+  LOCALE : 'unknown',
+
+  // gettext and ngettext don't access this so that the functions
+  // can safely bound to a different name (_ = Documentation.gettext)
+  gettext : function(string) {
+    var translated = Documentation.TRANSLATIONS[string];
+    if (typeof translated == 'undefined')
+      return string;
+    return (typeof translated == 'string') ? translated : translated[0];
+  },
+
+  ngettext : function(singular, plural, n) {
+    var translated = Documentation.TRANSLATIONS[singular];
+    if (typeof translated == 'undefined')
+      return (n == 1) ? singular : plural;
+    return translated[Documentation.PLURALEXPR(n)];
+  },
+
+  addTranslations : function(catalog) {
+    for (var key in catalog.messages)
+      this.TRANSLATIONS[key] = catalog.messages[key];
+    this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+    this.LOCALE = catalog.locale;
+  },
+
+  /**
+   * add context elements like header anchor links
+   */
+  addContextElements : function() {
+    $('div[id] > :header:first').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this headline')).
+      appendTo(this);
+    });
+    $('dt[id]').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this definition')).
+      appendTo(this);
+    });
+  },
+
+  /**
+   * workaround a firefox stupidity
+   * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
+   */
+  fixFirefoxAnchorBug : function() {
+    if (document.location.hash)
+      window.setTimeout(function() {
+        document.location.href += '';
+      }, 10);
+  },
+
+  /**
+   * highlight the search words provided in the url in the text
+   */
+  highlightSearchWords : function() {
+    var params = $.getQueryParameters();
+    var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+    if (terms.length) {
+      var body = $('div.body');
+      if (!body.length) {
+        body = $('body');
+      }
+      window.setTimeout(function() {
+        $.each(terms, function() {
+          body.highlightText(this.toLowerCase(), 'highlighted');
+        });
+      }, 10);
+      $('<p class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
+          .appendTo($('#searchbox'));
+    }
+  },
+
+  /**
+   * init the domain index toggle buttons
+   */
+  initIndexTable : function() {
+    var togglers = $('img.toggler').click(function() {
+      var src = $(this).attr('src');
+      var idnum = $(this).attr('id').substr(7);
+      $('tr.cg-' + idnum).toggle();
+      if (src.substr(-9) == 'minus.png')
+        $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+      else
+        $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+    }).css('display', '');
+    if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
+        togglers.click();
+    }
+  },
+
+  /**
+   * helper function to hide the search marks again
+   */
+  hideSearchWords : function() {
+    $('#searchbox .highlight-link').fadeOut(300);
+    $('span.highlighted').removeClass('highlighted');
+  },
+
+  /**
+   * make the url absolute
+   */
+  makeURL : function(relativeURL) {
+    return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+  },
+
+  /**
+   * get the current relative url
+   */
+  getCurrentURL : function() {
+    var path = document.location.pathname;
+    var parts = path.split(/\//);
+    $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+      if (this == '..')
+        parts.pop();
+    });
+    var url = parts.join('/');
+    return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+  },
+
+  initOnKeyListeners: function() {
+    $(document).keyup(function(event) {
+      var activeElementType = document.activeElement.tagName;
+      // don't navigate when in search box or textarea
+      if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
+        switch (event.keyCode) {
+          case 37: // left
+            var prevHref = $('link[rel="prev"]').prop('href');
+            if (prevHref) {
+              window.location.href = prevHref;
+              return false;
+            }
+          case 39: // right
+            var nextHref = $('link[rel="next"]').prop('href');
+            if (nextHref) {
+              window.location.href = nextHref;
+              return false;
+            }
+        }
+      }
+    });
+  }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+  Documentation.init();
+});
\ No newline at end of file
diff --git a/doc/_static/down-pressed.png b/doc/_static/down-pressed.png
new file mode 100644 (file)
index 0000000..7c30d00
Binary files /dev/null and b/doc/_static/down-pressed.png differ
diff --git a/doc/_static/down.png b/doc/_static/down.png
new file mode 100644 (file)
index 0000000..f48098a
Binary files /dev/null and b/doc/_static/down.png differ
diff --git a/doc/_static/file.png b/doc/_static/file.png
new file mode 100644 (file)
index 0000000..254c60b
Binary files /dev/null and b/doc/_static/file.png differ
diff --git a/doc/_static/jquery-1.11.1.js b/doc/_static/jquery-1.11.1.js
new file mode 100644 (file)
index 0000000..d4b67f7
--- /dev/null
@@ -0,0 +1,10308 @@
+/*!
+ * jQuery JavaScript Library v1.11.1
+ * http://jquery.com/
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ *
+ * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-05-01T17:42Z
+ */
+
+(function( global, factory ) {
+
+       if ( typeof module === "object" && typeof module.exports === "object" ) {
+               // For CommonJS and CommonJS-like environments where a proper window is present,
+               // execute the factory and get jQuery
+               // For environments that do not inherently posses a window with a document
+               // (such as Node.js), expose a jQuery-making factory as module.exports
+               // This accentuates the need for the creation of a real window
+               // e.g. var jQuery = require("jquery")(window);
+               // See ticket #14549 for more info
+               module.exports = global.document ?
+                       factory( global, true ) :
+                       function( w ) {
+                               if ( !w.document ) {
+                                       throw new Error( "jQuery requires a window with a document" );
+                               }
+                               return factory( w );
+                       };
+       } else {
+               factory( global );
+       }
+
+// Pass this if window is not defined yet
+}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//
+
+var deletedIds = [];
+
+var slice = deletedIds.slice;
+
+var concat = deletedIds.concat;
+
+var push = deletedIds.push;
+
+var indexOf = deletedIds.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var support = {};
+
+
+
+var
+       version = "1.11.1",
+
+       // Define a local copy of jQuery
+       jQuery = function( selector, context ) {
+               // The jQuery object is actually just the init constructor 'enhanced'
+               // Need init if jQuery is called (just allow error to be thrown if not included)
+               return new jQuery.fn.init( selector, context );
+       },
+
+       // Support: Android<4.1, IE<9
+       // Make sure we trim BOM and NBSP
+       rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+       // Matches dashed string for camelizing
+       rmsPrefix = /^-ms-/,
+       rdashAlpha = /-([\da-z])/gi,
+
+       // Used by jQuery.camelCase as callback to replace()
+       fcamelCase = function( all, letter ) {
+               return letter.toUpperCase();
+       };
+
+jQuery.fn = jQuery.prototype = {
+       // The current version of jQuery being used
+       jquery: version,
+
+       constructor: jQuery,
+
+       // Start with an empty selector
+       selector: "",
+
+       // The default length of a jQuery object is 0
+       length: 0,
+
+       toArray: function() {
+               return slice.call( this );
+       },
+
+       // Get the Nth element in the matched element set OR
+       // Get the whole matched element set as a clean array
+       get: function( num ) {
+               return num != null ?
+
+                       // Return just the one element from the set
+                       ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
+
+                       // Return all the elements in a clean array
+                       slice.call( this );
+       },
+
+       // Take an array of elements and push it onto the stack
+       // (returning the new matched element set)
+       pushStack: function( elems ) {
+
+               // Build a new jQuery matched element set
+               var ret = jQuery.merge( this.constructor(), elems );
+
+               // Add the old object onto the stack (as a reference)
+               ret.prevObject = this;
+               ret.context = this.context;
+
+               // Return the newly-formed element set
+               return ret;
+       },
+
+       // Execute a callback for every element in the matched set.
+       // (You can seed the arguments with an array of args, but this is
+       // only used internally.)
+       each: function( callback, args ) {
+               return jQuery.each( this, callback, args );
+       },
+
+       map: function( callback ) {
+               return this.pushStack( jQuery.map(this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               }));
+       },
+
+       slice: function() {
+               return this.pushStack( slice.apply( this, arguments ) );
+       },
+
+       first: function() {
+               return this.eq( 0 );
+       },
+
+       last: function() {
+               return this.eq( -1 );
+       },
+
+       eq: function( i ) {
+               var len = this.length,
+                       j = +i + ( i < 0 ? len : 0 );
+               return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
+       },
+
+       end: function() {
+               return this.prevObject || this.constructor(null);
+       },
+
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: push,
+       sort: deletedIds.sort,
+       splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+       var src, copyIsArray, copy, name, options, clone,
+               target = arguments[0] || {},
+               i = 1,
+               length = arguments.length,
+               deep = false;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+
+               // skip the boolean and the target
+               target = arguments[ i ] || {};
+               i++;
+       }
+
+       // Handle case when target is a string or something (possible in deep copy)
+       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+               target = {};
+       }
+
+       // extend jQuery itself if only one argument is passed
+       if ( i === length ) {
+               target = this;
+               i--;
+       }
+
+       for ( ; i < length; i++ ) {
+               // Only deal with non-null/undefined values
+               if ( (options = arguments[ i ]) != null ) {
+                       // Extend the base object
+                       for ( name in options ) {
+                               src = target[ name ];
+                               copy = options[ name ];
+
+                               // Prevent never-ending loop
+                               if ( target === copy ) {
+                                       continue;
+                               }
+
+                               // Recurse if we're merging plain objects or arrays
+                               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                                       if ( copyIsArray ) {
+                                               copyIsArray = false;
+                                               clone = src && jQuery.isArray(src) ? src : [];
+
+                                       } else {
+                                               clone = src && jQuery.isPlainObject(src) ? src : {};
+                                       }
+
+                                       // Never move original objects, clone them
+                                       target[ name ] = jQuery.extend( deep, clone, copy );
+
+                               // Don't bring in undefined values
+                               } else if ( copy !== undefined ) {
+                                       target[ name ] = copy;
+                               }
+                       }
+               }
+       }
+
+       // Return the modified object
+       return target;
+};
+
+jQuery.extend({
+       // Unique for each copy of jQuery on the page
+       expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+       // Assume jQuery is ready without the ready module
+       isReady: true,
+
+       error: function( msg ) {
+               throw new Error( msg );
+       },
+
+       noop: function() {},
+
+       // See test/unit/core.js for details concerning isFunction.
+       // Since version 1.3, DOM methods and functions like alert
+       // aren't supported. They return false on IE (#2968).
+       isFunction: function( obj ) {
+               return jQuery.type(obj) === "function";
+       },
+
+       isArray: Array.isArray || function( obj ) {
+               return jQuery.type(obj) === "array";
+       },
+
+       isWindow: function( obj ) {
+               /* jshint eqeqeq: false */
+               return obj != null && obj == obj.window;
+       },
+
+       isNumeric: function( obj ) {
+               // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+               // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+               // subtraction forces infinities to NaN
+               return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
+       },
+
+       isEmptyObject: function( obj ) {
+               var name;
+               for ( name in obj ) {
+                       return false;
+               }
+               return true;
+       },
+
+       isPlainObject: function( obj ) {
+               var key;
+
+               // Must be an Object.
+               // Because of IE, we also have to check the presence of the constructor property.
+               // Make sure that DOM nodes and window objects don't pass through, as well
+               if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+                       return false;
+               }
+
+               try {
+                       // Not own constructor property must be Object
+                       if ( obj.constructor &&
+                               !hasOwn.call(obj, "constructor") &&
+                               !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+                               return false;
+                       }
+               } catch ( e ) {
+                       // IE8,9 Will throw exceptions on certain host objects #9897
+                       return false;
+               }
+
+               // Support: IE<9
+               // Handle iteration over inherited properties before own properties.
+               if ( support.ownLast ) {
+                       for ( key in obj ) {
+                               return hasOwn.call( obj, key );
+                       }
+               }
+
+               // Own properties are enumerated firstly, so to speed up,
+               // if last one is own, then all properties are own.
+               for ( key in obj ) {}
+
+               return key === undefined || hasOwn.call( obj, key );
+       },
+
+       type: function( obj ) {
+               if ( obj == null ) {
+                       return obj + "";
+               }
+               return typeof obj === "object" || typeof obj === "function" ?
+                       class2type[ toString.call(obj) ] || "object" :
+                       typeof obj;
+       },
+
+       // Evaluates a script in a global context
+       // Workarounds based on findings by Jim Driscoll
+       // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+       globalEval: function( data ) {
+               if ( data && jQuery.trim( data ) ) {
+                       // We use execScript on Internet Explorer
+                       // We use an anonymous function so that context is window
+                       // rather than jQuery in Firefox
+                       ( window.execScript || function( data ) {
+                               window[ "eval" ].call( window, data );
+                       } )( data );
+               }
+       },
+
+       // Convert dashed to camelCase; used by the css and data modules
+       // Microsoft forgot to hump their vendor prefix (#9572)
+       camelCase: function( string ) {
+               return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+       },
+
+       nodeName: function( elem, name ) {
+               return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+       },
+
+       // args is for internal usage only
+       each: function( obj, callback, args ) {
+               var value,
+                       i = 0,
+                       length = obj.length,
+                       isArray = isArraylike( obj );
+
+               if ( args ) {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.apply( obj[ i ], args );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.apply( obj[ i ], args );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+
+               // A special, fast, case for the most common use of each
+               } else {
+                       if ( isArray ) {
+                               for ( ; i < length; i++ ) {
+                                       value = callback.call( obj[ i ], i, obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( i in obj ) {
+                                       value = callback.call( obj[ i ], i, obj[ i ] );
+
+                                       if ( value === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return obj;
+       },
+
+       // Support: Android<4.1, IE<9
+       trim: function( text ) {
+               return text == null ?
+                       "" :
+                       ( text + "" ).replace( rtrim, "" );
+       },
+
+       // results is for internal usage only
+       makeArray: function( arr, results ) {
+               var ret = results || [];
+
+               if ( arr != null ) {
+                       if ( isArraylike( Object(arr) ) ) {
+                               jQuery.merge( ret,
+                                       typeof arr === "string" ?
+                                       [ arr ] : arr
+                               );
+                       } else {
+                               push.call( ret, arr );
+                       }
+               }
+
+               return ret;
+       },
+
+       inArray: function( elem, arr, i ) {
+               var len;
+
+               if ( arr ) {
+                       if ( indexOf ) {
+                               return indexOf.call( arr, elem, i );
+                       }
+
+                       len = arr.length;
+                       i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+                       for ( ; i < len; i++ ) {
+                               // Skip accessing in sparse arrays
+                               if ( i in arr && arr[ i ] === elem ) {
+                                       return i;
+                               }
+                       }
+               }
+
+               return -1;
+       },
+
+       merge: function( first, second ) {
+               var len = +second.length,
+                       j = 0,
+                       i = first.length;
+
+               while ( j < len ) {
+                       first[ i++ ] = second[ j++ ];
+               }
+
+               // Support: IE<9
+               // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+               if ( len !== len ) {
+                       while ( second[j] !== undefined ) {
+                               first[ i++ ] = second[ j++ ];
+                       }
+               }
+
+               first.length = i;
+
+               return first;
+       },
+
+       grep: function( elems, callback, invert ) {
+               var callbackInverse,
+                       matches = [],
+                       i = 0,
+                       length = elems.length,
+                       callbackExpect = !invert;
+
+               // Go through the array, only saving the items
+               // that pass the validator function
+               for ( ; i < length; i++ ) {
+                       callbackInverse = !callback( elems[ i ], i );
+                       if ( callbackInverse !== callbackExpect ) {
+                               matches.push( elems[ i ] );
+                       }
+               }
+
+               return matches;
+       },
+
+       // arg is for internal usage only
+       map: function( elems, callback, arg ) {
+               var value,
+                       i = 0,
+                       length = elems.length,
+                       isArray = isArraylike( elems ),
+                       ret = [];
+
+               // Go through the array, translating each of the items to their new values
+               if ( isArray ) {
+                       for ( ; i < length; i++ ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+
+               // Go through every key on the object,
+               } else {
+                       for ( i in elems ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+               }
+
+               // Flatten any nested arrays
+               return concat.apply( [], ret );
+       },
+
+       // A global GUID counter for objects
+       guid: 1,
+
+       // Bind a function to a context, optionally partially applying any
+       // arguments.
+       proxy: function( fn, context ) {
+               var args, proxy, tmp;
+
+               if ( typeof context === "string" ) {
+                       tmp = fn[ context ];
+                       context = fn;
+                       fn = tmp;
+               }
+
+               // Quick check to determine if target is callable, in the spec
+               // this throws a TypeError, but we will just return undefined.
+               if ( !jQuery.isFunction( fn ) ) {
+                       return undefined;
+               }
+
+               // Simulated bind
+               args = slice.call( arguments, 2 );
+               proxy = function() {
+                       return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+               };
+
+               // Set the guid of unique handler to the same of original handler, so it can be removed
+               proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+               return proxy;
+       },
+
+       now: function() {
+               return +( new Date() );
+       },
+
+       // jQuery.support is not used in Core but other projects attach their
+       // properties to it so it needs to exist.
+       support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+       var length = obj.length,
+               type = jQuery.type( obj );
+
+       if ( type === "function" || jQuery.isWindow( obj ) ) {
+               return false;
+       }
+
+       if ( obj.nodeType === 1 && length ) {
+               return true;
+       }
+
+       return type === "array" || length === 0 ||
+               typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v1.10.19
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-04-18
+ */
+(function( window ) {
+
+var i,
+       support,
+       Expr,
+       getText,
+       isXML,
+       tokenize,
+       compile,
+       select,
+       outermostContext,
+       sortInput,
+       hasDuplicate,
+
+       // Local document vars
+       setDocument,
+       document,
+       docElem,
+       documentIsHTML,
+       rbuggyQSA,
+       rbuggyMatches,
+       matches,
+       contains,
+
+       // Instance-specific data
+       expando = "sizzle" + -(new Date()),
+       preferredDoc = window.document,
+       dirruns = 0,
+       done = 0,
+       classCache = createCache(),
+       tokenCache = createCache(),
+       compilerCache = createCache(),
+       sortOrder = function( a, b ) {
+               if ( a === b ) {
+                       hasDuplicate = true;
+               }
+               return 0;
+       },
+
+       // General-purpose constants
+       strundefined = typeof undefined,
+       MAX_NEGATIVE = 1 << 31,
+
+       // Instance methods
+       hasOwn = ({}).hasOwnProperty,
+       arr = [],
+       pop = arr.pop,
+       push_native = arr.push,
+       push = arr.push,
+       slice = arr.slice,
+       // Use a stripped-down indexOf if we can't use a native one
+       indexOf = arr.indexOf || function( elem ) {
+               var i = 0,
+                       len = this.length;
+               for ( ; i < len; i++ ) {
+                       if ( this[i] === elem ) {
+                               return i;
+                       }
+               }
+               return -1;
+       },
+
+       booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+       // Regular expressions
+
+       // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+       whitespace = "[\\x20\\t\\r\\n\\f]",
+       // http://www.w3.org/TR/css3-syntax/#characters
+       characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+       // Loosely modeled on CSS identifier characters
+       // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+       // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+       identifier = characterEncoding.replace( "w", "w#" ),
+
+       // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+       attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+               // Operator (capture 2)
+               "*([*^$|!~]?=)" + whitespace +
+               // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+               "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+               "*\\]",
+
+       pseudos = ":(" + characterEncoding + ")(?:\\((" +
+               // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+               // 1. quoted (capture 3; capture 4 or capture 5)
+               "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+               // 2. simple (capture 6)
+               "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+               // 3. anything else (capture 2)
+               ".*" +
+               ")\\)|)",
+
+       // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+       rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+       rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+       rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+       rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+       rpseudo = new RegExp( pseudos ),
+       ridentifier = new RegExp( "^" + identifier + "$" ),
+
+       matchExpr = {
+               "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+               "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+               "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+               "ATTR": new RegExp( "^" + attributes ),
+               "PSEUDO": new RegExp( "^" + pseudos ),
+               "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+                       "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+                       "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+               "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+               // For use in libraries implementing .is()
+               // We use this for POS matching in `select`
+               "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+                       whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+       },
+
+       rinputs = /^(?:input|select|textarea|button)$/i,
+       rheader = /^h\d$/i,
+
+       rnative = /^[^{]+\{\s*\[native \w/,
+
+       // Easily-parseable/retrievable ID or TAG or CLASS selectors
+       rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+       rsibling = /[+~]/,
+       rescape = /'|\\/g,
+
+       // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+       runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+       funescape = function( _, escaped, escapedWhitespace ) {
+               var high = "0x" + escaped - 0x10000;
+               // NaN means non-codepoint
+               // Support: Firefox<24
+               // Workaround erroneous numeric interpretation of +"0x"
+               return high !== high || escapedWhitespace ?
+                       escaped :
+                       high < 0 ?
+                               // BMP codepoint
+                               String.fromCharCode( high + 0x10000 ) :
+                               // Supplemental Plane codepoint (surrogate pair)
+                               String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+       };
+
+// Optimize for push.apply( _, NodeList )
+try {
+       push.apply(
+               (arr = slice.call( preferredDoc.childNodes )),
+               preferredDoc.childNodes
+       );
+       // Support: Android<4.0
+       // Detect silently failing push.apply
+       arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+       push = { apply: arr.length ?
+
+               // Leverage slice if possible
+               function( target, els ) {
+                       push_native.apply( target, slice.call(els) );
+               } :
+
+               // Support: IE<9
+               // Otherwise append directly
+               function( target, els ) {
+                       var j = target.length,
+                               i = 0;
+                       // Can't trust NodeList.length
+                       while ( (target[j++] = els[i++]) ) {}
+                       target.length = j - 1;
+               }
+       };
+}
+
+function Sizzle( selector, context, results, seed ) {
+       var match, elem, m, nodeType,
+               // QSA vars
+               i, groups, old, nid, newContext, newSelector;
+
+       if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+               setDocument( context );
+       }
+
+       context = context || document;
+       results = results || [];
+
+       if ( !selector || typeof selector !== "string" ) {
+               return results;
+       }
+
+       if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+               return [];
+       }
+
+       if ( documentIsHTML && !seed ) {
+
+               // Shortcuts
+               if ( (match = rquickExpr.exec( selector )) ) {
+                       // Speed-up: Sizzle("#ID")
+                       if ( (m = match[1]) ) {
+                               if ( nodeType === 9 ) {
+                                       elem = context.getElementById( m );
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document (jQuery #6963)
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE, Opera, and Webkit return items
+                                               // by name instead of ID
+                                               if ( elem.id === m ) {
+                                                       results.push( elem );
+                                                       return results;
+                                               }
+                                       } else {
+                                               return results;
+                                       }
+                               } else {
+                                       // Context is not a document
+                                       if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+                                               contains( context, elem ) && elem.id === m ) {
+                                               results.push( elem );
+                                               return results;
+                                       }
+                               }
+
+                       // Speed-up: Sizzle("TAG")
+                       } else if ( match[2] ) {
+                               push.apply( results, context.getElementsByTagName( selector ) );
+                               return results;
+
+                       // Speed-up: Sizzle(".CLASS")
+                       } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+                               push.apply( results, context.getElementsByClassName( m ) );
+                               return results;
+                       }
+               }
+
+               // QSA path
+               if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+                       nid = old = expando;
+                       newContext = context;
+                       newSelector = nodeType === 9 && selector;
+
+                       // qSA works strangely on Element-rooted queries
+                       // We can work around this by specifying an extra ID on the root
+                       // and working up from there (Thanks to Andrew Dupont for the technique)
+                       // IE 8 doesn't work on object elements
+                       if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+                               groups = tokenize( selector );
+
+                               if ( (old = context.getAttribute("id")) ) {
+                                       nid = old.replace( rescape, "\\$&" );
+                               } else {
+                                       context.setAttribute( "id", nid );
+                               }
+                               nid = "[id='" + nid + "'] ";
+
+                               i = groups.length;
+                               while ( i-- ) {
+                                       groups[i] = nid + toSelector( groups[i] );
+                               }
+                               newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+                               newSelector = groups.join(",");
+                       }
+
+                       if ( newSelector ) {
+                               try {
+                                       push.apply( results,
+                                               newContext.querySelectorAll( newSelector )
+                                       );
+                                       return results;
+                               } catch(qsaError) {
+                               } finally {
+                                       if ( !old ) {
+                                               context.removeAttribute("id");
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // All others
+       return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ *     property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *     deleting the oldest entry
+ */
+function createCache() {
+       var keys = [];
+
+       function cache( key, value ) {
+               // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+               if ( keys.push( key + " " ) > Expr.cacheLength ) {
+                       // Only keep the most recent entries
+                       delete cache[ keys.shift() ];
+               }
+               return (cache[ key + " " ] = value);
+       }
+       return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+       fn[ expando ] = true;
+       return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+       var div = document.createElement("div");
+
+       try {
+               return !!fn( div );
+       } catch (e) {
+               return false;
+       } finally {
+               // Remove from its parent by default
+               if ( div.parentNode ) {
+                       div.parentNode.removeChild( div );
+               }
+               // release memory in IE
+               div = null;
+       }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+       var arr = attrs.split("|"),
+               i = attrs.length;
+
+       while ( i-- ) {
+               Expr.attrHandle[ arr[i] ] = handler;
+       }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+       var cur = b && a,
+               diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+                       ( ~b.sourceIndex || MAX_NEGATIVE ) -
+                       ( ~a.sourceIndex || MAX_NEGATIVE );
+
+       // Use IE sourceIndex if available on both nodes
+       if ( diff ) {
+               return diff;
+       }
+
+       // Check if b follows a
+       if ( cur ) {
+               while ( (cur = cur.nextSibling) ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+               }
+       }
+
+       return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return name === "input" && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return (name === "input" || name === "button") && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+       return markFunction(function( argument ) {
+               argument = +argument;
+               return markFunction(function( seed, matches ) {
+                       var j,
+                               matchIndexes = fn( [], seed.length, argument ),
+                               i = matchIndexes.length;
+
+                       // Match elements found at the specified indexes
+                       while ( i-- ) {
+                               if ( seed[ (j = matchIndexes[i]) ] ) {
+                                       seed[j] = !(matches[j] = seed[j]);
+                               }
+                       }
+               });
+       });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+       return context && typeof context.getElementsByTagName !== strundefined && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+       // documentElement is verified for cases where it doesn't yet exist
+       // (such as loading iframes in IE - #4833)
+       var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+       return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+       var hasCompare,
+               doc = node ? node.ownerDocument || node : preferredDoc,
+               parent = doc.defaultView;
+
+       // If no document and documentElement is available, return
+       if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+               return document;
+       }
+
+       // Set our document
+       document = doc;
+       docElem = doc.documentElement;
+
+       // Support tests
+       documentIsHTML = !isXML( doc );
+
+       // Support: IE>8
+       // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+       // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+       // IE6-8 do not support the defaultView property so parent will be undefined
+       if ( parent && parent !== parent.top ) {
+               // IE11 does not have attachEvent, so all must suffer
+               if ( parent.addEventListener ) {
+                       parent.addEventListener( "unload", function() {
+                               setDocument();
+                       }, false );
+               } else if ( parent.attachEvent ) {
+                       parent.attachEvent( "onunload", function() {
+                               setDocument();
+                       });
+               }
+       }
+
+       /* Attributes
+       ---------------------------------------------------------------------- */
+
+       // Support: IE<8
+       // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+       support.attributes = assert(function( div ) {
+               div.className = "i";
+               return !div.getAttribute("className");
+       });
+
+       /* getElement(s)By*
+       ---------------------------------------------------------------------- */
+
+       // Check if getElementsByTagName("*") returns only elements
+       support.getElementsByTagName = assert(function( div ) {
+               div.appendChild( doc.createComment("") );
+               return !div.getElementsByTagName("*").length;
+       });
+
+       // Check if getElementsByClassName can be trusted
+       support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
+               div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+               // Support: Safari<4
+               // Catch class over-caching
+               div.firstChild.className = "i";
+               // Support: Opera<10
+               // Catch gEBCN failure to find non-leading classes
+               return div.getElementsByClassName("i").length === 2;
+       });
+
+       // Support: IE<10
+       // Check if getElementById returns elements by name
+       // The broken getElementById methods don't pick up programatically-set names,
+       // so use a roundabout getElementsByName test
+       support.getById = assert(function( div ) {
+               docElem.appendChild( div ).id = expando;
+               return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+       });
+
+       // ID find and filter
+       if ( support.getById ) {
+               Expr.find["ID"] = function( id, context ) {
+                       if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+                               var m = context.getElementById( id );
+                               // Check parentNode to catch when Blackberry 4.6 returns
+                               // nodes that are no longer in the document #6963
+                               return m && m.parentNode ? [ m ] : [];
+                       }
+               };
+               Expr.filter["ID"] = function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               return elem.getAttribute("id") === attrId;
+                       };
+               };
+       } else {
+               // Support: IE6/7
+               // getElementById is not reliable as a find shortcut
+               delete Expr.find["ID"];
+
+               Expr.filter["ID"] =  function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+                               return node && node.value === attrId;
+                       };
+               };
+       }
+
+       // Tag
+       Expr.find["TAG"] = support.getElementsByTagName ?
+               function( tag, context ) {
+                       if ( typeof context.getElementsByTagName !== strundefined ) {
+                               return context.getElementsByTagName( tag );
+                       }
+               } :
+               function( tag, context ) {
+                       var elem,
+                               tmp = [],
+                               i = 0,
+                               results = context.getElementsByTagName( tag );
+
+                       // Filter out possible comments
+                       if ( tag === "*" ) {
+                               while ( (elem = results[i++]) ) {
+                                       if ( elem.nodeType === 1 ) {
+                                               tmp.push( elem );
+                                       }
+                               }
+
+                               return tmp;
+                       }
+                       return results;
+               };
+
+       // Class
+       Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+               if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+                       return context.getElementsByClassName( className );
+               }
+       };
+
+       /* QSA/matchesSelector
+       ---------------------------------------------------------------------- */
+
+       // QSA and matchesSelector support
+
+       // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+       rbuggyMatches = [];
+
+       // qSa(:focus) reports false when true (Chrome 21)
+       // We allow this because of a bug in IE8/9 that throws an error
+       // whenever `document.activeElement` is accessed on an iframe
+       // So, we allow :focus to pass through QSA all the time to avoid the IE error
+       // See http://bugs.jquery.com/ticket/13378
+       rbuggyQSA = [];
+
+       if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+               // Build QSA regex
+               // Regex strategy adopted from Diego Perini
+               assert(function( div ) {
+                       // Select is set to empty string on purpose
+                       // This is to test IE's treatment of not explicitly
+                       // setting a boolean content attribute,
+                       // since its presence should be enough
+                       // http://bugs.jquery.com/ticket/12359
+                       div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
+
+                       // Support: IE8, Opera 11-12.16
+                       // Nothing should be selected when empty strings follow ^= or $= or *=
+                       // The test attribute must be unknown in Opera but "safe" for WinRT
+                       // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+                       if ( div.querySelectorAll("[msallowclip^='']").length ) {
+                               rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+                       }
+
+                       // Support: IE8
+                       // Boolean attributes and "value" are not treated correctly
+                       if ( !div.querySelectorAll("[selected]").length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+                       }
+
+                       // Webkit/Opera - :checked should return selected option elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       // IE8 throws error here and will not see later tests
+                       if ( !div.querySelectorAll(":checked").length ) {
+                               rbuggyQSA.push(":checked");
+                       }
+               });
+
+               assert(function( div ) {
+                       // Support: Windows 8 Native Apps
+                       // The type and name attributes are restricted during .innerHTML assignment
+                       var input = doc.createElement("input");
+                       input.setAttribute( "type", "hidden" );
+                       div.appendChild( input ).setAttribute( "name", "D" );
+
+                       // Support: IE8
+                       // Enforce case-sensitivity of name attribute
+                       if ( div.querySelectorAll("[name=d]").length ) {
+                               rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+                       }
+
+                       // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+                       // IE8 throws error here and will not see later tests
+                       if ( !div.querySelectorAll(":enabled").length ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
+
+                       // Opera 10-11 does not throw on post-comma invalid pseudos
+                       div.querySelectorAll("*,:x");
+                       rbuggyQSA.push(",.*:");
+               });
+       }
+
+       if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+               docElem.webkitMatchesSelector ||
+               docElem.mozMatchesSelector ||
+               docElem.oMatchesSelector ||
+               docElem.msMatchesSelector) )) ) {
+
+               assert(function( div ) {
+                       // Check to see if it's possible to do matchesSelector
+                       // on a disconnected node (IE 9)
+                       support.disconnectedMatch = matches.call( div, "div" );
+
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( div, "[s!='']:x" );
+                       rbuggyMatches.push( "!=", pseudos );
+               });
+       }
+
+       rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+       rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+       /* Contains
+       ---------------------------------------------------------------------- */
+       hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+       // Element contains another
+       // Purposefully does not implement inclusive descendent
+       // As in, an element does not contain itself
+       contains = hasCompare || rnative.test( docElem.contains ) ?
+               function( a, b ) {
+                       var adown = a.nodeType === 9 ? a.documentElement : a,
+                               bup = b && b.parentNode;
+                       return a === bup || !!( bup && bup.nodeType === 1 && (
+                               adown.contains ?
+                                       adown.contains( bup ) :
+                                       a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+                       ));
+               } :
+               function( a, b ) {
+                       if ( b ) {
+                               while ( (b = b.parentNode) ) {
+                                       if ( b === a ) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               };
+
+       /* Sorting
+       ---------------------------------------------------------------------- */
+
+       // Document order sorting
+       sortOrder = hasCompare ?
+       function( a, b ) {
+
+               // Flag for duplicate removal
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               // Sort on method existence if only one input has compareDocumentPosition
+               var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+               if ( compare ) {
+                       return compare;
+               }
+
+               // Calculate position if both inputs belong to the same document
+               compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+                       a.compareDocumentPosition( b ) :
+
+                       // Otherwise we know they are disconnected
+                       1;
+
+               // Disconnected nodes
+               if ( compare & 1 ||
+                       (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+                       // Choose the first element that is related to our preferred document
+                       if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+                               return -1;
+                       }
+                       if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+                               return 1;
+                       }
+
+                       // Maintain original order
+                       return sortInput ?
+                               ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+                               0;
+               }
+
+               return compare & 4 ? -1 : 1;
+       } :
+       function( a, b ) {
+               // Exit early if the nodes are identical
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               var cur,
+                       i = 0,
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       ap = [ a ],
+                       bp = [ b ];
+
+               // Parentless nodes are either documents or disconnected
+               if ( !aup || !bup ) {
+                       return a === doc ? -1 :
+                               b === doc ? 1 :
+                               aup ? -1 :
+                               bup ? 1 :
+                               sortInput ?
+                               ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+                               0;
+
+               // If the nodes are siblings, we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+               }
+
+               // Otherwise we need full lists of their ancestors for comparison
+               cur = a;
+               while ( (cur = cur.parentNode) ) {
+                       ap.unshift( cur );
+               }
+               cur = b;
+               while ( (cur = cur.parentNode) ) {
+                       bp.unshift( cur );
+               }
+
+               // Walk down the tree looking for a discrepancy
+               while ( ap[i] === bp[i] ) {
+                       i++;
+               }
+
+               return i ?
+                       // Do a sibling check if the nodes have a common ancestor
+                       siblingCheck( ap[i], bp[i] ) :
+
+                       // Otherwise nodes in our document sort first
+                       ap[i] === preferredDoc ? -1 :
+                       bp[i] === preferredDoc ? 1 :
+                       0;
+       };
+
+       return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+       return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       // Make sure that attribute selectors are quoted
+       expr = expr.replace( rattributeQuotes, "='$1']" );
+
+       if ( support.matchesSelector && documentIsHTML &&
+               ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+               ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+               try {
+                       var ret = matches.call( elem, expr );
+
+                       // IE 9's matchesSelector returns false on disconnected nodes
+                       if ( ret || support.disconnectedMatch ||
+                                       // As well, disconnected nodes are said to be in a document
+                                       // fragment in IE 9
+                                       elem.document && elem.document.nodeType !== 11 ) {
+                               return ret;
+                       }
+               } catch(e) {}
+       }
+
+       return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+       // Set document vars if needed
+       if ( ( context.ownerDocument || context ) !== document ) {
+               setDocument( context );
+       }
+       return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+       // Set document vars if needed
+       if ( ( elem.ownerDocument || elem ) !== document ) {
+               setDocument( elem );
+       }
+
+       var fn = Expr.attrHandle[ name.toLowerCase() ],
+               // Don't get fooled by Object.prototype properties (jQuery #13807)
+               val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+                       fn( elem, name, !documentIsHTML ) :
+                       undefined;
+
+       return val !== undefined ?
+               val :
+               support.attributes || !documentIsHTML ?
+                       elem.getAttribute( name ) :
+                       (val = elem.getAttributeNode(name)) && val.specified ?
+                               val.value :
+                               null;
+};
+
+Sizzle.error = function( msg ) {
+       throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+       var elem,
+               duplicates = [],
+               j = 0,
+               i = 0;
+
+       // Unless we *know* we can detect duplicates, assume their presence
+       hasDuplicate = !support.detectDuplicates;
+       sortInput = !support.sortStable && results.slice( 0 );
+       results.sort( sortOrder );
+
+       if ( hasDuplicate ) {
+               while ( (elem = results[i++]) ) {
+                       if ( elem === results[ i ] ) {
+                               j = duplicates.push( i );
+                       }
+               }
+               while ( j-- ) {
+                       results.splice( duplicates[ j ], 1 );
+               }
+       }
+
+       // Clear input after sorting to release objects
+       // See https://github.com/jquery/sizzle/pull/225
+       sortInput = null;
+
+       return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+       var node,
+               ret = "",
+               i = 0,
+               nodeType = elem.nodeType;
+
+       if ( !nodeType ) {
+               // If no nodeType, this is expected to be an array
+               while ( (node = elem[i++]) ) {
+                       // Do not traverse comment nodes
+                       ret += getText( node );
+               }
+       } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+               // Use textContent for elements
+               // innerText usage removed for consistency of new lines (jQuery #11153)
+               if ( typeof elem.textContent === "string" ) {
+                       return elem.textContent;
+               } else {
+                       // Traverse its children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               ret += getText( elem );
+                       }
+               }
+       } else if ( nodeType === 3 || nodeType === 4 ) {
+               return elem.nodeValue;
+       }
+       // Do not include comment or processing instruction nodes
+
+       return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+       // Can be adjusted by the user
+       cacheLength: 50,
+
+       createPseudo: markFunction,
+
+       match: matchExpr,
+
+       attrHandle: {},
+
+       find: {},
+
+       relative: {
+               ">": { dir: "parentNode", first: true },
+               " ": { dir: "parentNode" },
+               "+": { dir: "previousSibling", first: true },
+               "~": { dir: "previousSibling" }
+       },
+
+       preFilter: {
+               "ATTR": function( match ) {
+                       match[1] = match[1].replace( runescape, funescape );
+
+                       // Move the given value to match[3] whether quoted or unquoted
+                       match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+                       if ( match[2] === "~=" ) {
+                               match[3] = " " + match[3] + " ";
+                       }
+
+                       return match.slice( 0, 4 );
+               },
+
+               "CHILD": function( match ) {
+                       /* matches from matchExpr["CHILD"]
+                               1 type (only|nth|...)
+                               2 what (child|of-type)
+                               3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+                               4 xn-component of xn+y argument ([+-]?\d*n|)
+                               5 sign of xn-component
+                               6 x of xn-component
+                               7 sign of y-component
+                               8 y of y-component
+                       */
+                       match[1] = match[1].toLowerCase();
+
+                       if ( match[1].slice( 0, 3 ) === "nth" ) {
+                               // nth-* requires argument
+                               if ( !match[3] ) {
+                                       Sizzle.error( match[0] );
+                               }
+
+                               // numeric x and y parameters for Expr.filter.CHILD
+                               // remember that false/true cast respectively to 0/1
+                               match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+                               match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+                       // other types prohibit arguments
+                       } else if ( match[3] ) {
+                               Sizzle.error( match[0] );
+                       }
+
+                       return match;
+               },
+
+               "PSEUDO": function( match ) {
+                       var excess,
+                               unquoted = !match[6] && match[2];
+
+                       if ( matchExpr["CHILD"].test( match[0] ) ) {
+                               return null;
+                       }
+
+                       // Accept quoted arguments as-is
+                       if ( match[3] ) {
+                               match[2] = match[4] || match[5] || "";
+
+                       // Strip excess characters from unquoted arguments
+                       } else if ( unquoted && rpseudo.test( unquoted ) &&
+                               // Get excess from tokenize (recursively)
+                               (excess = tokenize( unquoted, true )) &&
+                               // advance to the next closing parenthesis
+                               (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+                               // excess is a negative index
+                               match[0] = match[0].slice( 0, excess );
+                               match[2] = unquoted.slice( 0, excess );
+                       }
+
+                       // Return only captures needed by the pseudo filter method (type and argument)
+                       return match.slice( 0, 3 );
+               }
+       },
+
+       filter: {
+
+               "TAG": function( nodeNameSelector ) {
+                       var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+                       return nodeNameSelector === "*" ?
+                               function() { return true; } :
+                               function( elem ) {
+                                       return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+                               };
+               },
+
+               "CLASS": function( className ) {
+                       var pattern = classCache[ className + " " ];
+
+                       return pattern ||
+                               (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+                               classCache( className, function( elem ) {
+                                       return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+                               });
+               },
+
+               "ATTR": function( name, operator, check ) {
+                       return function( elem ) {
+                               var result = Sizzle.attr( elem, name );
+
+                               if ( result == null ) {
+                                       return operator === "!=";
+                               }
+                               if ( !operator ) {
+                                       return true;
+                               }
+
+                               result += "";
+
+                               return operator === "=" ? result === check :
+                                       operator === "!=" ? result !== check :
+                                       operator === "^=" ? check && result.indexOf( check ) === 0 :
+                                       operator === "*=" ? check && result.indexOf( check ) > -1 :
+                                       operator === "$=" ? check && result.slice( -check.length ) === check :
+                                       operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+                                       operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+                                       false;
+                       };
+               },
+
+               "CHILD": function( type, what, argument, first, last ) {
+                       var simple = type.slice( 0, 3 ) !== "nth",
+                               forward = type.slice( -4 ) !== "last",
+                               ofType = what === "of-type";
+
+                       return first === 1 && last === 0 ?
+
+                               // Shortcut for :nth-*(n)
+                               function( elem ) {
+                                       return !!elem.parentNode;
+                               } :
+
+                               function( elem, context, xml ) {
+                                       var cache, outerCache, node, diff, nodeIndex, start,
+                                               dir = simple !== forward ? "nextSibling" : "previousSibling",
+                                               parent = elem.parentNode,
+                                               name = ofType && elem.nodeName.toLowerCase(),
+                                               useCache = !xml && !ofType;
+
+                                       if ( parent ) {
+
+                                               // :(first|last|only)-(child|of-type)
+                                               if ( simple ) {
+                                                       while ( dir ) {
+                                                               node = elem;
+                                                               while ( (node = node[ dir ]) ) {
+                                                                       if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+                                                                               return false;
+                                                                       }
+                                                               }
+                                                               // Reverse direction for :only-* (if we haven't yet done so)
+                                                               start = dir = type === "only" && !start && "nextSibling";
+                                                       }
+                                                       return true;
+                                               }
+
+                                               start = [ forward ? parent.firstChild : parent.lastChild ];
+
+                                               // non-xml :nth-child(...) stores cache data on `parent`
+                                               if ( forward && useCache ) {
+                                                       // Seek `elem` from a previously-cached index
+                                                       outerCache = parent[ expando ] || (parent[ expando ] = {});
+                                                       cache = outerCache[ type ] || [];
+                                                       nodeIndex = cache[0] === dirruns && cache[1];
+                                                       diff = cache[0] === dirruns && cache[2];
+                                                       node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+                                                       while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+                                                               // Fallback to seeking `elem` from the start
+                                                               (diff = nodeIndex = 0) || start.pop()) ) {
+
+                                                               // When found, cache indexes on `parent` and break
+                                                               if ( node.nodeType === 1 && ++diff && node === elem ) {
+                                                                       outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+                                                                       break;
+                                                               }
+                                                       }
+
+                                               // Use previously-cached element index if available
+                                               } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+                                                       diff = cache[1];
+
+                                               // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+                                               } else {
+                                                       // Use the same loop as above to seek `elem` from the start
+                                                       while ( (node = ++nodeIndex && node && node[ dir ] ||
+                                                               (diff = nodeIndex = 0) || start.pop()) ) {
+
+                                                               if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+                                                                       // Cache the index of each encountered element
+                                                                       if ( useCache ) {
+                                                                               (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+                                                                       }
+
+                                                                       if ( node === elem ) {
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+
+                                               // Incorporate the offset, then check against cycle size
+                                               diff -= last;
+                                               return diff === first || ( diff % first === 0 && diff / first >= 0 );
+                                       }
+                               };
+               },
+
+               "PSEUDO": function( pseudo, argument ) {
+                       // pseudo-class names are case-insensitive
+                       // http://www.w3.org/TR/selectors/#pseudo-classes
+                       // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+                       // Remember that setFilters inherits from pseudos
+                       var args,
+                               fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+                                       Sizzle.error( "unsupported pseudo: " + pseudo );
+
+                       // The user may use createPseudo to indicate that
+                       // arguments are needed to create the filter function
+                       // just as Sizzle does
+                       if ( fn[ expando ] ) {
+                               return fn( argument );
+                       }
+
+                       // But maintain support for old signatures
+                       if ( fn.length > 1 ) {
+                               args = [ pseudo, pseudo, "", argument ];
+                               return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+                                       markFunction(function( seed, matches ) {
+                                               var idx,
+                                                       matched = fn( seed, argument ),
+                                                       i = matched.length;
+                                               while ( i-- ) {
+                                                       idx = indexOf.call( seed, matched[i] );
+                                                       seed[ idx ] = !( matches[ idx ] = matched[i] );
+                                               }
+                                       }) :
+                                       function( elem ) {
+                                               return fn( elem, 0, args );
+                                       };
+                       }
+
+                       return fn;
+               }
+       },
+
+       pseudos: {
+               // Potentially complex pseudos
+               "not": markFunction(function( selector ) {
+                       // Trim the selector passed to compile
+                       // to avoid treating leading and trailing
+                       // spaces as combinators
+                       var input = [],
+                               results = [],
+                               matcher = compile( selector.replace( rtrim, "$1" ) );
+
+                       return matcher[ expando ] ?
+                               markFunction(function( seed, matches, context, xml ) {
+                                       var elem,
+                                               unmatched = matcher( seed, null, xml, [] ),
+                                               i = seed.length;
+
+                                       // Match elements unmatched by `matcher`
+                                       while ( i-- ) {
+                                               if ( (elem = unmatched[i]) ) {
+                                                       seed[i] = !(matches[i] = elem);
+                                               }
+                                       }
+                               }) :
+                               function( elem, context, xml ) {
+                                       input[0] = elem;
+                                       matcher( input, null, xml, results );
+                                       return !results.pop();
+                               };
+               }),
+
+               "has": markFunction(function( selector ) {
+                       return function( elem ) {
+                               return Sizzle( selector, elem ).length > 0;
+                       };
+               }),
+
+               "contains": markFunction(function( text ) {
+                       return function( elem ) {
+                               return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+                       };
+               }),
+
+               // "Whether an element is represented by a :lang() selector
+               // is based solely on the element's language value
+               // being equal to the identifier C,
+               // or beginning with the identifier C immediately followed by "-".
+               // The matching of C against the element's language value is performed case-insensitively.
+               // The identifier C does not have to be a valid language name."
+               // http://www.w3.org/TR/selectors/#lang-pseudo
+               "lang": markFunction( function( lang ) {
+                       // lang value must be a valid identifier
+                       if ( !ridentifier.test(lang || "") ) {
+                               Sizzle.error( "unsupported lang: " + lang );
+                       }
+                       lang = lang.replace( runescape, funescape ).toLowerCase();
+                       return function( elem ) {
+                               var elemLang;
+                               do {
+                                       if ( (elemLang = documentIsHTML ?
+                                               elem.lang :
+                                               elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+                                               elemLang = elemLang.toLowerCase();
+                                               return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+                                       }
+                               } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+                               return false;
+                       };
+               }),
+
+               // Miscellaneous
+               "target": function( elem ) {
+                       var hash = window.location && window.location.hash;
+                       return hash && hash.slice( 1 ) === elem.id;
+               },
+
+               "root": function( elem ) {
+                       return elem === docElem;
+               },
+
+               "focus": function( elem ) {
+                       return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+               },
+
+               // Boolean properties
+               "enabled": function( elem ) {
+                       return elem.disabled === false;
+               },
+
+               "disabled": function( elem ) {
+                       return elem.disabled === true;
+               },
+
+               "checked": function( elem ) {
+                       // In CSS3, :checked should return both checked and selected elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       var nodeName = elem.nodeName.toLowerCase();
+                       return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+               },
+
+               "selected": function( elem ) {
+                       // Accessing this property makes selected-by-default
+                       // options in Safari work properly
+                       if ( elem.parentNode ) {
+                               elem.parentNode.selectedIndex;
+                       }
+
+                       return elem.selected === true;
+               },
+
+               // Contents
+               "empty": function( elem ) {
+                       // http://www.w3.org/TR/selectors/#empty-pseudo
+                       // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+                       //   but not by others (comment: 8; processing instruction: 7; etc.)
+                       // nodeType < 6 works because attributes (2) do not appear as children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               if ( elem.nodeType < 6 ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               },
+
+               "parent": function( elem ) {
+                       return !Expr.pseudos["empty"]( elem );
+               },
+
+               // Element/input types
+               "header": function( elem ) {
+                       return rheader.test( elem.nodeName );
+               },
+
+               "input": function( elem ) {
+                       return rinputs.test( elem.nodeName );
+               },
+
+               "button": function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return name === "input" && elem.type === "button" || name === "button";
+               },
+
+               "text": function( elem ) {
+                       var attr;
+                       return elem.nodeName.toLowerCase() === "input" &&
+                               elem.type === "text" &&
+
+                               // Support: IE<8
+                               // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+                               ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+               },
+
+               // Position-in-collection
+               "first": createPositionalPseudo(function() {
+                       return [ 0 ];
+               }),
+
+               "last": createPositionalPseudo(function( matchIndexes, length ) {
+                       return [ length - 1 ];
+               }),
+
+               "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       return [ argument < 0 ? argument + length : argument ];
+               }),
+
+               "even": createPositionalPseudo(function( matchIndexes, length ) {
+                       var i = 0;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "odd": createPositionalPseudo(function( matchIndexes, length ) {
+                       var i = 1;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; --i >= 0; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               }),
+
+               "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; ++i < length; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               })
+       }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+       Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+       Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+       var matched, match, tokens, type,
+               soFar, groups, preFilters,
+               cached = tokenCache[ selector + " " ];
+
+       if ( cached ) {
+               return parseOnly ? 0 : cached.slice( 0 );
+       }
+
+       soFar = selector;
+       groups = [];
+       preFilters = Expr.preFilter;
+
+       while ( soFar ) {
+
+               // Comma and first run
+               if ( !matched || (match = rcomma.exec( soFar )) ) {
+                       if ( match ) {
+                               // Don't consume trailing commas as valid
+                               soFar = soFar.slice( match[0].length ) || soFar;
+                       }
+                       groups.push( (tokens = []) );
+               }
+
+               matched = false;
+
+               // Combinators
+               if ( (match = rcombinators.exec( soFar )) ) {
+                       matched = match.shift();
+                       tokens.push({
+                               value: matched,
+                               // Cast descendant combinators to space
+                               type: match[0].replace( rtrim, " " )
+                       });
+                       soFar = soFar.slice( matched.length );
+               }
+
+               // Filters
+               for ( type in Expr.filter ) {
+                       if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+                               (match = preFilters[ type ]( match ))) ) {
+                               matched = match.shift();
+                               tokens.push({
+                                       value: matched,
+                                       type: type,
+                                       matches: match
+                               });
+                               soFar = soFar.slice( matched.length );
+                       }
+               }
+
+               if ( !matched ) {
+                       break;
+               }
+       }
+
+       // Return the length of the invalid excess
+       // if we're just parsing
+       // Otherwise, throw an error or return tokens
+       return parseOnly ?
+               soFar.length :
+               soFar ?
+                       Sizzle.error( selector ) :
+                       // Cache the tokens
+                       tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+       var i = 0,
+               len = tokens.length,
+               selector = "";
+       for ( ; i < len; i++ ) {
+               selector += tokens[i].value;
+       }
+       return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+       var dir = combinator.dir,
+               checkNonElements = base && dir === "parentNode",
+               doneName = done++;
+
+       return combinator.first ?
+               // Check against closest ancestor/preceding element
+               function( elem, context, xml ) {
+                       while ( (elem = elem[ dir ]) ) {
+                               if ( elem.nodeType === 1 || checkNonElements ) {
+                                       return matcher( elem, context, xml );
+                               }
+                       }
+               } :
+
+               // Check against all ancestor/preceding elements
+               function( elem, context, xml ) {
+                       var oldCache, outerCache,
+                               newCache = [ dirruns, doneName ];
+
+                       // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+                       if ( xml ) {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               if ( matcher( elem, context, xml ) ) {
+                                                       return true;
+                                               }
+                                       }
+                               }
+                       } else {
+                               while ( (elem = elem[ dir ]) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               outerCache = elem[ expando ] || (elem[ expando ] = {});
+                                               if ( (oldCache = outerCache[ dir ]) &&
+                                                       oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+                                                       // Assign to newCache so results back-propagate to previous elements
+                                                       return (newCache[ 2 ] = oldCache[ 2 ]);
+                                               } else {
+                                                       // Reuse newcache so results back-propagate to previous elements
+                                                       outerCache[ dir ] = newCache;
+
+                                                       // A match means we're done; a fail means we have to keep checking
+                                                       if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+                                                               return true;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               };
+}
+
+function elementMatcher( matchers ) {
+       return matchers.length > 1 ?
+               function( elem, context, xml ) {
+                       var i = matchers.length;
+                       while ( i-- ) {
+                               if ( !matchers[i]( elem, context, xml ) ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               } :
+               matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+       var i = 0,
+               len = contexts.length;
+       for ( ; i < len; i++ ) {
+               Sizzle( selector, contexts[i], results );
+       }
+       return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+       var elem,
+               newUnmatched = [],
+               i = 0,
+               len = unmatched.length,
+               mapped = map != null;
+
+       for ( ; i < len; i++ ) {
+               if ( (elem = unmatched[i]) ) {
+                       if ( !filter || filter( elem, context, xml ) ) {
+                               newUnmatched.push( elem );
+                               if ( mapped ) {
+                                       map.push( i );
+                               }
+                       }
+               }
+       }
+
+       return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+       if ( postFilter && !postFilter[ expando ] ) {
+               postFilter = setMatcher( postFilter );
+       }
+       if ( postFinder && !postFinder[ expando ] ) {
+               postFinder = setMatcher( postFinder, postSelector );
+       }
+       return markFunction(function( seed, results, context, xml ) {
+               var temp, i, elem,
+                       preMap = [],
+                       postMap = [],
+                       preexisting = results.length,
+
+                       // Get initial elements from seed or context
+                       elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+                       // Prefilter to get matcher input, preserving a map for seed-results synchronization
+                       matcherIn = preFilter && ( seed || !selector ) ?
+                               condense( elems, preMap, preFilter, context, xml ) :
+                               elems,
+
+                       matcherOut = matcher ?
+                               // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+                               postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+                                       // ...intermediate processing is necessary
+                                       [] :
+
+                                       // ...otherwise use results directly
+                                       results :
+                               matcherIn;
+
+               // Find primary matches
+               if ( matcher ) {
+                       matcher( matcherIn, matcherOut, context, xml );
+               }
+
+               // Apply postFilter
+               if ( postFilter ) {
+                       temp = condense( matcherOut, postMap );
+                       postFilter( temp, [], context, xml );
+
+                       // Un-match failing elements by moving them back to matcherIn
+                       i = temp.length;
+                       while ( i-- ) {
+                               if ( (elem = temp[i]) ) {
+                                       matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+                               }
+                       }
+               }
+
+               if ( seed ) {
+                       if ( postFinder || preFilter ) {
+                               if ( postFinder ) {
+                                       // Get the final matcherOut by condensing this intermediate into postFinder contexts
+                                       temp = [];
+                                       i = matcherOut.length;
+                                       while ( i-- ) {
+                                               if ( (elem = matcherOut[i]) ) {
+                                                       // Restore matcherIn since elem is not yet a final match
+                                                       temp.push( (matcherIn[i] = elem) );
+                                               }
+                                       }
+                                       postFinder( null, (matcherOut = []), temp, xml );
+                               }
+
+                               // Move matched elements from seed to results to keep them synchronized
+                               i = matcherOut.length;
+                               while ( i-- ) {
+                                       if ( (elem = matcherOut[i]) &&
+                                               (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+                                               seed[temp] = !(results[temp] = elem);
+                                       }
+                               }
+                       }
+
+               // Add elements to results, through postFinder if defined
+               } else {
+                       matcherOut = condense(
+                               matcherOut === results ?
+                                       matcherOut.splice( preexisting, matcherOut.length ) :
+                                       matcherOut
+                       );
+                       if ( postFinder ) {
+                               postFinder( null, results, matcherOut, xml );
+                       } else {
+                               push.apply( results, matcherOut );
+                       }
+               }
+       });
+}
+
+function matcherFromTokens( tokens ) {
+       var checkContext, matcher, j,
+               len = tokens.length,
+               leadingRelative = Expr.relative[ tokens[0].type ],
+               implicitRelative = leadingRelative || Expr.relative[" "],
+               i = leadingRelative ? 1 : 0,
+
+               // The foundational matcher ensures that elements are reachable from top-level context(s)
+               matchContext = addCombinator( function( elem ) {
+                       return elem === checkContext;
+               }, implicitRelative, true ),
+               matchAnyContext = addCombinator( function( elem ) {
+                       return indexOf.call( checkContext, elem ) > -1;
+               }, implicitRelative, true ),
+               matchers = [ function( elem, context, xml ) {
+                       return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+                               (checkContext = context).nodeType ?
+                                       matchContext( elem, context, xml ) :
+                                       matchAnyContext( elem, context, xml ) );
+               } ];
+
+       for ( ; i < len; i++ ) {
+               if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+                       matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+               } else {
+                       matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+                       // Return special upon seeing a positional matcher
+                       if ( matcher[ expando ] ) {
+                               // Find the next relative operator (if any) for proper handling
+                               j = ++i;
+                               for ( ; j < len; j++ ) {
+                                       if ( Expr.relative[ tokens[j].type ] ) {
+                                               break;
+                                       }
+                               }
+                               return setMatcher(
+                                       i > 1 && elementMatcher( matchers ),
+                                       i > 1 && toSelector(
+                                               // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+                                               tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+                                       ).replace( rtrim, "$1" ),
+                                       matcher,
+                                       i < j && matcherFromTokens( tokens.slice( i, j ) ),
+                                       j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+                                       j < len && toSelector( tokens )
+                               );
+                       }
+                       matchers.push( matcher );
+               }
+       }
+
+       return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+       var bySet = setMatchers.length > 0,
+               byElement = elementMatchers.length > 0,
+               superMatcher = function( seed, context, xml, results, outermost ) {
+                       var elem, j, matcher,
+                               matchedCount = 0,
+                               i = "0",
+                               unmatched = seed && [],
+                               setMatched = [],
+                               contextBackup = outermostContext,
+                               // We must always have either seed elements or outermost context
+                               elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+                               // Use integer dirruns iff this is the outermost matcher
+                               dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+                               len = elems.length;
+
+                       if ( outermost ) {
+                               outermostContext = context !== document && context;
+                       }
+
+                       // Add elements passing elementMatchers directly to results
+                       // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+                       // Support: IE<9, Safari
+                       // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+                       for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+                               if ( byElement && elem ) {
+                                       j = 0;
+                                       while ( (matcher = elementMatchers[j++]) ) {
+                                               if ( matcher( elem, context, xml ) ) {
+                                                       results.push( elem );
+                                                       break;
+                                               }
+                                       }
+                                       if ( outermost ) {
+                                               dirruns = dirrunsUnique;
+                                       }
+                               }
+
+                               // Track unmatched elements for set filters
+                               if ( bySet ) {
+                                       // They will have gone through all possible matchers
+                                       if ( (elem = !matcher && elem) ) {
+                                               matchedCount--;
+                                       }
+
+                                       // Lengthen the array for every element, matched or not
+                                       if ( seed ) {
+                                               unmatched.push( elem );
+                                       }
+                               }
+                       }
+
+                       // Apply set filters to unmatched elements
+                       matchedCount += i;
+                       if ( bySet && i !== matchedCount ) {
+                               j = 0;
+                               while ( (matcher = setMatchers[j++]) ) {
+                                       matcher( unmatched, setMatched, context, xml );
+                               }
+
+                               if ( seed ) {
+                                       // Reintegrate element matches to eliminate the need for sorting
+                                       if ( matchedCount > 0 ) {
+                                               while ( i-- ) {
+                                                       if ( !(unmatched[i] || setMatched[i]) ) {
+                                                               setMatched[i] = pop.call( results );
+                                                       }
+                                               }
+                                       }
+
+                                       // Discard index placeholder values to get only actual matches
+                                       setMatched = condense( setMatched );
+                               }
+
+                               // Add matches to results
+                               push.apply( results, setMatched );
+
+                               // Seedless set matches succeeding multiple successful matchers stipulate sorting
+                               if ( outermost && !seed && setMatched.length > 0 &&
+                                       ( matchedCount + setMatchers.length ) > 1 ) {
+
+                                       Sizzle.uniqueSort( results );
+                               }
+                       }
+
+                       // Override manipulation of globals by nested matchers
+                       if ( outermost ) {
+                               dirruns = dirrunsUnique;
+                               outermostContext = contextBackup;
+                       }
+
+                       return unmatched;
+               };
+
+       return bySet ?
+               markFunction( superMatcher ) :
+               superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+       var i,
+               setMatchers = [],
+               elementMatchers = [],
+               cached = compilerCache[ selector + " " ];
+
+       if ( !cached ) {
+               // Generate a function of recursive functions that can be used to check each element
+               if ( !match ) {
+                       match = tokenize( selector );
+               }
+               i = match.length;
+               while ( i-- ) {
+                       cached = matcherFromTokens( match[i] );
+                       if ( cached[ expando ] ) {
+                               setMatchers.push( cached );
+                       } else {
+                               elementMatchers.push( cached );
+                       }
+               }
+
+               // Cache the compiled function
+               cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+               // Save selector and tokenization
+               cached.selector = selector;
+       }
+       return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ *  selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ *  selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+       var i, tokens, token, type, find,
+               compiled = typeof selector === "function" && selector,
+               match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+       results = results || [];
+
+       // Try to minimize operations if there is no seed and only one group
+       if ( match.length === 1 ) {
+
+               // Take a shortcut and set the context if the root selector is an ID
+               tokens = match[0] = match[0].slice( 0 );
+               if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+                               support.getById && context.nodeType === 9 && documentIsHTML &&
+                               Expr.relative[ tokens[1].type ] ) {
+
+                       context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+                       if ( !context ) {
+                               return results;
+
+                       // Precompiled matchers will still verify ancestry, so step up a level
+                       } else if ( compiled ) {
+                               context = context.parentNode;
+                       }
+
+                       selector = selector.slice( tokens.shift().value.length );
+               }
+
+               // Fetch a seed set for right-to-left matching
+               i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+               while ( i-- ) {
+                       token = tokens[i];
+
+                       // Abort if we hit a combinator
+                       if ( Expr.relative[ (type = token.type) ] ) {
+                               break;
+                       }
+                       if ( (find = Expr.find[ type ]) ) {
+                               // Search, expanding context for leading sibling combinators
+                               if ( (seed = find(
+                                       token.matches[0].replace( runescape, funescape ),
+                                       rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+                               )) ) {
+
+                                       // If seed is empty or no tokens remain, we can return early
+                                       tokens.splice( i, 1 );
+                                       selector = seed.length && toSelector( tokens );
+                                       if ( !selector ) {
+                                               push.apply( results, seed );
+                                               return results;
+                                       }
+
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // Compile and execute a filtering function if one is not provided
+       // Provide `match` to avoid retokenization if we modified the selector above
+       ( compiled || compile( selector, match ) )(
+               seed,
+               context,
+               !documentIsHTML,
+               results,
+               rsibling.test( selector ) && testContext( context.parentNode ) || context
+       );
+       return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+       // Should return 1, but returns 4 (following)
+       return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+       div.innerHTML = "<a href='#'></a>";
+       return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+       addHandle( "type|href|height|width", function( elem, name, isXML ) {
+               if ( !isXML ) {
+                       return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+               }
+       });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+       div.innerHTML = "<input/>";
+       div.firstChild.setAttribute( "value", "" );
+       return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+       addHandle( "value", function( elem, name, isXML ) {
+               if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+                       return elem.defaultValue;
+               }
+       });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+       return div.getAttribute("disabled") == null;
+}) ) {
+       addHandle( booleans, function( elem, name, isXML ) {
+               var val;
+               if ( !isXML ) {
+                       return elem[ name ] === true ? name.toLowerCase() :
+                                       (val = elem.getAttributeNode( name )) && val.specified ?
+                                       val.value :
+                               null;
+               }
+       });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+       if ( jQuery.isFunction( qualifier ) ) {
+               return jQuery.grep( elements, function( elem, i ) {
+                       /* jshint -W018 */
+                       return !!qualifier.call( elem, i, elem ) !== not;
+               });
+
+       }
+
+       if ( qualifier.nodeType ) {
+               return jQuery.grep( elements, function( elem ) {
+                       return ( elem === qualifier ) !== not;
+               });
+
+       }
+
+       if ( typeof qualifier === "string" ) {
+               if ( risSimple.test( qualifier ) ) {
+                       return jQuery.filter( qualifier, elements, not );
+               }
+
+               qualifier = jQuery.filter( qualifier, elements );
+       }
+
+       return jQuery.grep( elements, function( elem ) {
+               return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+       });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+       var elem = elems[ 0 ];
+
+       if ( not ) {
+               expr = ":not(" + expr + ")";
+       }
+
+       return elems.length === 1 && elem.nodeType === 1 ?
+               jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+               jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+                       return elem.nodeType === 1;
+               }));
+};
+
+jQuery.fn.extend({
+       find: function( selector ) {
+               var i,
+                       ret = [],
+                       self = this,
+                       len = self.length;
+
+               if ( typeof selector !== "string" ) {
+                       return this.pushStack( jQuery( selector ).filter(function() {
+                               for ( i = 0; i < len; i++ ) {
+                                       if ( jQuery.contains( self[ i ], this ) ) {
+                                               return true;
+                                       }
+                               }
+                       }) );
+               }
+
+               for ( i = 0; i < len; i++ ) {
+                       jQuery.find( selector, self[ i ], ret );
+               }
+
+               // Needed because $( selector, context ) becomes $( context ).find( selector )
+               ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+               ret.selector = this.selector ? this.selector + " " + selector : selector;
+               return ret;
+       },
+       filter: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], false) );
+       },
+       not: function( selector ) {
+               return this.pushStack( winnow(this, selector || [], true) );
+       },
+       is: function( selector ) {
+               return !!winnow(
+                       this,
+
+                       // If this is a positional/relative selector, check membership in the returned set
+                       // so $("p:first").is("p:last") won't return true for a doc with two "p".
+                       typeof selector === "string" && rneedsContext.test( selector ) ?
+                               jQuery( selector ) :
+                               selector || [],
+                       false
+               ).length;
+       }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+       // Use the correct document accordingly with window argument (sandbox)
+       document = window.document,
+
+       // A simple way to check for HTML strings
+       // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+       // Strict HTML recognition (#11290: must start with <)
+       rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+       init = jQuery.fn.init = function( selector, context ) {
+               var match, elem;
+
+               // HANDLE: $(""), $(null), $(undefined), $(false)
+               if ( !selector ) {
+                       return this;
+               }
+
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+                               // Assume that strings that start and end with <> are HTML and skip the regex check
+                               match = [ null, selector, null ];
+
+                       } else {
+                               match = rquickExpr.exec( selector );
+                       }
+
+                       // Match html or make sure no context is specified for #id
+                       if ( match && (match[1] || !context) ) {
+
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[1] ) {
+                                       context = context instanceof jQuery ? context[0] : context;
+
+                                       // scripts is true for back-compat
+                                       // Intentionally let the error be thrown if parseHTML is not present
+                                       jQuery.merge( this, jQuery.parseHTML(
+                                               match[1],
+                                               context && context.nodeType ? context.ownerDocument || context : document,
+                                               true
+                                       ) );
+
+                                       // HANDLE: $(html, props)
+                                       if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+                                               for ( match in context ) {
+                                                       // Properties of context are called as methods if possible
+                                                       if ( jQuery.isFunction( this[ match ] ) ) {
+                                                               this[ match ]( context[ match ] );
+
+                                                       // ...and otherwise set as attributes
+                                                       } else {
+                                                               this.attr( match, context[ match ] );
+                                                       }
+                                               }
+                                       }
+
+                                       return this;
+
+                               // HANDLE: $(#id)
+                               } else {
+                                       elem = document.getElementById( match[2] );
+
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document #6963
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE and Opera return items
+                                               // by name instead of ID
+                                               if ( elem.id !== match[2] ) {
+                                                       return rootjQuery.find( selector );
+                                               }
+
+                                               // Otherwise, we inject the element directly into the jQuery object
+                                               this.length = 1;
+                                               this[0] = elem;
+                                       }
+
+                                       this.context = document;
+                                       this.selector = selector;
+                                       return this;
+                               }
+
+                       // HANDLE: $(expr, $(...))
+                       } else if ( !context || context.jquery ) {
+                               return ( context || rootjQuery ).find( selector );
+
+                       // HANDLE: $(expr, context)
+                       // (which is just equivalent to: $(context).find(expr)
+                       } else {
+                               return this.constructor( context ).find( selector );
+                       }
+
+               // HANDLE: $(DOMElement)
+               } else if ( selector.nodeType ) {
+                       this.context = this[0] = selector;
+                       this.length = 1;
+                       return this;
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction( selector ) ) {
+                       return typeof rootjQuery.ready !== "undefined" ?
+                               rootjQuery.ready( selector ) :
+                               // Execute immediately if ready is not present
+                               selector( jQuery );
+               }
+
+               if ( selector.selector !== undefined ) {
+                       this.selector = selector.selector;
+                       this.context = selector.context;
+               }
+
+               return jQuery.makeArray( selector, this );
+       };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+       // methods guaranteed to produce a unique set when starting from a unique set
+       guaranteedUnique = {
+               children: true,
+               contents: true,
+               next: true,
+               prev: true
+       };
+
+jQuery.extend({
+       dir: function( elem, dir, until ) {
+               var matched = [],
+                       cur = elem[ dir ];
+
+               while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+                       if ( cur.nodeType === 1 ) {
+                               matched.push( cur );
+                       }
+                       cur = cur[dir];
+               }
+               return matched;
+       },
+
+       sibling: function( n, elem ) {
+               var r = [];
+
+               for ( ; n; n = n.nextSibling ) {
+                       if ( n.nodeType === 1 && n !== elem ) {
+                               r.push( n );
+                       }
+               }
+
+               return r;
+       }
+});
+
+jQuery.fn.extend({
+       has: function( target ) {
+               var i,
+                       targets = jQuery( target, this ),
+                       len = targets.length;
+
+               return this.filter(function() {
+                       for ( i = 0; i < len; i++ ) {
+                               if ( jQuery.contains( this, targets[i] ) ) {
+                                       return true;
+                               }
+                       }
+               });
+       },
+
+       closest: function( selectors, context ) {
+               var cur,
+                       i = 0,
+                       l = this.length,
+                       matched = [],
+                       pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+                               jQuery( selectors, context || this.context ) :
+                               0;
+
+               for ( ; i < l; i++ ) {
+                       for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+                               // Always skip document fragments
+                               if ( cur.nodeType < 11 && (pos ?
+                                       pos.index(cur) > -1 :
+
+                                       // Don't pass non-elements to Sizzle
+                                       cur.nodeType === 1 &&
+                                               jQuery.find.matchesSelector(cur, selectors)) ) {
+
+                                       matched.push( cur );
+                                       break;
+                               }
+                       }
+               }
+
+               return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+       },
+
+       // Determine the position of an element within
+       // the matched set of elements
+       index: function( elem ) {
+
+               // No argument, return index in parent
+               if ( !elem ) {
+                       return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+               }
+
+               // index in selector
+               if ( typeof elem === "string" ) {
+                       return jQuery.inArray( this[0], jQuery( elem ) );
+               }
+
+               // Locate the position of the desired element
+               return jQuery.inArray(
+                       // If it receives a jQuery object, the first element is used
+                       elem.jquery ? elem[0] : elem, this );
+       },
+
+       add: function( selector, context ) {
+               return this.pushStack(
+                       jQuery.unique(
+                               jQuery.merge( this.get(), jQuery( selector, context ) )
+                       )
+               );
+       },
+
+       addBack: function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter(selector)
+               );
+       }
+});
+
+function sibling( cur, dir ) {
+       do {
+               cur = cur[ dir ];
+       } while ( cur && cur.nodeType !== 1 );
+
+       return cur;
+}
+
+jQuery.each({
+       parent: function( elem ) {
+               var parent = elem.parentNode;
+               return parent && parent.nodeType !== 11 ? parent : null;
+       },
+       parents: function( elem ) {
+               return jQuery.dir( elem, "parentNode" );
+       },
+       parentsUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "parentNode", until );
+       },
+       next: function( elem ) {
+               return sibling( elem, "nextSibling" );
+       },
+       prev: function( elem ) {
+               return sibling( elem, "previousSibling" );
+       },
+       nextAll: function( elem ) {
+               return jQuery.dir( elem, "nextSibling" );
+       },
+       prevAll: function( elem ) {
+               return jQuery.dir( elem, "previousSibling" );
+       },
+       nextUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "nextSibling", until );
+       },
+       prevUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "previousSibling", until );
+       },
+       siblings: function( elem ) {
+               return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+       },
+       children: function( elem ) {
+               return jQuery.sibling( elem.firstChild );
+       },
+       contents: function( elem ) {
+               return jQuery.nodeName( elem, "iframe" ) ?
+                       elem.contentDocument || elem.contentWindow.document :
+                       jQuery.merge( [], elem.childNodes );
+       }
+}, function( name, fn ) {
+       jQuery.fn[ name ] = function( until, selector ) {
+               var ret = jQuery.map( this, fn, until );
+
+               if ( name.slice( -5 ) !== "Until" ) {
+                       selector = until;
+               }
+
+               if ( selector && typeof selector === "string" ) {
+                       ret = jQuery.filter( selector, ret );
+               }
+
+               if ( this.length > 1 ) {
+                       // Remove duplicates
+                       if ( !guaranteedUnique[ name ] ) {
+                               ret = jQuery.unique( ret );
+                       }
+
+                       // Reverse order for parents* and prev-derivatives
+                       if ( rparentsprev.test( name ) ) {
+                               ret = ret.reverse();
+                       }
+               }
+
+               return this.pushStack( ret );
+       };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+       var object = optionsCache[ options ] = {};
+       jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+               object[ flag ] = true;
+       });
+       return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *     options: an optional list of space-separated options that will change how
+ *                     the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *     once:                   will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *     memory:                 will keep track of previous values and will call any callback added
+ *                                     after the list has been fired right away with the latest "memorized"
+ *                                     values (like a Deferred)
+ *
+ *     unique:                 will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *     stopOnFalse:    interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+       // Convert options from String-formatted to Object-formatted if needed
+       // (we check in cache first)
+       options = typeof options === "string" ?
+               ( optionsCache[ options ] || createOptions( options ) ) :
+               jQuery.extend( {}, options );
+
+       var // Flag to know if list is currently firing
+               firing,
+               // Last fire value (for non-forgettable lists)
+               memory,
+               // Flag to know if list was already fired
+               fired,
+               // End of the loop when firing
+               firingLength,
+               // Index of currently firing callback (modified by remove if needed)
+               firingIndex,
+               // First callback to fire (used internally by add and fireWith)
+               firingStart,
+               // Actual callback list
+               list = [],
+               // Stack of fire calls for repeatable lists
+               stack = !options.once && [],
+               // Fire callbacks
+               fire = function( data ) {
+                       memory = options.memory && data;
+                       fired = true;
+                       firingIndex = firingStart || 0;
+                       firingStart = 0;
+                       firingLength = list.length;
+                       firing = true;
+                       for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+                               if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+                                       memory = false; // To prevent further calls using add
+                                       break;
+                               }
+                       }
+                       firing = false;
+                       if ( list ) {
+                               if ( stack ) {
+                                       if ( stack.length ) {
+                                               fire( stack.shift() );
+                                       }
+                               } else if ( memory ) {
+                                       list = [];
+                               } else {
+                                       self.disable();
+                               }
+                       }
+               },
+               // Actual Callbacks object
+               self = {
+                       // Add a callback or a collection of callbacks to the list
+                       add: function() {
+                               if ( list ) {
+                                       // First, we save the current length
+                                       var start = list.length;
+                                       (function add( args ) {
+                                               jQuery.each( args, function( _, arg ) {
+                                                       var type = jQuery.type( arg );
+                                                       if ( type === "function" ) {
+                                                               if ( !options.unique || !self.has( arg ) ) {
+                                                                       list.push( arg );
+                                                               }
+                                                       } else if ( arg && arg.length && type !== "string" ) {
+                                                               // Inspect recursively
+                                                               add( arg );
+                                                       }
+                                               });
+                                       })( arguments );
+                                       // Do we need to add the callbacks to the
+                                       // current firing batch?
+                                       if ( firing ) {
+                                               firingLength = list.length;
+                                       // With memory, if we're not firing then
+                                       // we should call right away
+                                       } else if ( memory ) {
+                                               firingStart = start;
+                                               fire( memory );
+                                       }
+                               }
+                               return this;
+                       },
+                       // Remove a callback from the list
+                       remove: function() {
+                               if ( list ) {
+                                       jQuery.each( arguments, function( _, arg ) {
+                                               var index;
+                                               while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+                                                       list.splice( index, 1 );
+                                                       // Handle firing indexes
+                                                       if ( firing ) {
+                                                               if ( index <= firingLength ) {
+                                                                       firingLength--;
+                                                               }
+                                                               if ( index <= firingIndex ) {
+                                                                       firingIndex--;
+                                                               }
+                                                       }
+                                               }
+                                       });
+                               }
+                               return this;
+                       },
+                       // Check if a given callback is in the list.
+                       // If no argument is given, return whether or not list has callbacks attached.
+                       has: function( fn ) {
+                               return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+                       },
+                       // Remove all callbacks from the list
+                       empty: function() {
+                               list = [];
+                               firingLength = 0;
+                               return this;
+                       },
+                       // Have the list do nothing anymore
+                       disable: function() {
+                               list = stack = memory = undefined;
+                               return this;
+                       },
+                       // Is it disabled?
+                       disabled: function() {
+                               return !list;
+                       },
+                       // Lock the list in its current state
+                       lock: function() {
+                               stack = undefined;
+                               if ( !memory ) {
+                                       self.disable();
+                               }
+                               return this;
+                       },
+                       // Is it locked?
+                       locked: function() {
+                               return !stack;
+                       },
+                       // Call all callbacks with the given context and arguments
+                       fireWith: function( context, args ) {
+                               if ( list && ( !fired || stack ) ) {
+                                       args = args || [];
+                                       args = [ context, args.slice ? args.slice() : args ];
+                                       if ( firing ) {
+                                               stack.push( args );
+                                       } else {
+                                               fire( args );
+                                       }
+                               }
+                               return this;
+                       },
+                       // Call all the callbacks with the given arguments
+                       fire: function() {
+                               self.fireWith( this, arguments );
+                               return this;
+                       },
+                       // To know if the callbacks have already been called at least once
+                       fired: function() {
+                               return !!fired;
+                       }
+               };
+
+       return self;
+};
+
+
+jQuery.extend({
+
+       Deferred: function( func ) {
+               var tuples = [
+                               // action, add listener, listener list, final state
+                               [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+                               [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+                               [ "notify", "progress", jQuery.Callbacks("memory") ]
+                       ],
+                       state = "pending",
+                       promise = {
+                               state: function() {
+                                       return state;
+                               },
+                               always: function() {
+                                       deferred.done( arguments ).fail( arguments );
+                                       return this;
+                               },
+                               then: function( /* fnDone, fnFail, fnProgress */ ) {
+                                       var fns = arguments;
+                                       return jQuery.Deferred(function( newDefer ) {
+                                               jQuery.each( tuples, function( i, tuple ) {
+                                                       var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+                                                       // deferred[ done | fail | progress ] for forwarding actions to newDefer
+                                                       deferred[ tuple[1] ](function() {
+                                                               var returned = fn && fn.apply( this, arguments );
+                                                               if ( returned && jQuery.isFunction( returned.promise ) ) {
+                                                                       returned.promise()
+                                                                               .done( newDefer.resolve )
+                                                                               .fail( newDefer.reject )
+                                                                               .progress( newDefer.notify );
+                                                               } else {
+                                                                       newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+                                                               }
+                                                       });
+                                               });
+                                               fns = null;
+                                       }).promise();
+                               },
+                               // Get a promise for this deferred
+                               // If obj is provided, the promise aspect is added to the object
+                               promise: function( obj ) {
+                                       return obj != null ? jQuery.extend( obj, promise ) : promise;
+                               }
+                       },
+                       deferred = {};
+
+               // Keep pipe for back-compat
+               promise.pipe = promise.then;
+
+               // Add list-specific methods
+               jQuery.each( tuples, function( i, tuple ) {
+                       var list = tuple[ 2 ],
+                               stateString = tuple[ 3 ];
+
+                       // promise[ done | fail | progress ] = list.add
+                       promise[ tuple[1] ] = list.add;
+
+                       // Handle state
+                       if ( stateString ) {
+                               list.add(function() {
+                                       // state = [ resolved | rejected ]
+                                       state = stateString;
+
+                               // [ reject_list | resolve_list ].disable; progress_list.lock
+                               }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+                       }
+
+                       // deferred[ resolve | reject | notify ]
+                       deferred[ tuple[0] ] = function() {
+                               deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+                               return this;
+                       };
+                       deferred[ tuple[0] + "With" ] = list.fireWith;
+               });
+
+               // Make the deferred a promise
+               promise.promise( deferred );
+
+               // Call given func if any
+               if ( func ) {
+                       func.call( deferred, deferred );
+               }
+
+               // All done!
+               return deferred;
+       },
+
+       // Deferred helper
+       when: function( subordinate /* , ..., subordinateN */ ) {
+               var i = 0,
+                       resolveValues = slice.call( arguments ),
+                       length = resolveValues.length,
+
+                       // the count of uncompleted subordinates
+                       remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+                       // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+                       deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+                       // Update function for both resolve and progress values
+                       updateFunc = function( i, contexts, values ) {
+                               return function( value ) {
+                                       contexts[ i ] = this;
+                                       values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+                                       if ( values === progressValues ) {
+                                               deferred.notifyWith( contexts, values );
+
+                                       } else if ( !(--remaining) ) {
+                                               deferred.resolveWith( contexts, values );
+                                       }
+                               };
+                       },
+
+                       progressValues, progressContexts, resolveContexts;
+
+               // add listeners to Deferred subordinates; treat others as resolved
+               if ( length > 1 ) {
+                       progressValues = new Array( length );
+                       progressContexts = new Array( length );
+                       resolveContexts = new Array( length );
+                       for ( ; i < length; i++ ) {
+                               if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+                                       resolveValues[ i ].promise()
+                                               .done( updateFunc( i, resolveContexts, resolveValues ) )
+                                               .fail( deferred.reject )
+                                               .progress( updateFunc( i, progressContexts, progressValues ) );
+                               } else {
+                                       --remaining;
+                               }
+                       }
+               }
+
+               // if we're not waiting on anything, resolve the master
+               if ( !remaining ) {
+                       deferred.resolveWith( resolveContexts, resolveValues );
+               }
+
+               return deferred.promise();
+       }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+       // Add the callback
+       jQuery.ready.promise().done( fn );
+
+       return this;
+};
+
+jQuery.extend({
+       // Is the DOM ready to be used? Set to true once it occurs.
+       isReady: false,
+
+       // A counter to track how many items to wait for before
+       // the ready event fires. See #6781
+       readyWait: 1,
+
+       // Hold (or release) the ready event
+       holdReady: function( hold ) {
+               if ( hold ) {
+                       jQuery.readyWait++;
+               } else {
+                       jQuery.ready( true );
+               }
+       },
+
+       // Handle when the DOM is ready
+       ready: function( wait ) {
+
+               // Abort if there are pending holds or we're already ready
+               if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+                       return;
+               }
+
+               // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+               if ( !document.body ) {
+                       return setTimeout( jQuery.ready );
+               }
+
+               // Remember that the DOM is ready
+               jQuery.isReady = true;
+
+               // If a normal DOM Ready event fired, decrement, and wait if need be
+               if ( wait !== true && --jQuery.readyWait > 0 ) {
+                       return;
+               }
+
+               // If there are functions bound, to execute
+               readyList.resolveWith( document, [ jQuery ] );
+
+               // Trigger any bound ready events
+               if ( jQuery.fn.triggerHandler ) {
+                       jQuery( document ).triggerHandler( "ready" );
+                       jQuery( document ).off( "ready" );
+               }
+       }
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+       if ( document.addEventListener ) {
+               document.removeEventListener( "DOMContentLoaded", completed, false );
+               window.removeEventListener( "load", completed, false );
+
+       } else {
+               document.detachEvent( "onreadystatechange", completed );
+               window.detachEvent( "onload", completed );
+       }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+       // readyState === "complete" is good enough for us to call the dom ready in oldIE
+       if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+               detach();
+               jQuery.ready();
+       }
+}
+
+jQuery.ready.promise = function( obj ) {
+       if ( !readyList ) {
+
+               readyList = jQuery.Deferred();
+
+               // Catch cases where $(document).ready() is called after the browser event has already occurred.
+               // we once tried to use readyState "interactive" here, but it caused issues like the one
+               // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+               if ( document.readyState === "complete" ) {
+                       // Handle it asynchronously to allow scripts the opportunity to delay ready
+                       setTimeout( jQuery.ready );
+
+               // Standards-based browsers support DOMContentLoaded
+               } else if ( document.addEventListener ) {
+                       // Use the handy event callback
+                       document.addEventListener( "DOMContentLoaded", completed, false );
+
+                       // A fallback to window.onload, that will always work
+                       window.addEventListener( "load", completed, false );
+
+               // If IE event model is used
+               } else {
+                       // Ensure firing before onload, maybe late but safe also for iframes
+                       document.attachEvent( "onreadystatechange", completed );
+
+                       // A fallback to window.onload, that will always work
+                       window.attachEvent( "onload", completed );
+
+                       // If IE and not a frame
+                       // continually check to see if the document is ready
+                       var top = false;
+
+                       try {
+                               top = window.frameElement == null && document.documentElement;
+                       } catch(e) {}
+
+                       if ( top && top.doScroll ) {
+                               (function doScrollCheck() {
+                                       if ( !jQuery.isReady ) {
+
+                                               try {
+                                                       // Use the trick by Diego Perini
+                                                       // http://javascript.nwbox.com/IEContentLoaded/
+                                                       top.doScroll("left");
+                                               } catch(e) {
+                                                       return setTimeout( doScrollCheck, 50 );
+                                               }
+
+                                               // detach all dom ready events
+                                               detach();
+
+                                               // and execute any waiting functions
+                                               jQuery.ready();
+                                       }
+                               })();
+                       }
+               }
+       }
+       return readyList.promise( obj );
+};
+
+
+var strundefined = typeof undefined;
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+       break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery(function() {
+       // Minified: var a,b,c,d
+       var val, div, body, container;
+
+       body = document.getElementsByTagName( "body" )[ 0 ];
+       if ( !body || !body.style ) {
+               // Return for frameset docs that don't have a body
+               return;
+       }
+
+       // Setup
+       div = document.createElement( "div" );
+       container = document.createElement( "div" );
+       container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+       body.appendChild( container ).appendChild( div );
+
+       if ( typeof div.style.zoom !== strundefined ) {
+               // Support: IE<8
+               // Check if natively block-level elements act like inline-block
+               // elements when setting their display to 'inline' and giving
+               // them layout
+               div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+               support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+               if ( val ) {
+                       // Prevent IE 6 from affecting layout for positioned elements #11048
+                       // Prevent IE from shrinking the body in IE 7 mode #12869
+                       // Support: IE<8
+                       body.style.zoom = 1;
+               }
+       }
+
+       body.removeChild( container );
+});
+
+
+
+
+(function() {
+       var div = document.createElement( "div" );
+
+       // Execute the test only if not already executed in another module.
+       if (support.deleteExpando == null) {
+               // Support: IE<9
+               support.deleteExpando = true;
+               try {
+                       delete div.test;
+               } catch( e ) {
+                       support.deleteExpando = false;
+               }
+       }
+
+       // Null elements to avoid leaks in IE.
+       div = null;
+})();
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+       var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+               nodeType = +elem.nodeType || 1;
+
+       // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+       return nodeType !== 1 && nodeType !== 9 ?
+               false :
+
+               // Nodes accept data unless otherwise specified; rejection can be conditional
+               !noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+       rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+       // If nothing was found internally, try to fetch any
+       // data from the HTML5 data-* attribute
+       if ( data === undefined && elem.nodeType === 1 ) {
+
+               var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+               data = elem.getAttribute( name );
+
+               if ( typeof data === "string" ) {
+                       try {
+                               data = data === "true" ? true :
+                                       data === "false" ? false :
+                                       data === "null" ? null :
+                                       // Only convert to a number if it doesn't change the string
+                                       +data + "" === data ? +data :
+                                       rbrace.test( data ) ? jQuery.parseJSON( data ) :
+                                       data;
+                       } catch( e ) {}
+
+                       // Make sure we set the data so it isn't changed later
+                       jQuery.data( elem, key, data );
+
+               } else {
+                       data = undefined;
+               }
+       }
+
+       return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+       var name;
+       for ( name in obj ) {
+
+               // if the public data object is empty, the private is still empty
+               if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+                       continue;
+               }
+               if ( name !== "toJSON" ) {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+       if ( !jQuery.acceptData( elem ) ) {
+               return;
+       }
+
+       var ret, thisCache,
+               internalKey = jQuery.expando,
+
+               // We have to handle DOM nodes and JS objects differently because IE6-7
+               // can't GC object references properly across the DOM-JS boundary
+               isNode = elem.nodeType,
+
+               // Only DOM nodes need the global jQuery cache; JS object data is
+               // attached directly to the object so GC can occur automatically
+               cache = isNode ? jQuery.cache : elem,
+
+               // Only defining an ID for JS objects if its cache already exists allows
+               // the code to shortcut on the same path as a DOM node with no cache
+               id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+       // Avoid doing any more work than we need to when trying to get data on an
+       // object that has no data at all
+       if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+               return;
+       }
+
+       if ( !id ) {
+               // Only DOM nodes need a new unique ID for each element since their data
+               // ends up in the global cache
+               if ( isNode ) {
+                       id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+               } else {
+                       id = internalKey;
+               }
+       }
+
+       if ( !cache[ id ] ) {
+               // Avoid exposing jQuery metadata on plain JS objects when the object
+               // is serialized using JSON.stringify
+               cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+       }
+
+       // An object can be passed to jQuery.data instead of a key/value pair; this gets
+       // shallow copied over onto the existing cache
+       if ( typeof name === "object" || typeof name === "function" ) {
+               if ( pvt ) {
+                       cache[ id ] = jQuery.extend( cache[ id ], name );
+               } else {
+                       cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+               }
+       }
+
+       thisCache = cache[ id ];
+
+       // jQuery data() is stored in a separate object inside the object's internal data
+       // cache in order to avoid key collisions between internal data and user-defined
+       // data.
+       if ( !pvt ) {
+               if ( !thisCache.data ) {
+                       thisCache.data = {};
+               }
+
+               thisCache = thisCache.data;
+       }
+
+       if ( data !== undefined ) {
+               thisCache[ jQuery.camelCase( name ) ] = data;
+       }
+
+       // Check for both converted-to-camel and non-converted data property names
+       // If a data property was specified
+       if ( typeof name === "string" ) {
+
+               // First Try to find as-is property data
+               ret = thisCache[ name ];
+
+               // Test for null|undefined property data
+               if ( ret == null ) {
+
+                       // Try to find the camelCased property
+                       ret = thisCache[ jQuery.camelCase( name ) ];
+               }
+       } else {
+               ret = thisCache;
+       }
+
+       return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+       if ( !jQuery.acceptData( elem ) ) {
+               return;
+       }
+
+       var thisCache, i,
+               isNode = elem.nodeType,
+
+               // See jQuery.data for more information
+               cache = isNode ? jQuery.cache : elem,
+               id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+       // If there is already no cache entry for this object, there is no
+       // purpose in continuing
+       if ( !cache[ id ] ) {
+               return;
+       }
+
+       if ( name ) {
+
+               thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+               if ( thisCache ) {
+
+                       // Support array or space separated string names for data keys
+                       if ( !jQuery.isArray( name ) ) {
+
+                               // try the string as a key before any manipulation
+                               if ( name in thisCache ) {
+                                       name = [ name ];
+                               } else {
+
+                                       // split the camel cased version by spaces unless a key with the spaces exists
+                                       name = jQuery.camelCase( name );
+                                       if ( name in thisCache ) {
+                                               name = [ name ];
+                                       } else {
+                                               name = name.split(" ");
+                                       }
+                               }
+                       } else {
+                               // If "name" is an array of keys...
+                               // When data is initially created, via ("key", "val") signature,
+                               // keys will be converted to camelCase.
+                               // Since there is no way to tell _how_ a key was added, remove
+                               // both plain key and camelCase key. #12786
+                               // This will only penalize the array argument path.
+                               name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+                       }
+
+                       i = name.length;
+                       while ( i-- ) {
+                               delete thisCache[ name[i] ];
+                       }
+
+                       // If there is no data left in the cache, we want to continue
+                       // and let the cache object itself get destroyed
+                       if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+                               return;
+                       }
+               }
+       }
+
+       // See jQuery.data for more information
+       if ( !pvt ) {
+               delete cache[ id ].data;
+
+               // Don't destroy the parent cache unless the internal data object
+               // had been the only thing left in it
+               if ( !isEmptyDataObject( cache[ id ] ) ) {
+                       return;
+               }
+       }
+
+       // Destroy the cache
+       if ( isNode ) {
+               jQuery.cleanData( [ elem ], true );
+
+       // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+       /* jshint eqeqeq: false */
+       } else if ( support.deleteExpando || cache != cache.window ) {
+               /* jshint eqeqeq: true */
+               delete cache[ id ];
+
+       // When all else fails, null
+       } else {
+               cache[ id ] = null;
+       }
+}
+
+jQuery.extend({
+       cache: {},
+
+       // The following elements (space-suffixed to avoid Object.prototype collisions)
+       // throw uncatchable exceptions if you attempt to set expando properties
+       noData: {
+               "applet ": true,
+               "embed ": true,
+               // ...but Flash objects (which have this classid) *can* handle expandos
+               "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+       },
+
+       hasData: function( elem ) {
+               elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+               return !!elem && !isEmptyDataObject( elem );
+       },
+
+       data: function( elem, name, data ) {
+               return internalData( elem, name, data );
+       },
+
+       removeData: function( elem, name ) {
+               return internalRemoveData( elem, name );
+       },
+
+       // For internal use only.
+       _data: function( elem, name, data ) {
+               return internalData( elem, name, data, true );
+       },
+
+       _removeData: function( elem, name ) {
+               return internalRemoveData( elem, name, true );
+       }
+});
+
+jQuery.fn.extend({
+       data: function( key, value ) {
+               var i, name, data,
+                       elem = this[0],
+                       attrs = elem && elem.attributes;
+
+               // Special expections of .data basically thwart jQuery.access,
+               // so implement the relevant behavior ourselves
+
+               // Gets all values
+               if ( key === undefined ) {
+                       if ( this.length ) {
+                               data = jQuery.data( elem );
+
+                               if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+                                       i = attrs.length;
+                                       while ( i-- ) {
+
+                                               // Support: IE11+
+                                               // The attrs elements can be null (#14894)
+                                               if ( attrs[ i ] ) {
+                                                       name = attrs[ i ].name;
+                                                       if ( name.indexOf( "data-" ) === 0 ) {
+                                                               name = jQuery.camelCase( name.slice(5) );
+                                                               dataAttr( elem, name, data[ name ] );
+                                                       }
+                                               }
+                                       }
+                                       jQuery._data( elem, "parsedAttrs", true );
+                               }
+                       }
+
+                       return data;
+               }
+
+               // Sets multiple values
+               if ( typeof key === "object" ) {
+                       return this.each(function() {
+                               jQuery.data( this, key );
+                       });
+               }
+
+               return arguments.length > 1 ?
+
+                       // Sets one value
+                       this.each(function() {
+                               jQuery.data( this, key, value );
+                       }) :
+
+                       // Gets one value
+                       // Try to fetch any internally stored data first
+                       elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+       },
+
+       removeData: function( key ) {
+               return this.each(function() {
+                       jQuery.removeData( this, key );
+               });
+       }
+});
+
+
+jQuery.extend({
+       queue: function( elem, type, data ) {
+               var queue;
+
+               if ( elem ) {
+                       type = ( type || "fx" ) + "queue";
+                       queue = jQuery._data( elem, type );
+
+                       // Speed up dequeue by getting out quickly if this is just a lookup
+                       if ( data ) {
+                               if ( !queue || jQuery.isArray(data) ) {
+                                       queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+                               } else {
+                                       queue.push( data );
+                               }
+                       }
+                       return queue || [];
+               }
+       },
+
+       dequeue: function( elem, type ) {
+               type = type || "fx";
+
+               var queue = jQuery.queue( elem, type ),
+                       startLength = queue.length,
+                       fn = queue.shift(),
+                       hooks = jQuery._queueHooks( elem, type ),
+                       next = function() {
+                               jQuery.dequeue( elem, type );
+                       };
+
+               // If the fx queue is dequeued, always remove the progress sentinel
+               if ( fn === "inprogress" ) {
+                       fn = queue.shift();
+                       startLength--;
+               }
+
+               if ( fn ) {
+
+                       // Add a progress sentinel to prevent the fx queue from being
+                       // automatically dequeued
+                       if ( type === "fx" ) {
+                               queue.unshift( "inprogress" );
+                       }
+
+                       // clear up the last queue stop function
+                       delete hooks.stop;
+                       fn.call( elem, next, hooks );
+               }
+
+               if ( !startLength && hooks ) {
+                       hooks.empty.fire();
+               }
+       },
+
+       // not intended for public consumption - generates a queueHooks object, or returns the current one
+       _queueHooks: function( elem, type ) {
+               var key = type + "queueHooks";
+               return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+                       empty: jQuery.Callbacks("once memory").add(function() {
+                               jQuery._removeData( elem, type + "queue" );
+                               jQuery._removeData( elem, key );
+                       })
+               });
+       }
+});
+
+jQuery.fn.extend({
+       queue: function( type, data ) {
+               var setter = 2;
+
+               if ( typeof type !== "string" ) {
+                       data = type;
+                       type = "fx";
+                       setter--;
+               }
+
+               if ( arguments.length < setter ) {
+                       return jQuery.queue( this[0], type );
+               }
+
+               return data === undefined ?
+                       this :
+                       this.each(function() {
+                               var queue = jQuery.queue( this, type, data );
+
+                               // ensure a hooks for this queue
+                               jQuery._queueHooks( this, type );
+
+                               if ( type === "fx" && queue[0] !== "inprogress" ) {
+                                       jQuery.dequeue( this, type );
+                               }
+                       });
+       },
+       dequeue: function( type ) {
+               return this.each(function() {
+                       jQuery.dequeue( this, type );
+               });
+       },
+       clearQueue: function( type ) {
+               return this.queue( type || "fx", [] );
+       },
+       // Get a promise resolved when queues of a certain type
+       // are emptied (fx is the type by default)
+       promise: function( type, obj ) {
+               var tmp,
+                       count = 1,
+                       defer = jQuery.Deferred(),
+                       elements = this,
+                       i = this.length,
+                       resolve = function() {
+                               if ( !( --count ) ) {
+                                       defer.resolveWith( elements, [ elements ] );
+                               }
+                       };
+
+               if ( typeof type !== "string" ) {
+                       obj = type;
+                       type = undefined;
+               }
+               type = type || "fx";
+
+               while ( i-- ) {
+                       tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+                       if ( tmp && tmp.empty ) {
+                               count++;
+                               tmp.empty.add( resolve );
+                       }
+               }
+               resolve();
+               return defer.promise( obj );
+       }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+               // isHidden might be called from jQuery#filter function;
+               // in that case, element will be second argument
+               elem = el || elem;
+               return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+       };
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+       var i = 0,
+               length = elems.length,
+               bulk = key == null;
+
+       // Sets many values
+       if ( jQuery.type( key ) === "object" ) {
+               chainable = true;
+               for ( i in key ) {
+                       jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+               }
+
+       // Sets one value
+       } else if ( value !== undefined ) {
+               chainable = true;
+
+               if ( !jQuery.isFunction( value ) ) {
+                       raw = true;
+               }
+
+               if ( bulk ) {
+                       // Bulk operations run against the entire set
+                       if ( raw ) {
+                               fn.call( elems, value );
+                               fn = null;
+
+                       // ...except when executing function values
+                       } else {
+                               bulk = fn;
+                               fn = function( elem, key, value ) {
+                                       return bulk.call( jQuery( elem ), value );
+                               };
+                       }
+               }
+
+               if ( fn ) {
+                       for ( ; i < length; i++ ) {
+                               fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+                       }
+               }
+       }
+
+       return chainable ?
+               elems :
+
+               // Gets
+               bulk ?
+                       fn.call( elems ) :
+                       length ? fn( elems[0], key ) : emptyGet;
+};
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+       // Minified: var a,b,c
+       var input = document.createElement( "input" ),
+               div = document.createElement( "div" ),
+               fragment = document.createDocumentFragment();
+
+       // Setup
+       div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+       // IE strips leading whitespace when .innerHTML is used
+       support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+       // Make sure that tbody elements aren't automatically inserted
+       // IE will insert them into empty tables
+       support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+       // Make sure that link elements get serialized correctly by innerHTML
+       // This requires a wrapper element in IE
+       support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+       // Makes sure cloning an html5 element does not cause problems
+       // Where outerHTML is undefined, this still works
+       support.html5Clone =
+               document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+       // Check if a disconnected checkbox will retain its checked
+       // value of true after appended to the DOM (IE6/7)
+       input.type = "checkbox";
+       input.checked = true;
+       fragment.appendChild( input );
+       support.appendChecked = input.checked;
+
+       // Make sure textarea (and checkbox) defaultValue is properly cloned
+       // Support: IE6-IE11+
+       div.innerHTML = "<textarea>x</textarea>";
+       support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+       // #11217 - WebKit loses check when the name is after the checked attribute
+       fragment.appendChild( div );
+       div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
+
+       // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+       // old WebKit doesn't clone checked state correctly in fragments
+       support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+       // Support: IE<9
+       // Opera does not clone events (and typeof div.attachEvent === undefined).
+       // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+       support.noCloneEvent = true;
+       if ( div.attachEvent ) {
+               div.attachEvent( "onclick", function() {
+                       support.noCloneEvent = false;
+               });
+
+               div.cloneNode( true ).click();
+       }
+
+       // Execute the test only if not already executed in another module.
+       if (support.deleteExpando == null) {
+               // Support: IE<9
+               support.deleteExpando = true;
+               try {
+                       delete div.test;
+               } catch( e ) {
+                       support.deleteExpando = false;
+               }
+       }
+})();
+
+
+(function() {
+       var i, eventName,
+               div = document.createElement( "div" );
+
+       // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+       for ( i in { submit: true, change: true, focusin: true }) {
+               eventName = "on" + i;
+
+               if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+                       // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+                       div.setAttribute( eventName, "t" );
+                       support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+               }
+       }
+
+       // Null elements to avoid leaks in IE.
+       div = null;
+})();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+       rkeyEvent = /^key/,
+       rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+       rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+       rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+       return true;
+}
+
+function returnFalse() {
+       return false;
+}
+
+function safeActiveElement() {
+       try {
+               return document.activeElement;
+       } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+       global: {},
+
+       add: function( elem, types, handler, data, selector ) {
+               var tmp, events, t, handleObjIn,
+                       special, eventHandle, handleObj,
+                       handlers, type, namespaces, origType,
+                       elemData = jQuery._data( elem );
+
+               // Don't attach events to noData or text/comment nodes (but allow plain objects)
+               if ( !elemData ) {
+                       return;
+               }
+
+               // Caller can pass in an object of custom data in lieu of the handler
+               if ( handler.handler ) {
+                       handleObjIn = handler;
+                       handler = handleObjIn.handler;
+                       selector = handleObjIn.selector;
+               }
+
+               // Make sure that the handler has a unique ID, used to find/remove it later
+               if ( !handler.guid ) {
+                       handler.guid = jQuery.guid++;
+               }
+
+               // Init the element's event structure and main handler, if this is the first
+               if ( !(events = elemData.events) ) {
+                       events = elemData.events = {};
+               }
+               if ( !(eventHandle = elemData.handle) ) {
+                       eventHandle = elemData.handle = function( e ) {
+                               // Discard the second event of a jQuery.event.trigger() and
+                               // when an event is called after a page has unloaded
+                               return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+                                       jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+                                       undefined;
+                       };
+                       // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+                       eventHandle.elem = elem;
+               }
+
+               // Handle multiple events separated by a space
+               types = ( types || "" ).match( rnotwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // There *must* be a type, no attaching namespace-only handlers
+                       if ( !type ) {
+                               continue;
+                       }
+
+                       // If event changes its type, use the special event handlers for the changed type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // If selector defined, determine special event api type, otherwise given type
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+
+                       // Update special based on newly reset type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // handleObj is passed to all event handlers
+                       handleObj = jQuery.extend({
+                               type: type,
+                               origType: origType,
+                               data: data,
+                               handler: handler,
+                               guid: handler.guid,
+                               selector: selector,
+                               needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+                               namespace: namespaces.join(".")
+                       }, handleObjIn );
+
+                       // Init the event handler queue if we're the first
+                       if ( !(handlers = events[ type ]) ) {
+                               handlers = events[ type ] = [];
+                               handlers.delegateCount = 0;
+
+                               // Only use addEventListener/attachEvent if the special events handler returns false
+                               if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+                                       // Bind the global event handler to the element
+                                       if ( elem.addEventListener ) {
+                                               elem.addEventListener( type, eventHandle, false );
+
+                                       } else if ( elem.attachEvent ) {
+                                               elem.attachEvent( "on" + type, eventHandle );
+                                       }
+                               }
+                       }
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
+
+                               if ( !handleObj.handler.guid ) {
+                                       handleObj.handler.guid = handler.guid;
+                               }
+                       }
+
+                       // Add to the element's handler list, delegates in front
+                       if ( selector ) {
+                               handlers.splice( handlers.delegateCount++, 0, handleObj );
+                       } else {
+                               handlers.push( handleObj );
+                       }
+
+                       // Keep track of which events have ever been used, for event optimization
+                       jQuery.event.global[ type ] = true;
+               }
+
+               // Nullify elem to prevent memory leaks in IE
+               elem = null;
+       },
+
+       // Detach an event or set of events from an element
+       remove: function( elem, types, handler, selector, mappedTypes ) {
+               var j, handleObj, tmp,
+                       origCount, t, events,
+                       special, handlers, type,
+                       namespaces, origType,
+                       elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+               if ( !elemData || !(events = elemData.events) ) {
+                       return;
+               }
+
+               // Once for each type.namespace in types; type may be omitted
+               types = ( types || "" ).match( rnotwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[t] ) || [];
+                       type = origType = tmp[1];
+                       namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+                       // Unbind all events (on this namespace, if provided) for the element
+                       if ( !type ) {
+                               for ( type in events ) {
+                                       jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+                               }
+                               continue;
+                       }
+
+                       special = jQuery.event.special[ type ] || {};
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+                       handlers = events[ type ] || [];
+                       tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+                       // Remove matching events
+                       origCount = j = handlers.length;
+                       while ( j-- ) {
+                               handleObj = handlers[ j ];
+
+                               if ( ( mappedTypes || origType === handleObj.origType ) &&
+                                       ( !handler || handler.guid === handleObj.guid ) &&
+                                       ( !tmp || tmp.test( handleObj.namespace ) ) &&
+                                       ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+                                       handlers.splice( j, 1 );
+
+                                       if ( handleObj.selector ) {
+                                               handlers.delegateCount--;
+                                       }
+                                       if ( special.remove ) {
+                                               special.remove.call( elem, handleObj );
+                                       }
+                               }
+                       }
+
+                       // Remove generic event handler if we removed something and no more handlers exist
+                       // (avoids potential for endless recursion during removal of special event handlers)
+                       if ( origCount && !handlers.length ) {
+                               if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+                                       jQuery.removeEvent( elem, type, elemData.handle );
+                               }
+
+                               delete events[ type ];
+                       }
+               }
+
+               // Remove the expando if it's no longer used
+               if ( jQuery.isEmptyObject( events ) ) {
+                       delete elemData.handle;
+
+                       // removeData also checks for emptiness and clears the expando if empty
+                       // so use it instead of delete
+                       jQuery._removeData( elem, "events" );
+               }
+       },
+
+       trigger: function( event, data, elem, onlyHandlers ) {
+               var handle, ontype, cur,
+                       bubbleType, special, tmp, i,
+                       eventPath = [ elem || document ],
+                       type = hasOwn.call( event, "type" ) ? event.type : event,
+                       namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+               cur = tmp = elem = elem || document;
+
+               // Don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               // focus/blur morphs to focusin/out; ensure we're not firing them right now
+               if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+                       return;
+               }
+
+               if ( type.indexOf(".") >= 0 ) {
+                       // Namespaced trigger; create a regexp to match event type in handle()
+                       namespaces = type.split(".");
+                       type = namespaces.shift();
+                       namespaces.sort();
+               }
+               ontype = type.indexOf(":") < 0 && "on" + type;
+
+               // Caller can pass in a jQuery.Event object, Object, or just an event type string
+               event = event[ jQuery.expando ] ?
+                       event :
+                       new jQuery.Event( type, typeof event === "object" && event );
+
+               // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+               event.isTrigger = onlyHandlers ? 2 : 3;
+               event.namespace = namespaces.join(".");
+               event.namespace_re = event.namespace ?
+                       new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+                       null;
+
+               // Clean up the event in case it is being reused
+               event.result = undefined;
+               if ( !event.target ) {
+                       event.target = elem;
+               }
+
+               // Clone any incoming data and prepend the event, creating the handler arg list
+               data = data == null ?
+                       [ event ] :
+                       jQuery.makeArray( data, [ event ] );
+
+               // Allow special events to draw outside the lines
+               special = jQuery.event.special[ type ] || {};
+               if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+                       return;
+               }
+
+               // Determine event propagation path in advance, per W3C events spec (#9951)
+               // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+               if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+                       bubbleType = special.delegateType || type;
+                       if ( !rfocusMorph.test( bubbleType + type ) ) {
+                               cur = cur.parentNode;
+                       }
+                       for ( ; cur; cur = cur.parentNode ) {
+                               eventPath.push( cur );
+                               tmp = cur;
+                       }
+
+                       // Only add window if we got to document (e.g., not plain obj or detached DOM)
+                       if ( tmp === (elem.ownerDocument || document) ) {
+                               eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+                       }
+               }
+
+               // Fire handlers on the event path
+               i = 0;
+               while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+                       event.type = i > 1 ?
+                               bubbleType :
+                               special.bindType || type;
+
+                       // jQuery handler
+                       handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+                       if ( handle ) {
+                               handle.apply( cur, data );
+                       }
+
+                       // Native handler
+                       handle = ontype && cur[ ontype ];
+                       if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+                               event.result = handle.apply( cur, data );
+                               if ( event.result === false ) {
+                                       event.preventDefault();
+                               }
+                       }
+               }
+               event.type = type;
+
+               // If nobody prevented the default action, do it now
+               if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+                       if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+                               jQuery.acceptData( elem ) ) {
+
+                               // Call a native DOM method on the target with the same name name as the event.
+                               // Can't use an .isFunction() check here because IE6/7 fails that test.
+                               // Don't do default actions on window, that's where global variables be (#6170)
+                               if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+                                       // Don't re-trigger an onFOO event when we call its FOO() method
+                                       tmp = elem[ ontype ];
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = null;
+                                       }
+
+                                       // Prevent re-triggering of the same event, since we already bubbled it above
+                                       jQuery.event.triggered = type;
+                                       try {
+                                               elem[ type ]();
+                                       } catch ( e ) {
+                                               // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+                                               // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+                                       }
+                                       jQuery.event.triggered = undefined;
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = tmp;
+                                       }
+                               }
+                       }
+               }
+
+               return event.result;
+       },
+
+       dispatch: function( event ) {
+
+               // Make a writable jQuery.Event from the native event object
+               event = jQuery.event.fix( event );
+
+               var i, ret, handleObj, matched, j,
+                       handlerQueue = [],
+                       args = slice.call( arguments ),
+                       handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+                       special = jQuery.event.special[ event.type ] || {};
+
+               // Use the fix-ed jQuery.Event rather than the (read-only) native event
+               args[0] = event;
+               event.delegateTarget = this;
+
+               // Call the preDispatch hook for the mapped type, and let it bail if desired
+               if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+                       return;
+               }
+
+               // Determine handlers
+               handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+               // Run delegates first; they may want to stop propagation beneath us
+               i = 0;
+               while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+                       event.currentTarget = matched.elem;
+
+                       j = 0;
+                       while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+                               // Triggered event must either 1) have no namespace, or
+                               // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+                               if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+                                       event.handleObj = handleObj;
+                                       event.data = handleObj.data;
+
+                                       ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+                                                       .apply( matched.elem, args );
+
+                                       if ( ret !== undefined ) {
+                                               if ( (event.result = ret) === false ) {
+                                                       event.preventDefault();
+                                                       event.stopPropagation();
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Call the postDispatch hook for the mapped type
+               if ( special.postDispatch ) {
+                       special.postDispatch.call( this, event );
+               }
+
+               return event.result;
+       },
+
+       handlers: function( event, handlers ) {
+               var sel, handleObj, matches, i,
+                       handlerQueue = [],
+                       delegateCount = handlers.delegateCount,
+                       cur = event.target;
+
+               // Find delegate handlers
+               // Black-hole SVG <use> instance trees (#13180)
+               // Avoid non-left-click bubbling in Firefox (#3861)
+               if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+                       /* jshint eqeqeq: false */
+                       for ( ; cur != this; cur = cur.parentNode || this ) {
+                               /* jshint eqeqeq: true */
+
+                               // Don't check non-elements (#13208)
+                               // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+                               if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+                                       matches = [];
+                                       for ( i = 0; i < delegateCount; i++ ) {
+                                               handleObj = handlers[ i ];
+
+                                               // Don't conflict with Object.prototype properties (#13203)
+                                               sel = handleObj.selector + " ";
+
+                                               if ( matches[ sel ] === undefined ) {
+                                                       matches[ sel ] = handleObj.needsContext ?
+                                                               jQuery( sel, this ).index( cur ) >= 0 :
+                                                               jQuery.find( sel, this, null, [ cur ] ).length;
+                                               }
+                                               if ( matches[ sel ] ) {
+                                                       matches.push( handleObj );
+                                               }
+                                       }
+                                       if ( matches.length ) {
+                                               handlerQueue.push({ elem: cur, handlers: matches });
+                                       }
+                               }
+                       }
+               }
+
+               // Add the remaining (directly-bound) handlers
+               if ( delegateCount < handlers.length ) {
+                       handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+               }
+
+               return handlerQueue;
+       },
+
+       fix: function( event ) {
+               if ( event[ jQuery.expando ] ) {
+                       return event;
+               }
+
+               // Create a writable copy of the event object and normalize some properties
+               var i, prop, copy,
+                       type = event.type,
+                       originalEvent = event,
+                       fixHook = this.fixHooks[ type ];
+
+               if ( !fixHook ) {
+                       this.fixHooks[ type ] = fixHook =
+                               rmouseEvent.test( type ) ? this.mouseHooks :
+                               rkeyEvent.test( type ) ? this.keyHooks :
+                               {};
+               }
+               copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+               event = new jQuery.Event( originalEvent );
+
+               i = copy.length;
+               while ( i-- ) {
+                       prop = copy[ i ];
+                       event[ prop ] = originalEvent[ prop ];
+               }
+
+               // Support: IE<9
+               // Fix target property (#1925)
+               if ( !event.target ) {
+                       event.target = originalEvent.srcElement || document;
+               }
+
+               // Support: Chrome 23+, Safari?
+               // Target should not be a text node (#504, #13143)
+               if ( event.target.nodeType === 3 ) {
+                       event.target = event.target.parentNode;
+               }
+
+               // Support: IE<9
+               // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+               event.metaKey = !!event.metaKey;
+
+               return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+       },
+
+       // Includes some event props shared by KeyEvent and MouseEvent
+       props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+       fixHooks: {},
+
+       keyHooks: {
+               props: "char charCode key keyCode".split(" "),
+               filter: function( event, original ) {
+
+                       // Add which for key events
+                       if ( event.which == null ) {
+                               event.which = original.charCode != null ? original.charCode : original.keyCode;
+                       }
+
+                       return event;
+               }
+       },
+
+       mouseHooks: {
+               props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+               filter: function( event, original ) {
+                       var body, eventDoc, doc,
+                               button = original.button,
+                               fromElement = original.fromElement;
+
+                       // Calculate pageX/Y if missing and clientX/Y available
+                       if ( event.pageX == null && original.clientX != null ) {
+                               eventDoc = event.target.ownerDocument || document;
+                               doc = eventDoc.documentElement;
+                               body = eventDoc.body;
+
+                               event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+                               event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+                       }
+
+                       // Add relatedTarget, if necessary
+                       if ( !event.relatedTarget && fromElement ) {
+                               event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+                       }
+
+                       // Add which for click: 1 === left; 2 === middle; 3 === right
+                       // Note: button is not normalized, so don't use it
+                       if ( !event.which && button !== undefined ) {
+                               event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+                       }
+
+                       return event;
+               }
+       },
+
+       special: {
+               load: {
+                       // Prevent triggered image.load events from bubbling to window.load
+                       noBubble: true
+               },
+               focus: {
+                       // Fire native event if possible so blur/focus sequence is correct
+                       trigger: function() {
+                               if ( this !== safeActiveElement() && this.focus ) {
+                                       try {
+                                               this.focus();
+                                               return false;
+                                       } catch ( e ) {
+                                               // Support: IE<9
+                                               // If we error on focus to hidden element (#1486, #12518),
+                                               // let .trigger() run the handlers
+                                       }
+                               }
+                       },
+                       delegateType: "focusin"
+               },
+               blur: {
+                       trigger: function() {
+                               if ( this === safeActiveElement() && this.blur ) {
+                                       this.blur();
+                                       return false;
+                               }
+                       },
+                       delegateType: "focusout"
+               },
+               click: {
+                       // For checkbox, fire native event so checked state will be right
+                       trigger: function() {
+                               if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+                                       this.click();
+                                       return false;
+                               }
+                       },
+
+                       // For cross-browser consistency, don't fire native .click() on links
+                       _default: function( event ) {
+                               return jQuery.nodeName( event.target, "a" );
+                       }
+               },
+
+               beforeunload: {
+                       postDispatch: function( event ) {
+
+                               // Support: Firefox 20+
+                               // Firefox doesn't alert if the returnValue field is not set.
+                               if ( event.result !== undefined && event.originalEvent ) {
+                                       event.originalEvent.returnValue = event.result;
+                               }
+                       }
+               }
+       },
+
+       simulate: function( type, elem, event, bubble ) {
+               // Piggyback on a donor event to simulate a different one.
+               // Fake originalEvent to avoid donor's stopPropagation, but if the
+               // simulated event prevents default then we do the same on the donor.
+               var e = jQuery.extend(
+                       new jQuery.Event(),
+                       event,
+                       {
+                               type: type,
+                               isSimulated: true,
+                               originalEvent: {}
+                       }
+               );
+               if ( bubble ) {
+                       jQuery.event.trigger( e, null, elem );
+               } else {
+                       jQuery.event.dispatch.call( elem, e );
+               }
+               if ( e.isDefaultPrevented() ) {
+                       event.preventDefault();
+               }
+       }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+       function( elem, type, handle ) {
+               if ( elem.removeEventListener ) {
+                       elem.removeEventListener( type, handle, false );
+               }
+       } :
+       function( elem, type, handle ) {
+               var name = "on" + type;
+
+               if ( elem.detachEvent ) {
+
+                       // #8545, #7054, preventing memory leaks for custom events in IE6-8
+                       // detachEvent needed property on element, by name of that event, to properly expose it to GC
+                       if ( typeof elem[ name ] === strundefined ) {
+                               elem[ name ] = null;
+                       }
+
+                       elem.detachEvent( name, handle );
+               }
+       };
+
+jQuery.Event = function( src, props ) {
+       // Allow instantiation without the 'new' keyword
+       if ( !(this instanceof jQuery.Event) ) {
+               return new jQuery.Event( src, props );
+       }
+
+       // Event object
+       if ( src && src.type ) {
+               this.originalEvent = src;
+               this.type = src.type;
+
+               // Events bubbling up the document may have been marked as prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = src.defaultPrevented ||
+                               src.defaultPrevented === undefined &&
+                               // Support: IE < 9, Android < 4.0
+                               src.returnValue === false ?
+                       returnTrue :
+                       returnFalse;
+
+       // Event type
+       } else {
+               this.type = src;
+       }
+
+       // Put explicitly provided properties onto the event object
+       if ( props ) {
+               jQuery.extend( this, props );
+       }
+
+       // Create a timestamp if incoming event doesn't have one
+       this.timeStamp = src && src.timeStamp || jQuery.now();
+
+       // Mark it as fixed
+       this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+       isDefaultPrevented: returnFalse,
+       isPropagationStopped: returnFalse,
+       isImmediatePropagationStopped: returnFalse,
+
+       preventDefault: function() {
+               var e = this.originalEvent;
+
+               this.isDefaultPrevented = returnTrue;
+               if ( !e ) {
+                       return;
+               }
+
+               // If preventDefault exists, run it on the original event
+               if ( e.preventDefault ) {
+                       e.preventDefault();
+
+               // Support: IE
+               // Otherwise set the returnValue property of the original event to false
+               } else {
+                       e.returnValue = false;
+               }
+       },
+       stopPropagation: function() {
+               var e = this.originalEvent;
+
+               this.isPropagationStopped = returnTrue;
+               if ( !e ) {
+                       return;
+               }
+               // If stopPropagation exists, run it on the original event
+               if ( e.stopPropagation ) {
+                       e.stopPropagation();
+               }
+
+               // Support: IE
+               // Set the cancelBubble property of the original event to true
+               e.cancelBubble = true;
+       },
+       stopImmediatePropagation: function() {
+               var e = this.originalEvent;
+
+               this.isImmediatePropagationStopped = returnTrue;
+
+               if ( e && e.stopImmediatePropagation ) {
+                       e.stopImmediatePropagation();
+               }
+
+               this.stopPropagation();
+       }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+       mouseenter: "mouseover",
+       mouseleave: "mouseout",
+       pointerenter: "pointerover",
+       pointerleave: "pointerout"
+}, function( orig, fix ) {
+       jQuery.event.special[ orig ] = {
+               delegateType: fix,
+               bindType: fix,
+
+               handle: function( event ) {
+                       var ret,
+                               target = this,
+                               related = event.relatedTarget,
+                               handleObj = event.handleObj;
+
+                       // For mousenter/leave call the handler if related is outside the target.
+                       // NB: No relatedTarget if the mouse left/entered the browser window
+                       if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+                               event.type = handleObj.origType;
+                               ret = handleObj.handler.apply( this, arguments );
+                               event.type = fix;
+                       }
+                       return ret;
+               }
+       };
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+       jQuery.event.special.submit = {
+               setup: function() {
+                       // Only need this for delegated form submit events
+                       if ( jQuery.nodeName( this, "form" ) ) {
+                               return false;
+                       }
+
+                       // Lazy-add a submit handler when a descendant form may potentially be submitted
+                       jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+                               // Node name check avoids a VML-related crash in IE (#9807)
+                               var elem = e.target,
+                                       form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+                               if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+                                       jQuery.event.add( form, "submit._submit", function( event ) {
+                                               event._submit_bubble = true;
+                                       });
+                                       jQuery._data( form, "submitBubbles", true );
+                               }
+                       });
+                       // return undefined since we don't need an event listener
+               },
+
+               postDispatch: function( event ) {
+                       // If form was submitted by the user, bubble the event up the tree
+                       if ( event._submit_bubble ) {
+                               delete event._submit_bubble;
+                               if ( this.parentNode && !event.isTrigger ) {
+                                       jQuery.event.simulate( "submit", this.parentNode, event, true );
+                               }
+                       }
+               },
+
+               teardown: function() {
+                       // Only need this for delegated form submit events
+                       if ( jQuery.nodeName( this, "form" ) ) {
+                               return false;
+                       }
+
+                       // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+                       jQuery.event.remove( this, "._submit" );
+               }
+       };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+       jQuery.event.special.change = {
+
+               setup: function() {
+
+                       if ( rformElems.test( this.nodeName ) ) {
+                               // IE doesn't fire change on a check/radio until blur; trigger it on click
+                               // after a propertychange. Eat the blur-change in special.change.handle.
+                               // This still fires onchange a second time for check/radio after blur.
+                               if ( this.type === "checkbox" || this.type === "radio" ) {
+                                       jQuery.event.add( this, "propertychange._change", function( event ) {
+                                               if ( event.originalEvent.propertyName === "checked" ) {
+                                                       this._just_changed = true;
+                                               }
+                                       });
+                                       jQuery.event.add( this, "click._change", function( event ) {
+                                               if ( this._just_changed && !event.isTrigger ) {
+                                                       this._just_changed = false;
+                                               }
+                                               // Allow triggered, simulated change events (#11500)
+                                               jQuery.event.simulate( "change", this, event, true );
+                                       });
+                               }
+                               return false;
+                       }
+                       // Delegated event; lazy-add a change handler on descendant inputs
+                       jQuery.event.add( this, "beforeactivate._change", function( e ) {
+                               var elem = e.target;
+
+                               if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+                                       jQuery.event.add( elem, "change._change", function( event ) {
+                                               if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+                                                       jQuery.event.simulate( "change", this.parentNode, event, true );
+                                               }
+                                       });
+                                       jQuery._data( elem, "changeBubbles", true );
+                               }
+                       });
+               },
+
+               handle: function( event ) {
+                       var elem = event.target;
+
+                       // Swallow native change events from checkbox/radio, we already triggered them above
+                       if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+                               return event.handleObj.handler.apply( this, arguments );
+                       }
+               },
+
+               teardown: function() {
+                       jQuery.event.remove( this, "._change" );
+
+                       return !rformElems.test( this.nodeName );
+               }
+       };
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+       jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+               // Attach a single capturing handler on the document while someone wants focusin/focusout
+               var handler = function( event ) {
+                               jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+                       };
+
+               jQuery.event.special[ fix ] = {
+                       setup: function() {
+                               var doc = this.ownerDocument || this,
+                                       attaches = jQuery._data( doc, fix );
+
+                               if ( !attaches ) {
+                                       doc.addEventListener( orig, handler, true );
+                               }
+                               jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+                       },
+                       teardown: function() {
+                               var doc = this.ownerDocument || this,
+                                       attaches = jQuery._data( doc, fix ) - 1;
+
+                               if ( !attaches ) {
+                                       doc.removeEventListener( orig, handler, true );
+                                       jQuery._removeData( doc, fix );
+                               } else {
+                                       jQuery._data( doc, fix, attaches );
+                               }
+                       }
+               };
+       });
+}
+
+jQuery.fn.extend({
+
+       on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+               var type, origFn;
+
+               // Types can be a map of types/handlers
+               if ( typeof types === "object" ) {
+                       // ( types-Object, selector, data )
+                       if ( typeof selector !== "string" ) {
+                               // ( types-Object, data )
+                               data = data || selector;
+                               selector = undefined;
+                       }
+                       for ( type in types ) {
+                               this.on( type, selector, data, types[ type ], one );
+                       }
+                       return this;
+               }
+
+               if ( data == null && fn == null ) {
+                       // ( types, fn )
+                       fn = selector;
+                       data = selector = undefined;
+               } else if ( fn == null ) {
+                       if ( typeof selector === "string" ) {
+                               // ( types, selector, fn )
+                               fn = data;
+                               data = undefined;
+                       } else {
+                               // ( types, data, fn )
+                               fn = data;
+                               data = selector;
+                               selector = undefined;
+                       }
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               } else if ( !fn ) {
+                       return this;
+               }
+
+               if ( one === 1 ) {
+                       origFn = fn;
+                       fn = function( event ) {
+                               // Can use an empty set, since event contains the info
+                               jQuery().off( event );
+                               return origFn.apply( this, arguments );
+                       };
+                       // Use same guid so caller can remove using origFn
+                       fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+               }
+               return this.each( function() {
+                       jQuery.event.add( this, types, fn, data, selector );
+               });
+       },
+       one: function( types, selector, data, fn ) {
+               return this.on( types, selector, data, fn, 1 );
+       },
+       off: function( types, selector, fn ) {
+               var handleObj, type;
+               if ( types && types.preventDefault && types.handleObj ) {
+                       // ( event )  dispatched jQuery.Event
+                       handleObj = types.handleObj;
+                       jQuery( types.delegateTarget ).off(
+                               handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+                               handleObj.selector,
+                               handleObj.handler
+                       );
+                       return this;
+               }
+               if ( typeof types === "object" ) {
+                       // ( types-object [, selector] )
+                       for ( type in types ) {
+                               this.off( type, selector, types[ type ] );
+                       }
+                       return this;
+               }
+               if ( selector === false || typeof selector === "function" ) {
+                       // ( types [, fn] )
+                       fn = selector;
+                       selector = undefined;
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               }
+               return this.each(function() {
+                       jQuery.event.remove( this, types, fn, selector );
+               });
+       },
+
+       trigger: function( type, data ) {
+               return this.each(function() {
+                       jQuery.event.trigger( type, data, this );
+               });
+       },
+       triggerHandler: function( type, data ) {
+               var elem = this[0];
+               if ( elem ) {
+                       return jQuery.event.trigger( type, data, elem, true );
+               }
+       }
+});
+
+
+function createSafeFragment( document ) {
+       var list = nodeNames.split( "|" ),
+               safeFrag = document.createDocumentFragment();
+
+       if ( safeFrag.createElement ) {
+               while ( list.length ) {
+                       safeFrag.createElement(
+                               list.pop()
+                       );
+               }
+       }
+       return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+               "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+       rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+       rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+       rleadingWhitespace = /^\s+/,
+       rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+       rtagName = /<([\w:]+)/,
+       rtbody = /<tbody/i,
+       rhtml = /<|&#?\w+;/,
+       rnoInnerhtml = /<(?:script|style|link)/i,
+       // checked="checked" or checked
+       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+       rscriptType = /^$|\/(?:java|ecma)script/i,
+       rscriptTypeMasked = /^true\/(.*)/,
+       rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+       // We have to close these tags to support XHTML (#13200)
+       wrapMap = {
+               option: [ 1, "<select multiple='multiple'>", "</select>" ],
+               legend: [ 1, "<fieldset>", "</fieldset>" ],
+               area: [ 1, "<map>", "</map>" ],
+               param: [ 1, "<object>", "</object>" ],
+               thead: [ 1, "<table>", "</table>" ],
+               tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+               col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+               td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+               // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+               // unless wrapped in a div with non-breaking characters in front of it.
+               _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
+       },
+       safeFragment = createSafeFragment( document ),
+       fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+       var elems, elem,
+               i = 0,
+               found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+                       typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+                       undefined;
+
+       if ( !found ) {
+               for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+                       if ( !tag || jQuery.nodeName( elem, tag ) ) {
+                               found.push( elem );
+                       } else {
+                               jQuery.merge( found, getAll( elem, tag ) );
+                       }
+               }
+       }
+
+       return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+               jQuery.merge( [ context ], found ) :
+               found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+       if ( rcheckableType.test( elem.type ) ) {
+               elem.defaultChecked = elem.checked;
+       }
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+       return jQuery.nodeName( elem, "table" ) &&
+               jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+               elem.getElementsByTagName("tbody")[0] ||
+                       elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+               elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+       elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+       return elem;
+}
+function restoreScript( elem ) {
+       var match = rscriptTypeMasked.exec( elem.type );
+       if ( match ) {
+               elem.type = match[1];
+       } else {
+               elem.removeAttribute("type");
+       }
+       return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+       var elem,
+               i = 0;
+       for ( ; (elem = elems[i]) != null; i++ ) {
+               jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+       }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+       if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+               return;
+       }
+
+       var type, i, l,
+               oldData = jQuery._data( src ),
+               curData = jQuery._data( dest, oldData ),
+               events = oldData.events;
+
+       if ( events ) {
+               delete curData.handle;
+               curData.events = {};
+
+               for ( type in events ) {
+                       for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+                               jQuery.event.add( dest, type, events[ type ][ i ] );
+                       }
+               }
+       }
+
+       // make the cloned public data object a copy from the original
+       if ( curData.data ) {
+               curData.data = jQuery.extend( {}, curData.data );
+       }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+       var nodeName, e, data;
+
+       // We do not need to do anything for non-Elements
+       if ( dest.nodeType !== 1 ) {
+               return;
+       }
+
+       nodeName = dest.nodeName.toLowerCase();
+
+       // IE6-8 copies events bound via attachEvent when using cloneNode.
+       if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+               data = jQuery._data( dest );
+
+               for ( e in data.events ) {
+                       jQuery.removeEvent( dest, e, data.handle );
+               }
+
+               // Event data gets referenced instead of copied if the expando gets copied too
+               dest.removeAttribute( jQuery.expando );
+       }
+
+       // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+       if ( nodeName === "script" && dest.text !== src.text ) {
+               disableScript( dest ).text = src.text;
+               restoreScript( dest );
+
+       // IE6-10 improperly clones children of object elements using classid.
+       // IE10 throws NoModificationAllowedError if parent is null, #12132.
+       } else if ( nodeName === "object" ) {
+               if ( dest.parentNode ) {
+                       dest.outerHTML = src.outerHTML;
+               }
+
+               // This path appears unavoidable for IE9. When cloning an object
+               // element in IE9, the outerHTML strategy above is not sufficient.
+               // If the src has innerHTML and the destination does not,
+               // copy the src.innerHTML into the dest.innerHTML. #10324
+               if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+                       dest.innerHTML = src.innerHTML;
+               }
+
+       } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+               // IE6-8 fails to persist the checked state of a cloned checkbox
+               // or radio button. Worse, IE6-7 fail to give the cloned element
+               // a checked appearance if the defaultChecked value isn't also set
+
+               dest.defaultChecked = dest.checked = src.checked;
+
+               // IE6-7 get confused and end up setting the value of a cloned
+               // checkbox/radio button to an empty string instead of "on"
+               if ( dest.value !== src.value ) {
+                       dest.value = src.value;
+               }
+
+       // IE6-8 fails to return the selected option to the default selected
+       // state when cloning options
+       } else if ( nodeName === "option" ) {
+               dest.defaultSelected = dest.selected = src.defaultSelected;
+
+       // IE6-8 fails to set the defaultValue to the correct value when
+       // cloning other types of input fields
+       } else if ( nodeName === "input" || nodeName === "textarea" ) {
+               dest.defaultValue = src.defaultValue;
+       }
+}
+
+jQuery.extend({
+       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+               var destElements, node, clone, i, srcElements,
+                       inPage = jQuery.contains( elem.ownerDocument, elem );
+
+               if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+                       clone = elem.cloneNode( true );
+
+               // IE<=8 does not properly clone detached, unknown element nodes
+               } else {
+                       fragmentDiv.innerHTML = elem.outerHTML;
+                       fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+               }
+
+               if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+                               (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+                       // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+                       destElements = getAll( clone );
+                       srcElements = getAll( elem );
+
+                       // Fix all IE cloning issues
+                       for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+                               // Ensure that the destination node is not null; Fixes #9587
+                               if ( destElements[i] ) {
+                                       fixCloneNodeIssues( node, destElements[i] );
+                               }
+                       }
+               }
+
+               // Copy the events from the original to the clone
+               if ( dataAndEvents ) {
+                       if ( deepDataAndEvents ) {
+                               srcElements = srcElements || getAll( elem );
+                               destElements = destElements || getAll( clone );
+
+                               for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+                                       cloneCopyEvent( node, destElements[i] );
+                               }
+                       } else {
+                               cloneCopyEvent( elem, clone );
+                       }
+               }
+
+               // Preserve script evaluation history
+               destElements = getAll( clone, "script" );
+               if ( destElements.length > 0 ) {
+                       setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+               }
+
+               destElements = srcElements = node = null;
+
+               // Return the cloned set
+               return clone;
+       },
+
+       buildFragment: function( elems, context, scripts, selection ) {
+               var j, elem, contains,
+                       tmp, tag, tbody, wrap,
+                       l = elems.length,
+
+                       // Ensure a safe fragment
+                       safe = createSafeFragment( context ),
+
+                       nodes = [],
+                       i = 0;
+
+               for ( ; i < l; i++ ) {
+                       elem = elems[ i ];
+
+                       if ( elem || elem === 0 ) {
+
+                               // Add nodes directly
+                               if ( jQuery.type( elem ) === "object" ) {
+                                       jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+                               // Convert non-html into a text node
+                               } else if ( !rhtml.test( elem ) ) {
+                                       nodes.push( context.createTextNode( elem ) );
+
+                               // Convert html into DOM nodes
+                               } else {
+                                       tmp = tmp || safe.appendChild( context.createElement("div") );
+
+                                       // Deserialize a standard representation
+                                       tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+                                       wrap = wrapMap[ tag ] || wrapMap._default;
+
+                                       tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+                                       // Descend through wrappers to the right content
+                                       j = wrap[0];
+                                       while ( j-- ) {
+                                               tmp = tmp.lastChild;
+                                       }
+
+                                       // Manually add leading whitespace removed by IE
+                                       if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+                                               nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+                                       }
+
+                                       // Remove IE's autoinserted <tbody> from table fragments
+                                       if ( !support.tbody ) {
+
+                                               // String was a <table>, *may* have spurious <tbody>
+                                               elem = tag === "table" && !rtbody.test( elem ) ?
+                                                       tmp.firstChild :
+
+                                                       // String was a bare <thead> or <tfoot>
+                                                       wrap[1] === "<table>" && !rtbody.test( elem ) ?
+                                                               tmp :
+                                                               0;
+
+                                               j = elem && elem.childNodes.length;
+                                               while ( j-- ) {
+                                                       if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+                                                               elem.removeChild( tbody );
+                                                       }
+                                               }
+                                       }
+
+                                       jQuery.merge( nodes, tmp.childNodes );
+
+                                       // Fix #12392 for WebKit and IE > 9
+                                       tmp.textContent = "";
+
+                                       // Fix #12392 for oldIE
+                                       while ( tmp.firstChild ) {
+                                               tmp.removeChild( tmp.firstChild );
+                                       }
+
+                                       // Remember the top-level container for proper cleanup
+                                       tmp = safe.lastChild;
+                               }
+                       }
+               }
+
+               // Fix #11356: Clear elements from fragment
+               if ( tmp ) {
+                       safe.removeChild( tmp );
+               }
+
+               // Reset defaultChecked for any radios and checkboxes
+               // about to be appended to the DOM in IE 6/7 (#8060)
+               if ( !support.appendChecked ) {
+                       jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+               }
+
+               i = 0;
+               while ( (elem = nodes[ i++ ]) ) {
+
+                       // #4087 - If origin and destination elements are the same, and this is
+                       // that element, do not do anything
+                       if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+                               continue;
+                       }
+
+                       contains = jQuery.contains( elem.ownerDocument, elem );
+
+                       // Append to fragment
+                       tmp = getAll( safe.appendChild( elem ), "script" );
+
+                       // Preserve script evaluation history
+                       if ( contains ) {
+                               setGlobalEval( tmp );
+                       }
+
+                       // Capture executables
+                       if ( scripts ) {
+                               j = 0;
+                               while ( (elem = tmp[ j++ ]) ) {
+                                       if ( rscriptType.test( elem.type || "" ) ) {
+                                               scripts.push( elem );
+                                       }
+                               }
+                       }
+               }
+
+               tmp = null;
+
+               return safe;
+       },
+
+       cleanData: function( elems, /* internal */ acceptData ) {
+               var elem, type, id, data,
+                       i = 0,
+                       internalKey = jQuery.expando,
+                       cache = jQuery.cache,
+                       deleteExpando = support.deleteExpando,
+                       special = jQuery.event.special;
+
+               for ( ; (elem = elems[i]) != null; i++ ) {
+                       if ( acceptData || jQuery.acceptData( elem ) ) {
+
+                               id = elem[ internalKey ];
+                               data = id && cache[ id ];
+
+                               if ( data ) {
+                                       if ( data.events ) {
+                                               for ( type in data.events ) {
+                                                       if ( special[ type ] ) {
+                                                               jQuery.event.remove( elem, type );
+
+                                                       // This is a shortcut to avoid jQuery.event.remove's overhead
+                                                       } else {
+                                                               jQuery.removeEvent( elem, type, data.handle );
+                                                       }
+                                               }
+                                       }
+
+                                       // Remove cache only if it was not already removed by jQuery.event.remove
+                                       if ( cache[ id ] ) {
+
+                                               delete cache[ id ];
+
+                                               // IE does not allow us to delete expando properties from nodes,
+                                               // nor does it have a removeAttribute function on Document nodes;
+                                               // we must handle all of these cases
+                                               if ( deleteExpando ) {
+                                                       delete elem[ internalKey ];
+
+                                               } else if ( typeof elem.removeAttribute !== strundefined ) {
+                                                       elem.removeAttribute( internalKey );
+
+                                               } else {
+                                                       elem[ internalKey ] = null;
+                                               }
+
+                                               deletedIds.push( id );
+                                       }
+                               }
+                       }
+               }
+       }
+});
+
+jQuery.fn.extend({
+       text: function( value ) {
+               return access( this, function( value ) {
+                       return value === undefined ?
+                               jQuery.text( this ) :
+                               this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+               }, null, value, arguments.length );
+       },
+
+       append: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.appendChild( elem );
+                       }
+               });
+       },
+
+       prepend: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.insertBefore( elem, target.firstChild );
+                       }
+               });
+       },
+
+       before: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this );
+                       }
+               });
+       },
+
+       after: function() {
+               return this.domManip( arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this.nextSibling );
+                       }
+               });
+       },
+
+       remove: function( selector, keepData /* Internal Use Only */ ) {
+               var elem,
+                       elems = selector ? jQuery.filter( selector, this ) : this,
+                       i = 0;
+
+               for ( ; (elem = elems[i]) != null; i++ ) {
+
+                       if ( !keepData && elem.nodeType === 1 ) {
+                               jQuery.cleanData( getAll( elem ) );
+                       }
+
+                       if ( elem.parentNode ) {
+                               if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+                                       setGlobalEval( getAll( elem, "script" ) );
+                               }
+                               elem.parentNode.removeChild( elem );
+                       }
+               }
+
+               return this;
+       },
+
+       empty: function() {
+               var elem,
+                       i = 0;
+
+               for ( ; (elem = this[i]) != null; i++ ) {
+                       // Remove element nodes and prevent memory leaks
+                       if ( elem.nodeType === 1 ) {
+                               jQuery.cleanData( getAll( elem, false ) );
+                       }
+
+                       // Remove any remaining nodes
+                       while ( elem.firstChild ) {
+                               elem.removeChild( elem.firstChild );
+                       }
+
+                       // If this is a select, ensure that it displays empty (#12336)
+                       // Support: IE<9
+                       if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+                               elem.options.length = 0;
+                       }
+               }
+
+               return this;
+       },
+
+       clone: function( dataAndEvents, deepDataAndEvents ) {
+               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+               return this.map(function() {
+                       return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+               });
+       },
+
+       html: function( value ) {
+               return access( this, function( value ) {
+                       var elem = this[ 0 ] || {},
+                               i = 0,
+                               l = this.length;
+
+                       if ( value === undefined ) {
+                               return elem.nodeType === 1 ?
+                                       elem.innerHTML.replace( rinlinejQuery, "" ) :
+                                       undefined;
+                       }
+
+                       // See if we can take a shortcut and just use innerHTML
+                       if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+                               ( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
+                               ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+                               !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+                               value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+                               try {
+                                       for (; i < l; i++ ) {
+                                               // Remove element nodes and prevent memory leaks
+                                               elem = this[i] || {};
+                                               if ( elem.nodeType === 1 ) {
+                                                       jQuery.cleanData( getAll( elem, false ) );
+                                                       elem.innerHTML = value;
+                                               }
+                                       }
+
+                                       elem = 0;
+
+                               // If using innerHTML throws an exception, use the fallback method
+                               } catch(e) {}
+                       }
+
+                       if ( elem ) {
+                               this.empty().append( value );
+                       }
+               }, null, value, arguments.length );
+       },
+
+       replaceWith: function() {
+               var arg = arguments[ 0 ];
+
+               // Make the changes, replacing each context element with the new content
+               this.domManip( arguments, function( elem ) {
+                       arg = this.parentNode;
+
+                       jQuery.cleanData( getAll( this ) );
+
+                       if ( arg ) {
+                               arg.replaceChild( elem, this );
+                       }
+               });
+
+               // Force removal if there was no new content (e.g., from empty arguments)
+               return arg && (arg.length || arg.nodeType) ? this : this.remove();
+       },
+
+       detach: function( selector ) {
+               return this.remove( selector, true );
+       },
+
+       domManip: function( args, callback ) {
+
+               // Flatten any nested arrays
+               args = concat.apply( [], args );
+
+               var first, node, hasScripts,
+                       scripts, doc, fragment,
+                       i = 0,
+                       l = this.length,
+                       set = this,
+                       iNoClone = l - 1,
+                       value = args[0],
+                       isFunction = jQuery.isFunction( value );
+
+               // We can't cloneNode fragments that contain checked, in WebKit
+               if ( isFunction ||
+                               ( l > 1 && typeof value === "string" &&
+                                       !support.checkClone && rchecked.test( value ) ) ) {
+                       return this.each(function( index ) {
+                               var self = set.eq( index );
+                               if ( isFunction ) {
+                                       args[0] = value.call( this, index, self.html() );
+                               }
+                               self.domManip( args, callback );
+                       });
+               }
+
+               if ( l ) {
+                       fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+                       first = fragment.firstChild;
+
+                       if ( fragment.childNodes.length === 1 ) {
+                               fragment = first;
+                       }
+
+                       if ( first ) {
+                               scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+                               hasScripts = scripts.length;
+
+                               // Use the original fragment for the last item instead of the first because it can end up
+                               // being emptied incorrectly in certain situations (#8070).
+                               for ( ; i < l; i++ ) {
+                                       node = fragment;
+
+                                       if ( i !== iNoClone ) {
+                                               node = jQuery.clone( node, true, true );
+
+                                               // Keep references to cloned scripts for later restoration
+                                               if ( hasScripts ) {
+                                                       jQuery.merge( scripts, getAll( node, "script" ) );
+                                               }
+                                       }
+
+                                       callback.call( this[i], node, i );
+                               }
+
+                               if ( hasScripts ) {
+                                       doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+                                       // Reenable scripts
+                                       jQuery.map( scripts, restoreScript );
+
+                                       // Evaluate executable scripts on first document insertion
+                                       for ( i = 0; i < hasScripts; i++ ) {
+                                               node = scripts[ i ];
+                                               if ( rscriptType.test( node.type || "" ) &&
+                                                       !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+                                                       if ( node.src ) {
+                                                               // Optional AJAX dependency, but won't run scripts if not present
+                                                               if ( jQuery._evalUrl ) {
+                                                                       jQuery._evalUrl( node.src );
+                                                               }
+                                                       } else {
+                                                               jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Fix #11809: Avoid leaking memory
+                               fragment = first = null;
+                       }
+               }
+
+               return this;
+       }
+});
+
+jQuery.each({
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function( name, original ) {
+       jQuery.fn[ name ] = function( selector ) {
+               var elems,
+                       i = 0,
+                       ret = [],
+                       insert = jQuery( selector ),
+                       last = insert.length - 1;
+
+               for ( ; i <= last; i++ ) {
+                       elems = i === last ? this : this.clone(true);
+                       jQuery( insert[i] )[ original ]( elems );
+
+                       // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+                       push.apply( ret, elems.get() );
+               }
+
+               return this.pushStack( ret );
+       };
+});
+
+
+var iframe,
+       elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+       var style,
+               elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+               // getDefaultComputedStyle might be reliably used only on attached element
+               display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+                       // Use of this method is a temporary fix (more like optmization) until something better comes along,
+                       // since it was removed from specification and supported only in FF
+                       style.display : jQuery.css( elem[ 0 ], "display" );
+
+       // We don't have any data stored on the element,
+       // so use "detach" method as fast way to get rid of the element
+       elem.detach();
+
+       return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+       var doc = document,
+               display = elemdisplay[ nodeName ];
+
+       if ( !display ) {
+               display = actualDisplay( nodeName, doc );
+
+               // If the simple way fails, read from inside an iframe
+               if ( display === "none" || !display ) {
+
+                       // Use the already-created iframe if possible
+                       iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
+
+                       // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+                       doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+                       // Support: IE
+                       doc.write();
+                       doc.close();
+
+                       display = actualDisplay( nodeName, doc );
+                       iframe.detach();
+               }
+
+               // Store the correct default display
+               elemdisplay[ nodeName ] = display;
+       }
+
+       return display;
+}
+
+
+(function() {
+       var shrinkWrapBlocksVal;
+
+       support.shrinkWrapBlocks = function() {
+               if ( shrinkWrapBlocksVal != null ) {
+                       return shrinkWrapBlocksVal;
+               }
+
+               // Will be changed later if needed.
+               shrinkWrapBlocksVal = false;
+
+               // Minified: var b,c,d
+               var div, body, container;
+
+               body = document.getElementsByTagName( "body" )[ 0 ];
+               if ( !body || !body.style ) {
+                       // Test fired too early or in an unsupported environment, exit.
+                       return;
+               }
+
+               // Setup
+               div = document.createElement( "div" );
+               container = document.createElement( "div" );
+               container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+               body.appendChild( container ).appendChild( div );
+
+               // Support: IE6
+               // Check if elements with layout shrink-wrap their children
+               if ( typeof div.style.zoom !== strundefined ) {
+                       // Reset CSS: box-sizing; display; margin; border
+                       div.style.cssText =
+                               // Support: Firefox<29, Android 2.3
+                               // Vendor-prefix box-sizing
+                               "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+                               "box-sizing:content-box;display:block;margin:0;border:0;" +
+                               "padding:1px;width:1px;zoom:1";
+                       div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+                       shrinkWrapBlocksVal = div.offsetWidth !== 3;
+               }
+
+               body.removeChild( container );
+
+               return shrinkWrapBlocksVal;
+       };
+
+})();
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+
+
+var getStyles, curCSS,
+       rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+       getStyles = function( elem ) {
+               return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+       };
+
+       curCSS = function( elem, name, computed ) {
+               var width, minWidth, maxWidth, ret,
+                       style = elem.style;
+
+               computed = computed || getStyles( elem );
+
+               // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+               ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+               if ( computed ) {
+
+                       if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+                               ret = jQuery.style( elem, name );
+                       }
+
+                       // A tribute to the "awesome hack by Dean Edwards"
+                       // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+                       // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+                       // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+                       if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+                               // Remember the original values
+                               width = style.width;
+                               minWidth = style.minWidth;
+                               maxWidth = style.maxWidth;
+
+                               // Put in the new values to get a computed value out
+                               style.minWidth = style.maxWidth = style.width = ret;
+                               ret = computed.width;
+
+                               // Revert the changed values
+                               style.width = width;
+                               style.minWidth = minWidth;
+                               style.maxWidth = maxWidth;
+                       }
+               }
+
+               // Support: IE
+               // IE returns zIndex value as an integer.
+               return ret === undefined ?
+                       ret :
+                       ret + "";
+       };
+} else if ( document.documentElement.currentStyle ) {
+       getStyles = function( elem ) {
+               return elem.currentStyle;
+       };
+
+       curCSS = function( elem, name, computed ) {
+               var left, rs, rsLeft, ret,
+                       style = elem.style;
+
+               computed = computed || getStyles( elem );
+               ret = computed ? computed[ name ] : undefined;
+
+               // Avoid setting ret to empty string here
+               // so we don't default to auto
+               if ( ret == null && style && style[ name ] ) {
+                       ret = style[ name ];
+               }
+
+               // From the awesome hack by Dean Edwards
+               // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+               // If we're not dealing with a regular pixel number
+               // but a number that has a weird ending, we need to convert it to pixels
+               // but not position css attributes, as those are proportional to the parent element instead
+               // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+               if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+                       // Remember the original values
+                       left = style.left;
+                       rs = elem.runtimeStyle;
+                       rsLeft = rs && rs.left;
+
+                       // Put in the new values to get a computed value out
+                       if ( rsLeft ) {
+                               rs.left = elem.currentStyle.left;
+                       }
+                       style.left = name === "fontSize" ? "1em" : ret;
+                       ret = style.pixelLeft + "px";
+
+                       // Revert the changed values
+                       style.left = left;
+                       if ( rsLeft ) {
+                               rs.left = rsLeft;
+                       }
+               }
+
+               // Support: IE
+               // IE returns zIndex value as an integer.
+               return ret === undefined ?
+                       ret :
+                       ret + "" || "auto";
+       };
+}
+
+
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+       // Define the hook, we'll check on the first run if it's really needed.
+       return {
+               get: function() {
+                       var condition = conditionFn();
+
+                       if ( condition == null ) {
+                               // The test was not ready at this point; screw the hook this time
+                               // but check again when needed next time.
+                               return;
+                       }
+
+                       if ( condition ) {
+                               // Hook not needed (or it's not possible to use it due to missing dependency),
+                               // remove it.
+                               // Since there are no other hooks for marginRight, remove the whole object.
+                               delete this.get;
+                               return;
+                       }
+
+                       // Hook needed; redefine it so that the support test is not executed again.
+
+                       return (this.get = hookFn).apply( this, arguments );
+               }
+       };
+}
+
+
+(function() {
+       // Minified: var b,c,d,e,f,g, h,i
+       var div, style, a, pixelPositionVal, boxSizingReliableVal,
+               reliableHiddenOffsetsVal, reliableMarginRightVal;
+
+       // Setup
+       div = document.createElement( "div" );
+       div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+       a = div.getElementsByTagName( "a" )[ 0 ];
+       style = a && a.style;
+
+       // Finish early in limited (non-browser) environments
+       if ( !style ) {
+               return;
+       }
+
+       style.cssText = "float:left;opacity:.5";
+
+       // Support: IE<9
+       // Make sure that element opacity exists (as opposed to filter)
+       support.opacity = style.opacity === "0.5";
+
+       // Verify style float existence
+       // (IE uses styleFloat instead of cssFloat)
+       support.cssFloat = !!style.cssFloat;
+
+       div.style.backgroundClip = "content-box";
+       div.cloneNode( true ).style.backgroundClip = "";
+       support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+       // Support: Firefox<29, Android 2.3
+       // Vendor-prefix box-sizing
+       support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
+               style.WebkitBoxSizing === "";
+
+       jQuery.extend(support, {
+               reliableHiddenOffsets: function() {
+                       if ( reliableHiddenOffsetsVal == null ) {
+                               computeStyleTests();
+                       }
+                       return reliableHiddenOffsetsVal;
+               },
+
+               boxSizingReliable: function() {
+                       if ( boxSizingReliableVal == null ) {
+                               computeStyleTests();
+                       }
+                       return boxSizingReliableVal;
+               },
+
+               pixelPosition: function() {
+                       if ( pixelPositionVal == null ) {
+                               computeStyleTests();
+                       }
+                       return pixelPositionVal;
+               },
+
+               // Support: Android 2.3
+               reliableMarginRight: function() {
+                       if ( reliableMarginRightVal == null ) {
+                               computeStyleTests();
+                       }
+                       return reliableMarginRightVal;
+               }
+       });
+
+       function computeStyleTests() {
+               // Minified: var b,c,d,j
+               var div, body, container, contents;
+
+               body = document.getElementsByTagName( "body" )[ 0 ];
+               if ( !body || !body.style ) {
+                       // Test fired too early or in an unsupported environment, exit.
+                       return;
+               }
+
+               // Setup
+               div = document.createElement( "div" );
+               container = document.createElement( "div" );
+               container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+               body.appendChild( container ).appendChild( div );
+
+               div.style.cssText =
+                       // Support: Firefox<29, Android 2.3
+                       // Vendor-prefix box-sizing
+                       "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+                       "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+                       "border:1px;padding:1px;width:4px;position:absolute";
+
+               // Support: IE<9
+               // Assume reasonable values in the absence of getComputedStyle
+               pixelPositionVal = boxSizingReliableVal = false;
+               reliableMarginRightVal = true;
+
+               // Check for getComputedStyle so that this code is not run in IE<9.
+               if ( window.getComputedStyle ) {
+                       pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+                       boxSizingReliableVal =
+                               ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+                       // Support: Android 2.3
+                       // Div with explicit width and no margin-right incorrectly
+                       // gets computed margin-right based on width of container (#3333)
+                       // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                       contents = div.appendChild( document.createElement( "div" ) );
+
+                       // Reset CSS: box-sizing; display; margin; border; padding
+                       contents.style.cssText = div.style.cssText =
+                               // Support: Firefox<29, Android 2.3
+                               // Vendor-prefix box-sizing
+                               "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+                               "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+                       contents.style.marginRight = contents.style.width = "0";
+                       div.style.width = "1px";
+
+                       reliableMarginRightVal =
+                               !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
+               }
+
+               // Support: IE8
+               // Check if table cells still have offsetWidth/Height when they are set
+               // to display:none and there are still other visible table cells in a
+               // table row; if so, offsetWidth/Height are not reliable for use when
+               // determining if an element has been hidden directly using
+               // display:none (it is still safe to use offsets if a parent element is
+               // hidden; don safety goggles and see bug #4512 for more information).
+               div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+               contents = div.getElementsByTagName( "td" );
+               contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
+               reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+               if ( reliableHiddenOffsetsVal ) {
+                       contents[ 0 ].style.display = "";
+                       contents[ 1 ].style.display = "none";
+                       reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+               }
+
+               body.removeChild( container );
+       }
+
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+       var ret, name,
+               old = {};
+
+       // Remember the old values, and insert the new ones
+       for ( name in options ) {
+               old[ name ] = elem.style[ name ];
+               elem.style[ name ] = options[ name ];
+       }
+
+       ret = callback.apply( elem, args || [] );
+
+       // Revert the old values
+       for ( name in options ) {
+               elem.style[ name ] = old[ name ];
+       }
+
+       return ret;
+};
+
+
+var
+               ralpha = /alpha\([^)]*\)/i,
+       ropacity = /opacity\s*=\s*([^)]*)/,
+
+       // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+       // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+       rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+       rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+       rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+       cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+       cssNormalTransform = {
+               letterSpacing: "0",
+               fontWeight: "400"
+       },
+
+       cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+       // shortcut for names that are not vendor prefixed
+       if ( name in style ) {
+               return name;
+       }
+
+       // check for vendor prefixed names
+       var capName = name.charAt(0).toUpperCase() + name.slice(1),
+               origName = name,
+               i = cssPrefixes.length;
+
+       while ( i-- ) {
+               name = cssPrefixes[ i ] + capName;
+               if ( name in style ) {
+                       return name;
+               }
+       }
+
+       return origName;
+}
+
+function showHide( elements, show ) {
+       var display, elem, hidden,
+               values = [],
+               index = 0,
+               length = elements.length;
+
+       for ( ; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+
+               values[ index ] = jQuery._data( elem, "olddisplay" );
+               display = elem.style.display;
+               if ( show ) {
+                       // Reset the inline display of this element to learn if it is
+                       // being hidden by cascaded rules or not
+                       if ( !values[ index ] && display === "none" ) {
+                               elem.style.display = "";
+                       }
+
+                       // Set elements which have been overridden with display: none
+                       // in a stylesheet to whatever the default browser style is
+                       // for such an element
+                       if ( elem.style.display === "" && isHidden( elem ) ) {
+                               values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+                       }
+               } else {
+                       hidden = isHidden( elem );
+
+                       if ( display && display !== "none" || !hidden ) {
+                               jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+                       }
+               }
+       }
+
+       // Set the display of most of the elements in a second loop
+       // to avoid the constant reflow
+       for ( index = 0; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+               if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+                       elem.style.display = show ? values[ index ] || "" : "none";
+               }
+       }
+
+       return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+       var matches = rnumsplit.exec( value );
+       return matches ?
+               // Guard against undefined "subtract", e.g., when used as in cssHooks
+               Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+               value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+       var i = extra === ( isBorderBox ? "border" : "content" ) ?
+               // If we already have the right measurement, avoid augmentation
+               4 :
+               // Otherwise initialize for horizontal or vertical properties
+               name === "width" ? 1 : 0,
+
+               val = 0;
+
+       for ( ; i < 4; i += 2 ) {
+               // both box models exclude margin, so add it if we want it
+               if ( extra === "margin" ) {
+                       val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+               }
+
+               if ( isBorderBox ) {
+                       // border-box includes padding, so remove it if we want content
+                       if ( extra === "content" ) {
+                               val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+                       }
+
+                       // at this point, extra isn't border nor margin, so remove border
+                       if ( extra !== "margin" ) {
+                               val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+               } else {
+                       // at this point, extra isn't content, so add padding
+                       val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+                       // at this point, extra isn't content nor padding, so add border
+                       if ( extra !== "padding" ) {
+                               val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+               }
+       }
+
+       return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+       // Start with offset property, which is equivalent to the border-box value
+       var valueIsBorderBox = true,
+               val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+               styles = getStyles( elem ),
+               isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+       // some non-html elements return undefined for offsetWidth, so check for null/undefined
+       // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+       // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+       if ( val <= 0 || val == null ) {
+               // Fall back to computed then uncomputed css if necessary
+               val = curCSS( elem, name, styles );
+               if ( val < 0 || val == null ) {
+                       val = elem.style[ name ];
+               }
+
+               // Computed unit is not pixels. Stop here and return.
+               if ( rnumnonpx.test(val) ) {
+                       return val;
+               }
+
+               // we need the check for style in case a browser which returns unreliable values
+               // for getComputedStyle silently falls back to the reliable elem.style
+               valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+               // Normalize "", auto, and prepare for extra
+               val = parseFloat( val ) || 0;
+       }
+
+       // use the active box-sizing model to add/subtract irrelevant styles
+       return ( val +
+               augmentWidthOrHeight(
+                       elem,
+                       name,
+                       extra || ( isBorderBox ? "border" : "content" ),
+                       valueIsBorderBox,
+                       styles
+               )
+       ) + "px";
+}
+
+jQuery.extend({
+       // Add in style property hooks for overriding the default
+       // behavior of getting and setting a style property
+       cssHooks: {
+               opacity: {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+                                       // We should always get a number back from opacity
+                                       var ret = curCSS( elem, "opacity" );
+                                       return ret === "" ? "1" : ret;
+                               }
+                       }
+               }
+       },
+
+       // Don't automatically add "px" to these possibly-unitless properties
+       cssNumber: {
+               "columnCount": true,
+               "fillOpacity": true,
+               "flexGrow": true,
+               "flexShrink": true,
+               "fontWeight": true,
+               "lineHeight": true,
+               "opacity": true,
+               "order": true,
+               "orphans": true,
+               "widows": true,
+               "zIndex": true,
+               "zoom": true
+       },
+
+       // Add in properties whose names you wish to fix before
+       // setting or getting the value
+       cssProps: {
+               // normalize float css property
+               "float": support.cssFloat ? "cssFloat" : "styleFloat"
+       },
+
+       // Get and set the style property on a DOM Node
+       style: function( elem, name, value, extra ) {
+               // Don't set styles on text and comment nodes
+               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+                       return;
+               }
+
+               // Make sure that we're working with the right name
+               var ret, type, hooks,
+                       origName = jQuery.camelCase( name ),
+                       style = elem.style;
+
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // Check if we're setting a value
+               if ( value !== undefined ) {
+                       type = typeof value;
+
+                       // convert relative number strings (+= or -=) to relative numbers. #7345
+                       if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+                               value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+                               // Fixes bug #9237
+                               type = "number";
+                       }
+
+                       // Make sure that null and NaN values aren't set. See: #7116
+                       if ( value == null || value !== value ) {
+                               return;
+                       }
+
+                       // If a number was passed in, add 'px' to the (except for certain CSS properties)
+                       if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+                               value += "px";
+                       }
+
+                       // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+                       // but it would mean to define eight (for every problematic property) identical functions
+                       if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+                               style[ name ] = "inherit";
+                       }
+
+                       // If a hook was provided, use that value, otherwise just set the specified value
+                       if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+                               // Support: IE
+                               // Swallow errors from 'invalid' CSS values (#5509)
+                               try {
+                                       style[ name ] = value;
+                               } catch(e) {}
+                       }
+
+               } else {
+                       // If a hook was provided get the non-computed value from there
+                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+                               return ret;
+                       }
+
+                       // Otherwise just get the value from the style object
+                       return style[ name ];
+               }
+       },
+
+       css: function( elem, name, extra, styles ) {
+               var num, val, hooks,
+                       origName = jQuery.camelCase( name );
+
+               // Make sure that we're working with the right name
+               name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+               // gets hook for the prefixed version
+               // followed by the unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // If a hook was provided get the computed value from there
+               if ( hooks && "get" in hooks ) {
+                       val = hooks.get( elem, true, extra );
+               }
+
+               // Otherwise, if a way to get the computed value exists, use that
+               if ( val === undefined ) {
+                       val = curCSS( elem, name, styles );
+               }
+
+               //convert "normal" to computed value
+               if ( val === "normal" && name in cssNormalTransform ) {
+                       val = cssNormalTransform[ name ];
+               }
+
+               // Return, converting to number if forced or a qualifier was provided and val looks numeric
+               if ( extra === "" || extra ) {
+                       num = parseFloat( val );
+                       return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+               }
+               return val;
+       }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+       jQuery.cssHooks[ name ] = {
+               get: function( elem, computed, extra ) {
+                       if ( computed ) {
+                               // certain elements can have dimension info if we invisibly show them
+                               // however, it must have a current display style that would benefit from this
+                               return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+                                       jQuery.swap( elem, cssShow, function() {
+                                               return getWidthOrHeight( elem, name, extra );
+                                       }) :
+                                       getWidthOrHeight( elem, name, extra );
+                       }
+               },
+
+               set: function( elem, value, extra ) {
+                       var styles = extra && getStyles( elem );
+                       return setPositiveNumber( elem, value, extra ?
+                               augmentWidthOrHeight(
+                                       elem,
+                                       name,
+                                       extra,
+                                       support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+                                       styles
+                               ) : 0
+                       );
+               }
+       };
+});
+
+if ( !support.opacity ) {
+       jQuery.cssHooks.opacity = {
+               get: function( elem, computed ) {
+                       // IE uses filters for opacity
+                       return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+                               ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+                               computed ? "1" : "";
+               },
+
+               set: function( elem, value ) {
+                       var style = elem.style,
+                               currentStyle = elem.currentStyle,
+                               opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+                               filter = currentStyle && currentStyle.filter || style.filter || "";
+
+                       // IE has trouble with opacity if it does not have layout
+                       // Force it by setting the zoom level
+                       style.zoom = 1;
+
+                       // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+                       // if value === "", then remove inline opacity #12685
+                       if ( ( value >= 1 || value === "" ) &&
+                                       jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+                                       style.removeAttribute ) {
+
+                               // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+                               // if "filter:" is present at all, clearType is disabled, we want to avoid this
+                               // style.removeAttribute is IE Only, but so apparently is this code path...
+                               style.removeAttribute( "filter" );
+
+                               // if there is no filter style applied in a css rule or unset inline opacity, we are done
+                               if ( value === "" || currentStyle && !currentStyle.filter ) {
+                                       return;
+                               }
+                       }
+
+                       // otherwise, set new filter values
+                       style.filter = ralpha.test( filter ) ?
+                               filter.replace( ralpha, opacity ) :
+                               filter + " " + opacity;
+               }
+       };
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+       function( elem, computed ) {
+               if ( computed ) {
+                       // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                       // Work around by temporarily setting element display to inline-block
+                       return jQuery.swap( elem, { "display": "inline-block" },
+                               curCSS, [ elem, "marginRight" ] );
+               }
+       }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+       margin: "",
+       padding: "",
+       border: "Width"
+}, function( prefix, suffix ) {
+       jQuery.cssHooks[ prefix + suffix ] = {
+               expand: function( value ) {
+                       var i = 0,
+                               expanded = {},
+
+                               // assumes a single number if not a string
+                               parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+                       for ( ; i < 4; i++ ) {
+                               expanded[ prefix + cssExpand[ i ] + suffix ] =
+                                       parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+                       }
+
+                       return expanded;
+               }
+       };
+
+       if ( !rmargin.test( prefix ) ) {
+               jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+       }
+});
+
+jQuery.fn.extend({
+       css: function( name, value ) {
+               return access( this, function( elem, name, value ) {
+                       var styles, len,
+                               map = {},
+                               i = 0;
+
+                       if ( jQuery.isArray( name ) ) {
+                               styles = getStyles( elem );
+                               len = name.length;
+
+                               for ( ; i < len; i++ ) {
+                                       map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+                               }
+
+                               return map;
+                       }
+
+                       return value !== undefined ?
+                               jQuery.style( elem, name, value ) :
+                               jQuery.css( elem, name );
+               }, name, value, arguments.length > 1 );
+       },
+       show: function() {
+               return showHide( this, true );
+       },
+       hide: function() {
+               return showHide( this );
+       },
+       toggle: function( state ) {
+               if ( typeof state === "boolean" ) {
+                       return state ? this.show() : this.hide();
+               }
+
+               return this.each(function() {
+                       if ( isHidden( this ) ) {
+                               jQuery( this ).show();
+                       } else {
+                               jQuery( this ).hide();
+                       }
+               });
+       }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+       return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+       constructor: Tween,
+       init: function( elem, options, prop, end, easing, unit ) {
+               this.elem = elem;
+               this.prop = prop;
+               this.easing = easing || "swing";
+               this.options = options;
+               this.start = this.now = this.cur();
+               this.end = end;
+               this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+       },
+       cur: function() {
+               var hooks = Tween.propHooks[ this.prop ];
+
+               return hooks && hooks.get ?
+                       hooks.get( this ) :
+                       Tween.propHooks._default.get( this );
+       },
+       run: function( percent ) {
+               var eased,
+                       hooks = Tween.propHooks[ this.prop ];
+
+               if ( this.options.duration ) {
+                       this.pos = eased = jQuery.easing[ this.easing ](
+                               percent, this.options.duration * percent, 0, 1, this.options.duration
+                       );
+               } else {
+                       this.pos = eased = percent;
+               }
+               this.now = ( this.end - this.start ) * eased + this.start;
+
+               if ( this.options.step ) {
+                       this.options.step.call( this.elem, this.now, this );
+               }
+
+               if ( hooks && hooks.set ) {
+                       hooks.set( this );
+               } else {
+                       Tween.propHooks._default.set( this );
+               }
+               return this;
+       }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+       _default: {
+               get: function( tween ) {
+                       var result;
+
+                       if ( tween.elem[ tween.prop ] != null &&
+                               (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+                               return tween.elem[ tween.prop ];
+                       }
+
+                       // passing an empty string as a 3rd parameter to .css will automatically
+                       // attempt a parseFloat and fallback to a string if the parse fails
+                       // so, simple values such as "10px" are parsed to Float.
+                       // complex values such as "rotate(1rad)" are returned as is.
+                       result = jQuery.css( tween.elem, tween.prop, "" );
+                       // Empty strings, null, undefined and "auto" are converted to 0.
+                       return !result || result === "auto" ? 0 : result;
+               },
+               set: function( tween ) {
+                       // use step hook for back compat - use cssHook if its there - use .style if its
+                       // available and use plain properties where available
+                       if ( jQuery.fx.step[ tween.prop ] ) {
+                               jQuery.fx.step[ tween.prop ]( tween );
+                       } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+                               jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+                       } else {
+                               tween.elem[ tween.prop ] = tween.now;
+                       }
+               }
+       }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+       set: function( tween ) {
+               if ( tween.elem.nodeType && tween.elem.parentNode ) {
+                       tween.elem[ tween.prop ] = tween.now;
+               }
+       }
+};
+
+jQuery.easing = {
+       linear: function( p ) {
+               return p;
+       },
+       swing: function( p ) {
+               return 0.5 - Math.cos( p * Math.PI ) / 2;
+       }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+       fxNow, timerId,
+       rfxtypes = /^(?:toggle|show|hide)$/,
+       rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+       rrun = /queueHooks$/,
+       animationPrefilters = [ defaultPrefilter ],
+       tweeners = {
+               "*": [ function( prop, value ) {
+                       var tween = this.createTween( prop, value ),
+                               target = tween.cur(),
+                               parts = rfxnum.exec( value ),
+                               unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+                               // Starting value computation is required for potential unit mismatches
+                               start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+                                       rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+                               scale = 1,
+                               maxIterations = 20;
+
+                       if ( start && start[ 3 ] !== unit ) {
+                               // Trust units reported by jQuery.css
+                               unit = unit || start[ 3 ];
+
+                               // Make sure we update the tween properties later on
+                               parts = parts || [];
+
+                               // Iteratively approximate from a nonzero starting point
+                               start = +target || 1;
+
+                               do {
+                                       // If previous iteration zeroed out, double until we get *something*
+                                       // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+                                       scale = scale || ".5";
+
+                                       // Adjust and apply
+                                       start = start / scale;
+                                       jQuery.style( tween.elem, prop, start + unit );
+
+                               // Update scale, tolerating zero or NaN from tween.cur()
+                               // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+                               } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+                       }
+
+                       // Update tween properties
+                       if ( parts ) {
+                               start = tween.start = +start || +target || 0;
+                               tween.unit = unit;
+                               // If a +=/-= token was provided, we're doing a relative animation
+                               tween.end = parts[ 1 ] ?
+                                       start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+                                       +parts[ 2 ];
+                       }
+
+                       return tween;
+               } ]
+       };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+       setTimeout(function() {
+               fxNow = undefined;
+       });
+       return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+       var which,
+               attrs = { height: type },
+               i = 0;
+
+       // if we include width, step value is 1 to do all cssExpand values,
+       // if we don't include width, step value is 2 to skip over Left and Right
+       includeWidth = includeWidth ? 1 : 0;
+       for ( ; i < 4 ; i += 2 - includeWidth ) {
+               which = cssExpand[ i ];
+               attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+       }
+
+       if ( includeWidth ) {
+               attrs.opacity = attrs.width = type;
+       }
+
+       return attrs;
+}
+
+function createTween( value, prop, animation ) {
+       var tween,
+               collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+               index = 0,
+               length = collection.length;
+       for ( ; index < length; index++ ) {
+               if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+                       // we're done with this property
+                       return tween;
+               }
+       }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+       /* jshint validthis: true */
+       var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+               anim = this,
+               orig = {},
+               style = elem.style,
+               hidden = elem.nodeType && isHidden( elem ),
+               dataShow = jQuery._data( elem, "fxshow" );
+
+       // handle queue: false promises
+       if ( !opts.queue ) {
+               hooks = jQuery._queueHooks( elem, "fx" );
+               if ( hooks.unqueued == null ) {
+                       hooks.unqueued = 0;
+                       oldfire = hooks.empty.fire;
+                       hooks.empty.fire = function() {
+                               if ( !hooks.unqueued ) {
+                                       oldfire();
+                               }
+                       };
+               }
+               hooks.unqueued++;
+
+               anim.always(function() {
+                       // doing this makes sure that the complete handler will be called
+                       // before this completes
+                       anim.always(function() {
+                               hooks.unqueued--;
+                               if ( !jQuery.queue( elem, "fx" ).length ) {
+                                       hooks.empty.fire();
+                               }
+                       });
+               });
+       }
+
+       // height/width overflow pass
+       if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+               // Make sure that nothing sneaks out
+               // Record all 3 overflow attributes because IE does not
+               // change the overflow attribute when overflowX and
+               // overflowY are set to the same value
+               opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+               // Set display property to inline-block for height/width
+               // animations on inline elements that are having width/height animated
+               display = jQuery.css( elem, "display" );
+
+               // Test default display if display is currently "none"
+               checkDisplay = display === "none" ?
+                       jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+               if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+
+                       // inline-level elements accept inline-block;
+                       // block-level elements need to be inline with layout
+                       if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
+                               style.display = "inline-block";
+                       } else {
+                               style.zoom = 1;
+                       }
+               }
+       }
+
+       if ( opts.overflow ) {
+               style.overflow = "hidden";
+               if ( !support.shrinkWrapBlocks() ) {
+                       anim.always(function() {
+                               style.overflow = opts.overflow[ 0 ];
+                               style.overflowX = opts.overflow[ 1 ];
+                               style.overflowY = opts.overflow[ 2 ];
+                       });
+               }
+       }
+
+       // show/hide pass
+       for ( prop in props ) {
+               value = props[ prop ];
+               if ( rfxtypes.exec( value ) ) {
+                       delete props[ prop ];
+                       toggle = toggle || value === "toggle";
+                       if ( value === ( hidden ? "hide" : "show" ) ) {
+
+                               // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+                               if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+                                       hidden = true;
+                               } else {
+                                       continue;
+                               }
+                       }
+                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+               // Any non-fx value stops us from restoring the original display value
+               } else {
+                       display = undefined;
+               }
+       }
+
+       if ( !jQuery.isEmptyObject( orig ) ) {
+               if ( dataShow ) {
+                       if ( "hidden" in dataShow ) {
+                               hidden = dataShow.hidden;
+                       }
+               } else {
+                       dataShow = jQuery._data( elem, "fxshow", {} );
+               }
+
+               // store state if its toggle - enables .stop().toggle() to "reverse"
+               if ( toggle ) {
+                       dataShow.hidden = !hidden;
+               }
+               if ( hidden ) {
+                       jQuery( elem ).show();
+               } else {
+                       anim.done(function() {
+                               jQuery( elem ).hide();
+                       });
+               }
+               anim.done(function() {
+                       var prop;
+                       jQuery._removeData( elem, "fxshow" );
+                       for ( prop in orig ) {
+                               jQuery.style( elem, prop, orig[ prop ] );
+                       }
+               });
+               for ( prop in orig ) {
+                       tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+                       if ( !( prop in dataShow ) ) {
+                               dataShow[ prop ] = tween.start;
+                               if ( hidden ) {
+                                       tween.end = tween.start;
+                                       tween.start = prop === "width" || prop === "height" ? 1 : 0;
+                               }
+                       }
+               }
+
+       // If this is a noop like .hide().hide(), restore an overwritten display value
+       } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+               style.display = display;
+       }
+}
+
+function propFilter( props, specialEasing ) {
+       var index, name, easing, value, hooks;
+
+       // camelCase, specialEasing and expand cssHook pass
+       for ( index in props ) {
+               name = jQuery.camelCase( index );
+               easing = specialEasing[ name ];
+               value = props[ index ];
+               if ( jQuery.isArray( value ) ) {
+                       easing = value[ 1 ];
+                       value = props[ index ] = value[ 0 ];
+               }
+
+               if ( index !== name ) {
+                       props[ name ] = value;
+                       delete props[ index ];
+               }
+
+               hooks = jQuery.cssHooks[ name ];
+               if ( hooks && "expand" in hooks ) {
+                       value = hooks.expand( value );
+                       delete props[ name ];
+
+                       // not quite $.extend, this wont overwrite keys already present.
+                       // also - reusing 'index' from above because we have the correct "name"
+                       for ( index in value ) {
+                               if ( !( index in props ) ) {
+                                       props[ index ] = value[ index ];
+                                       specialEasing[ index ] = easing;
+                               }
+                       }
+               } else {
+                       specialEasing[ name ] = easing;
+               }
+       }
+}
+
+function Animation( elem, properties, options ) {
+       var result,
+               stopped,
+               index = 0,
+               length = animationPrefilters.length,
+               deferred = jQuery.Deferred().always( function() {
+                       // don't match elem in the :animated selector
+                       delete tick.elem;
+               }),
+               tick = function() {
+                       if ( stopped ) {
+                               return false;
+                       }
+                       var currentTime = fxNow || createFxNow(),
+                               remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+                               // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+                               temp = remaining / animation.duration || 0,
+                               percent = 1 - temp,
+                               index = 0,
+                               length = animation.tweens.length;
+
+                       for ( ; index < length ; index++ ) {
+                               animation.tweens[ index ].run( percent );
+                       }
+
+                       deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+                       if ( percent < 1 && length ) {
+                               return remaining;
+                       } else {
+                               deferred.resolveWith( elem, [ animation ] );
+                               return false;
+                       }
+               },
+               animation = deferred.promise({
+                       elem: elem,
+                       props: jQuery.extend( {}, properties ),
+                       opts: jQuery.extend( true, { specialEasing: {} }, options ),
+                       originalProperties: properties,
+                       originalOptions: options,
+                       startTime: fxNow || createFxNow(),
+                       duration: options.duration,
+                       tweens: [],
+                       createTween: function( prop, end ) {
+                               var tween = jQuery.Tween( elem, animation.opts, prop, end,
+                                               animation.opts.specialEasing[ prop ] || animation.opts.easing );
+                               animation.tweens.push( tween );
+                               return tween;
+                       },
+                       stop: function( gotoEnd ) {
+                               var index = 0,
+                                       // if we are going to the end, we want to run all the tweens
+                                       // otherwise we skip this part
+                                       length = gotoEnd ? animation.tweens.length : 0;
+                               if ( stopped ) {
+                                       return this;
+                               }
+                               stopped = true;
+                               for ( ; index < length ; index++ ) {
+                                       animation.tweens[ index ].run( 1 );
+                               }
+
+                               // resolve when we played the last frame
+                               // otherwise, reject
+                               if ( gotoEnd ) {
+                                       deferred.resolveWith( elem, [ animation, gotoEnd ] );
+                               } else {
+                                       deferred.rejectWith( elem, [ animation, gotoEnd ] );
+                               }
+                               return this;
+                       }
+               }),
+               props = animation.props;
+
+       propFilter( props, animation.opts.specialEasing );
+
+       for ( ; index < length ; index++ ) {
+               result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+               if ( result ) {
+                       return result;
+               }
+       }
+
+       jQuery.map( props, createTween, animation );
+
+       if ( jQuery.isFunction( animation.opts.start ) ) {
+               animation.opts.start.call( elem, animation );
+       }
+
+       jQuery.fx.timer(
+               jQuery.extend( tick, {
+                       elem: elem,
+                       anim: animation,
+                       queue: animation.opts.queue
+               })
+       );
+
+       // attach callbacks from options
+       return animation.progress( animation.opts.progress )
+               .done( animation.opts.done, animation.opts.complete )
+               .fail( animation.opts.fail )
+               .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+       tweener: function( props, callback ) {
+               if ( jQuery.isFunction( props ) ) {
+                       callback = props;
+                       props = [ "*" ];
+               } else {
+                       props = props.split(" ");
+               }
+
+               var prop,
+                       index = 0,
+                       length = props.length;
+
+               for ( ; index < length ; index++ ) {
+                       prop = props[ index ];
+                       tweeners[ prop ] = tweeners[ prop ] || [];
+                       tweeners[ prop ].unshift( callback );
+               }
+       },
+
+       prefilter: function( callback, prepend ) {
+               if ( prepend ) {
+                       animationPrefilters.unshift( callback );
+               } else {
+                       animationPrefilters.push( callback );
+               }
+       }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+       var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+               complete: fn || !fn && easing ||
+                       jQuery.isFunction( speed ) && speed,
+               duration: speed,
+               easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+       };
+
+       opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+               opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+       // normalize opt.queue - true/undefined/null -> "fx"
+       if ( opt.queue == null || opt.queue === true ) {
+               opt.queue = "fx";
+       }
+
+       // Queueing
+       opt.old = opt.complete;
+
+       opt.complete = function() {
+               if ( jQuery.isFunction( opt.old ) ) {
+                       opt.old.call( this );
+               }
+
+               if ( opt.queue ) {
+                       jQuery.dequeue( this, opt.queue );
+               }
+       };
+
+       return opt;
+};
+
+jQuery.fn.extend({
+       fadeTo: function( speed, to, easing, callback ) {
+
+               // show any hidden elements after setting opacity to 0
+               return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+                       // animate to the value specified
+                       .end().animate({ opacity: to }, speed, easing, callback );
+       },
+       animate: function( prop, speed, easing, callback ) {
+               var empty = jQuery.isEmptyObject( prop ),
+                       optall = jQuery.speed( speed, easing, callback ),
+                       doAnimation = function() {
+                               // Operate on a copy of prop so per-property easing won't be lost
+                               var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+                               // Empty animations, or finishing resolves immediately
+                               if ( empty || jQuery._data( this, "finish" ) ) {
+                                       anim.stop( true );
+                               }
+                       };
+                       doAnimation.finish = doAnimation;
+
+               return empty || optall.queue === false ?
+                       this.each( doAnimation ) :
+                       this.queue( optall.queue, doAnimation );
+       },
+       stop: function( type, clearQueue, gotoEnd ) {
+               var stopQueue = function( hooks ) {
+                       var stop = hooks.stop;
+                       delete hooks.stop;
+                       stop( gotoEnd );
+               };
+
+               if ( typeof type !== "string" ) {
+                       gotoEnd = clearQueue;
+                       clearQueue = type;
+                       type = undefined;
+               }
+               if ( clearQueue && type !== false ) {
+                       this.queue( type || "fx", [] );
+               }
+
+               return this.each(function() {
+                       var dequeue = true,
+                               index = type != null && type + "queueHooks",
+                               timers = jQuery.timers,
+                               data = jQuery._data( this );
+
+                       if ( index ) {
+                               if ( data[ index ] && data[ index ].stop ) {
+                                       stopQueue( data[ index ] );
+                               }
+                       } else {
+                               for ( index in data ) {
+                                       if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+                                               stopQueue( data[ index ] );
+                                       }
+                               }
+                       }
+
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+                                       timers[ index ].anim.stop( gotoEnd );
+                                       dequeue = false;
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // start the next in the queue if the last step wasn't forced
+                       // timers currently will call their complete callbacks, which will dequeue
+                       // but only if they were gotoEnd
+                       if ( dequeue || !gotoEnd ) {
+                               jQuery.dequeue( this, type );
+                       }
+               });
+       },
+       finish: function( type ) {
+               if ( type !== false ) {
+                       type = type || "fx";
+               }
+               return this.each(function() {
+                       var index,
+                               data = jQuery._data( this ),
+                               queue = data[ type + "queue" ],
+                               hooks = data[ type + "queueHooks" ],
+                               timers = jQuery.timers,
+                               length = queue ? queue.length : 0;
+
+                       // enable finishing flag on private data
+                       data.finish = true;
+
+                       // empty the queue first
+                       jQuery.queue( this, type, [] );
+
+                       if ( hooks && hooks.stop ) {
+                               hooks.stop.call( this, true );
+                       }
+
+                       // look for any active animations, and finish them
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+                                       timers[ index ].anim.stop( true );
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // look for any animations in the old queue and finish them
+                       for ( index = 0; index < length; index++ ) {
+                               if ( queue[ index ] && queue[ index ].finish ) {
+                                       queue[ index ].finish.call( this );
+                               }
+                       }
+
+                       // turn off finishing flag
+                       delete data.finish;
+               });
+       }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+       var cssFn = jQuery.fn[ name ];
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return speed == null || typeof speed === "boolean" ?
+                       cssFn.apply( this, arguments ) :
+                       this.animate( genFx( name, true ), speed, easing, callback );
+       };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+       slideDown: genFx("show"),
+       slideUp: genFx("hide"),
+       slideToggle: genFx("toggle"),
+       fadeIn: { opacity: "show" },
+       fadeOut: { opacity: "hide" },
+       fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return this.animate( props, speed, easing, callback );
+       };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+       var timer,
+               timers = jQuery.timers,
+               i = 0;
+
+       fxNow = jQuery.now();
+
+       for ( ; i < timers.length; i++ ) {
+               timer = timers[ i ];
+               // Checks the timer has not already been removed
+               if ( !timer() && timers[ i ] === timer ) {
+                       timers.splice( i--, 1 );
+               }
+       }
+
+       if ( !timers.length ) {
+               jQuery.fx.stop();
+       }
+       fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+       jQuery.timers.push( timer );
+       if ( timer() ) {
+               jQuery.fx.start();
+       } else {
+               jQuery.timers.pop();
+       }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+       if ( !timerId ) {
+               timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+       }
+};
+
+jQuery.fx.stop = function() {
+       clearInterval( timerId );
+       timerId = null;
+};
+
+jQuery.fx.speeds = {
+       slow: 600,
+       fast: 200,
+       // Default speed
+       _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+       time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+       type = type || "fx";
+
+       return this.queue( type, function( next, hooks ) {
+               var timeout = setTimeout( next, time );
+               hooks.stop = function() {
+                       clearTimeout( timeout );
+               };
+       });
+};
+
+
+(function() {
+       // Minified: var a,b,c,d,e
+       var input, div, select, a, opt;
+
+       // Setup
+       div = document.createElement( "div" );
+       div.setAttribute( "className", "t" );
+       div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+       a = div.getElementsByTagName("a")[ 0 ];
+
+       // First batch of tests.
+       select = document.createElement("select");
+       opt = select.appendChild( document.createElement("option") );
+       input = div.getElementsByTagName("input")[ 0 ];
+
+       a.style.cssText = "top:1px";
+
+       // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+       support.getSetAttribute = div.className !== "t";
+
+       // Get the style information from getAttribute
+       // (IE uses .cssText instead)
+       support.style = /top/.test( a.getAttribute("style") );
+
+       // Make sure that URLs aren't manipulated
+       // (IE normalizes it by default)
+       support.hrefNormalized = a.getAttribute("href") === "/a";
+
+       // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+       support.checkOn = !!input.value;
+
+       // Make sure that a selected-by-default option has a working selected property.
+       // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+       support.optSelected = opt.selected;
+
+       // Tests for enctype support on a form (#6743)
+       support.enctype = !!document.createElement("form").enctype;
+
+       // Make sure that the options inside disabled selects aren't marked as disabled
+       // (WebKit marks them as disabled)
+       select.disabled = true;
+       support.optDisabled = !opt.disabled;
+
+       // Support: IE8 only
+       // Check if we can trust getAttribute("value")
+       input = document.createElement( "input" );
+       input.setAttribute( "value", "" );
+       support.input = input.getAttribute( "value" ) === "";
+
+       // Check if an input maintains its value after becoming a radio
+       input.value = "t";
+       input.setAttribute( "type", "radio" );
+       support.radioValue = input.value === "t";
+})();
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+       val: function( value ) {
+               var hooks, ret, isFunction,
+                       elem = this[0];
+
+               if ( !arguments.length ) {
+                       if ( elem ) {
+                               hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+                               if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+                                       return ret;
+                               }
+
+                               ret = elem.value;
+
+                               return typeof ret === "string" ?
+                                       // handle most common string cases
+                                       ret.replace(rreturn, "") :
+                                       // handle cases where value is null/undef or number
+                                       ret == null ? "" : ret;
+                       }
+
+                       return;
+               }
+
+               isFunction = jQuery.isFunction( value );
+
+               return this.each(function( i ) {
+                       var val;
+
+                       if ( this.nodeType !== 1 ) {
+                               return;
+                       }
+
+                       if ( isFunction ) {
+                               val = value.call( this, i, jQuery( this ).val() );
+                       } else {
+                               val = value;
+                       }
+
+                       // Treat null/undefined as ""; convert numbers to string
+                       if ( val == null ) {
+                               val = "";
+                       } else if ( typeof val === "number" ) {
+                               val += "";
+                       } else if ( jQuery.isArray( val ) ) {
+                               val = jQuery.map( val, function( value ) {
+                                       return value == null ? "" : value + "";
+                               });
+                       }
+
+                       hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+                               this.value = val;
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+                               var val = jQuery.find.attr( elem, "value" );
+                               return val != null ?
+                                       val :
+                                       // Support: IE10-11+
+                                       // option.text throws exceptions (#14686, #14858)
+                                       jQuery.trim( jQuery.text( elem ) );
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var value, option,
+                                       options = elem.options,
+                                       index = elem.selectedIndex,
+                                       one = elem.type === "select-one" || index < 0,
+                                       values = one ? null : [],
+                                       max = one ? index + 1 : options.length,
+                                       i = index < 0 ?
+                                               max :
+                                               one ? index : 0;
+
+                               // Loop through all the selected options
+                               for ( ; i < max; i++ ) {
+                                       option = options[ i ];
+
+                                       // oldIE doesn't update selected after form reset (#2551)
+                                       if ( ( option.selected || i === index ) &&
+                                                       // Don't return options that are disabled or in a disabled optgroup
+                                                       ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+                                                       ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+                                               // Get the specific value for the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
+
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var optionSet, option,
+                                       options = elem.options,
+                                       values = jQuery.makeArray( value ),
+                                       i = options.length;
+
+                               while ( i-- ) {
+                                       option = options[ i ];
+
+                                       if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+                                               // Support: IE6
+                                               // When new option element is added to select box we need to
+                                               // force reflow of newly added node in order to workaround delay
+                                               // of initialization properties
+                                               try {
+                                                       option.selected = optionSet = true;
+
+                                               } catch ( _ ) {
+
+                                                       // Will be executed only in IE6
+                                                       option.scrollHeight;
+                                               }
+
+                                       } else {
+                                               option.selected = false;
+                                       }
+                               }
+
+                               // Force browsers to behave consistently when non-matching value is set
+                               if ( !optionSet ) {
+                                       elem.selectedIndex = -1;
+                               }
+
+                               return options;
+                       }
+               }
+       }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+       jQuery.valHooks[ this ] = {
+               set: function( elem, value ) {
+                       if ( jQuery.isArray( value ) ) {
+                               return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+                       }
+               }
+       };
+       if ( !support.checkOn ) {
+               jQuery.valHooks[ this ].get = function( elem ) {
+                       // Support: Webkit
+                       // "" is returned instead of "on" if a value isn't specified
+                       return elem.getAttribute("value") === null ? "on" : elem.value;
+               };
+       }
+});
+
+
+
+
+var nodeHook, boolHook,
+       attrHandle = jQuery.expr.attrHandle,
+       ruseDefault = /^(?:checked|selected)$/i,
+       getSetAttribute = support.getSetAttribute,
+       getSetInput = support.input;
+
+jQuery.fn.extend({
+       attr: function( name, value ) {
+               return access( this, jQuery.attr, name, value, arguments.length > 1 );
+       },
+
+       removeAttr: function( name ) {
+               return this.each(function() {
+                       jQuery.removeAttr( this, name );
+               });
+       }
+});
+
+jQuery.extend({
+       attr: function( elem, name, value ) {
+               var hooks, ret,
+                       nType = elem.nodeType;
+
+               // don't get/set attributes on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               // Fallback to prop when attributes are not supported
+               if ( typeof elem.getAttribute === strundefined ) {
+                       return jQuery.prop( elem, name, value );
+               }
+
+               // All attributes are lowercase
+               // Grab necessary hook if one is defined
+               if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+                       name = name.toLowerCase();
+                       hooks = jQuery.attrHooks[ name ] ||
+                               ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+               }
+
+               if ( value !== undefined ) {
+
+                       if ( value === null ) {
+                               jQuery.removeAttr( elem, name );
+
+                       } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                               return ret;
+
+                       } else {
+                               elem.setAttribute( name, value + "" );
+                               return value;
+                       }
+
+               } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+                       return ret;
+
+               } else {
+                       ret = jQuery.find.attr( elem, name );
+
+                       // Non-existent attributes return null, we normalize to undefined
+                       return ret == null ?
+                               undefined :
+                               ret;
+               }
+       },
+
+       removeAttr: function( elem, value ) {
+               var name, propName,
+                       i = 0,
+                       attrNames = value && value.match( rnotwhite );
+
+               if ( attrNames && elem.nodeType === 1 ) {
+                       while ( (name = attrNames[i++]) ) {
+                               propName = jQuery.propFix[ name ] || name;
+
+                               // Boolean attributes get special treatment (#10870)
+                               if ( jQuery.expr.match.bool.test( name ) ) {
+                                       // Set corresponding property to false
+                                       if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+                                               elem[ propName ] = false;
+                                       // Support: IE<9
+                                       // Also clear defaultChecked/defaultSelected (if appropriate)
+                                       } else {
+                                               elem[ jQuery.camelCase( "default-" + name ) ] =
+                                                       elem[ propName ] = false;
+                                       }
+
+                               // See #9699 for explanation of this approach (setting first, then removal)
+                               } else {
+                                       jQuery.attr( elem, name, "" );
+                               }
+
+                               elem.removeAttribute( getSetAttribute ? name : propName );
+                       }
+               }
+       },
+
+       attrHooks: {
+               type: {
+                       set: function( elem, value ) {
+                               if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+                                       // Setting the type on a radio button after the value resets the value in IE6-9
+                                       // Reset value to default in case type is set after value during creation
+                                       var val = elem.value;
+                                       elem.setAttribute( "type", value );
+                                       if ( val ) {
+                                               elem.value = val;
+                                       }
+                                       return value;
+                               }
+                       }
+               }
+       }
+});
+
+// Hook for boolean attributes
+boolHook = {
+       set: function( elem, value, name ) {
+               if ( value === false ) {
+                       // Remove boolean attributes when set to false
+                       jQuery.removeAttr( elem, name );
+               } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+                       // IE<8 needs the *property* name
+                       elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+               // Use defaultChecked and defaultSelected for oldIE
+               } else {
+                       elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+               }
+
+               return name;
+       }
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+       var getter = attrHandle[ name ] || jQuery.find.attr;
+
+       attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+               function( elem, name, isXML ) {
+                       var ret, handle;
+                       if ( !isXML ) {
+                               // Avoid an infinite loop by temporarily removing this function from the getter
+                               handle = attrHandle[ name ];
+                               attrHandle[ name ] = ret;
+                               ret = getter( elem, name, isXML ) != null ?
+                                       name.toLowerCase() :
+                                       null;
+                               attrHandle[ name ] = handle;
+                       }
+                       return ret;
+               } :
+               function( elem, name, isXML ) {
+                       if ( !isXML ) {
+                               return elem[ jQuery.camelCase( "default-" + name ) ] ?
+                                       name.toLowerCase() :
+                                       null;
+                       }
+               };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+       jQuery.attrHooks.value = {
+               set: function( elem, value, name ) {
+                       if ( jQuery.nodeName( elem, "input" ) ) {
+                               // Does not return so that setAttribute is also used
+                               elem.defaultValue = value;
+                       } else {
+                               // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+                               return nodeHook && nodeHook.set( elem, value, name );
+                       }
+               }
+       };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+       // Use this for any attribute in IE6/7
+       // This fixes almost every IE6/7 issue
+       nodeHook = {
+               set: function( elem, value, name ) {
+                       // Set the existing or create a new attribute node
+                       var ret = elem.getAttributeNode( name );
+                       if ( !ret ) {
+                               elem.setAttributeNode(
+                                       (ret = elem.ownerDocument.createAttribute( name ))
+                               );
+                       }
+
+                       ret.value = value += "";
+
+                       // Break association with cloned elements by also using setAttribute (#9646)
+                       if ( name === "value" || value === elem.getAttribute( name ) ) {
+                               return value;
+                       }
+               }
+       };
+
+       // Some attributes are constructed with empty-string values when not defined
+       attrHandle.id = attrHandle.name = attrHandle.coords =
+               function( elem, name, isXML ) {
+                       var ret;
+                       if ( !isXML ) {
+                               return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+                                       ret.value :
+                                       null;
+                       }
+               };
+
+       // Fixing value retrieval on a button requires this module
+       jQuery.valHooks.button = {
+               get: function( elem, name ) {
+                       var ret = elem.getAttributeNode( name );
+                       if ( ret && ret.specified ) {
+                               return ret.value;
+                       }
+               },
+               set: nodeHook.set
+       };
+
+       // Set contenteditable to false on removals(#10429)
+       // Setting to empty string throws an error as an invalid value
+       jQuery.attrHooks.contenteditable = {
+               set: function( elem, value, name ) {
+                       nodeHook.set( elem, value === "" ? false : value, name );
+               }
+       };
+
+       // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+       // This is for removals
+       jQuery.each([ "width", "height" ], function( i, name ) {
+               jQuery.attrHooks[ name ] = {
+                       set: function( elem, value ) {
+                               if ( value === "" ) {
+                                       elem.setAttribute( name, "auto" );
+                                       return value;
+                               }
+                       }
+               };
+       });
+}
+
+if ( !support.style ) {
+       jQuery.attrHooks.style = {
+               get: function( elem ) {
+                       // Return undefined in the case of empty string
+                       // Note: IE uppercases css property names, but if we were to .toLowerCase()
+                       // .cssText, that would destroy case senstitivity in URL's, like in "background"
+                       return elem.style.cssText || undefined;
+               },
+               set: function( elem, value ) {
+                       return ( elem.style.cssText = value + "" );
+               }
+       };
+}
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+       rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+       prop: function( name, value ) {
+               return access( this, jQuery.prop, name, value, arguments.length > 1 );
+       },
+
+       removeProp: function( name ) {
+               name = jQuery.propFix[ name ] || name;
+               return this.each(function() {
+                       // try/catch handles cases where IE balks (such as removing a property on window)
+                       try {
+                               this[ name ] = undefined;
+                               delete this[ name ];
+                       } catch( e ) {}
+               });
+       }
+});
+
+jQuery.extend({
+       propFix: {
+               "for": "htmlFor",
+               "class": "className"
+       },
+
+       prop: function( elem, name, value ) {
+               var ret, hooks, notxml,
+                       nType = elem.nodeType;
+
+               // don't get/set properties on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+               if ( notxml ) {
+                       // Fix name and attach hooks
+                       name = jQuery.propFix[ name ] || name;
+                       hooks = jQuery.propHooks[ name ];
+               }
+
+               if ( value !== undefined ) {
+                       return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+                               ret :
+                               ( elem[ name ] = value );
+
+               } else {
+                       return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+                               ret :
+                               elem[ name ];
+               }
+       },
+
+       propHooks: {
+               tabIndex: {
+                       get: function( elem ) {
+                               // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+                               // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+                               // Use proper attribute retrieval(#12072)
+                               var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+                               return tabindex ?
+                                       parseInt( tabindex, 10 ) :
+                                       rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+                                               0 :
+                                               -1;
+                       }
+               }
+       }
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+       // href/src property should get the full normalized URL (#10299/#12915)
+       jQuery.each([ "href", "src" ], function( i, name ) {
+               jQuery.propHooks[ name ] = {
+                       get: function( elem ) {
+                               return elem.getAttribute( name, 4 );
+                       }
+               };
+       });
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+       jQuery.propHooks.selected = {
+               get: function( elem ) {
+                       var parent = elem.parentNode;
+
+                       if ( parent ) {
+                               parent.selectedIndex;
+
+                               // Make sure that it also works with optgroups, see #5701
+                               if ( parent.parentNode ) {
+                                       parent.parentNode.selectedIndex;
+                               }
+                       }
+                       return null;
+               }
+       };
+}
+
+jQuery.each([
+       "tabIndex",
+       "readOnly",
+       "maxLength",
+       "cellSpacing",
+       "cellPadding",
+       "rowSpan",
+       "colSpan",
+       "useMap",
+       "frameBorder",
+       "contentEditable"
+], function() {
+       jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+       jQuery.propFix.enctype = "encoding";
+}
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+       addClass: function( value ) {
+               var classes, elem, cur, clazz, j, finalValue,
+                       i = 0,
+                       len = this.length,
+                       proceed = typeof value === "string" && value;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).addClass( value.call( this, j, this.className ) );
+                       });
+               }
+
+               if ( proceed ) {
+                       // The disjunction here is for better compressibility (see removeClass)
+                       classes = ( value || "" ).match( rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( rclass, " " ) :
+                                       " "
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+                                                       cur += clazz + " ";
+                                               }
+                                       }
+
+                                       // only assign if different to avoid unneeded rendering.
+                                       finalValue = jQuery.trim( cur );
+                                       if ( elem.className !== finalValue ) {
+                                               elem.className = finalValue;
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       removeClass: function( value ) {
+               var classes, elem, cur, clazz, j, finalValue,
+                       i = 0,
+                       len = this.length,
+                       proceed = arguments.length === 0 || typeof value === "string" && value;
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( j ) {
+                               jQuery( this ).removeClass( value.call( this, j, this.className ) );
+                       });
+               }
+               if ( proceed ) {
+                       classes = ( value || "" ).match( rnotwhite ) || [];
+
+                       for ( ; i < len; i++ ) {
+                               elem = this[ i ];
+                               // This expression is here for better compressibility (see addClass)
+                               cur = elem.nodeType === 1 && ( elem.className ?
+                                       ( " " + elem.className + " " ).replace( rclass, " " ) :
+                                       ""
+                               );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( (clazz = classes[j++]) ) {
+                                               // Remove *all* instances
+                                               while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+                                                       cur = cur.replace( " " + clazz + " ", " " );
+                                               }
+                                       }
+
+                                       // only assign if different to avoid unneeded rendering.
+                                       finalValue = value ? jQuery.trim( cur ) : "";
+                                       if ( elem.className !== finalValue ) {
+                                               elem.className = finalValue;
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       toggleClass: function( value, stateVal ) {
+               var type = typeof value;
+
+               if ( typeof stateVal === "boolean" && type === "string" ) {
+                       return stateVal ? this.addClass( value ) : this.removeClass( value );
+               }
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function( i ) {
+                               jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+                       });
+               }
+
+               return this.each(function() {
+                       if ( type === "string" ) {
+                               // toggle individual class names
+                               var className,
+                                       i = 0,
+                                       self = jQuery( this ),
+                                       classNames = value.match( rnotwhite ) || [];
+
+                               while ( (className = classNames[ i++ ]) ) {
+                                       // check each className given, space separated list
+                                       if ( self.hasClass( className ) ) {
+                                               self.removeClass( className );
+                                       } else {
+                                               self.addClass( className );
+                                       }
+                               }
+
+                       // Toggle whole class name
+                       } else if ( type === strundefined || type === "boolean" ) {
+                               if ( this.className ) {
+                                       // store className if set
+                                       jQuery._data( this, "__className__", this.className );
+                               }
+
+                               // If the element has a class name or if we're passed "false",
+                               // then remove the whole classname (if there was one, the above saved it).
+                               // Otherwise bring back whatever was previously saved (if anything),
+                               // falling back to the empty string if nothing was stored.
+                               this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+                       }
+               });
+       },
+
+       hasClass: function( selector ) {
+               var className = " " + selector + " ",
+                       i = 0,
+                       l = this.length;
+               for ( ; i < l; i++ ) {
+                       if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+       "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+       // Handle event binding
+       jQuery.fn[ name ] = function( data, fn ) {
+               return arguments.length > 0 ?
+                       this.on( name, null, data, fn ) :
+                       this.trigger( name );
+       };
+});
+
+jQuery.fn.extend({
+       hover: function( fnOver, fnOut ) {
+               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+       },
+
+       bind: function( types, data, fn ) {
+               return this.on( types, null, data, fn );
+       },
+       unbind: function( types, fn ) {
+               return this.off( types, null, fn );
+       },
+
+       delegate: function( selector, types, data, fn ) {
+               return this.on( types, selector, data, fn );
+       },
+       undelegate: function( selector, types, fn ) {
+               // ( namespace ) or ( selector, types [, fn] )
+               return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+       }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+       // Attempt to parse using the native JSON parser first
+       if ( window.JSON && window.JSON.parse ) {
+               // Support: Android 2.3
+               // Workaround failure to string-cast null input
+               return window.JSON.parse( data + "" );
+       }
+
+       var requireNonComma,
+               depth = null,
+               str = jQuery.trim( data + "" );
+
+       // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+       // after removing valid tokens
+       return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+               // Force termination if we see a misplaced comma
+               if ( requireNonComma && comma ) {
+                       depth = 0;
+               }
+
+               // Perform no more replacements after returning to outermost depth
+               if ( depth === 0 ) {
+                       return token;
+               }
+
+               // Commas must not follow "[", "{", or ","
+               requireNonComma = open || comma;
+
+               // Determine new depth
+               // array/object open ("[" or "{"): depth += true - false (increment)
+               // array/object close ("]" or "}"): depth += false - true (decrement)
+               // other cases ("," or primitive): depth += true - true (numeric cast)
+               depth += !close - !open;
+
+               // Remove this token
+               return "";
+       }) ) ?
+               ( Function( "return " + str ) )() :
+               jQuery.error( "Invalid JSON: " + data );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+       var xml, tmp;
+       if ( !data || typeof data !== "string" ) {
+               return null;
+       }
+       try {
+               if ( window.DOMParser ) { // Standard
+                       tmp = new DOMParser();
+                       xml = tmp.parseFromString( data, "text/xml" );
+               } else { // IE
+                       xml = new ActiveXObject( "Microsoft.XMLDOM" );
+                       xml.async = "false";
+                       xml.loadXML( data );
+               }
+       } catch( e ) {
+               xml = undefined;
+       }
+       if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+               jQuery.error( "Invalid XML: " + data );
+       }
+       return xml;
+};
+
+
+var
+       // Document location
+       ajaxLocParts,
+       ajaxLocation,
+
+       rhash = /#.*$/,
+       rts = /([?&])_=[^&]*/,
+       rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+       // #7653, #8125, #8152: local protocol detection
+       rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+       rnoContent = /^(?:GET|HEAD)$/,
+       rprotocol = /^\/\//,
+       rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+       /* Prefilters
+        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+        * 2) These are called:
+        *    - BEFORE asking for a transport
+        *    - AFTER param serialization (s.data is a string if s.processData is true)
+        * 3) key is the dataType
+        * 4) the catchall symbol "*" can be used
+        * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+        */
+       prefilters = {},
+
+       /* Transports bindings
+        * 1) key is the dataType
+        * 2) the catchall symbol "*" can be used
+        * 3) selection will start with transport dataType and THEN go to "*" if needed
+        */
+       transports = {},
+
+       // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+       allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+       ajaxLocation = location.href;
+} catch( e ) {
+       // Use the href attribute of an A element
+       // since IE will modify it given document.location
+       ajaxLocation = document.createElement( "a" );
+       ajaxLocation.href = "";
+       ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+       // dataTypeExpression is optional and defaults to "*"
+       return function( dataTypeExpression, func ) {
+
+               if ( typeof dataTypeExpression !== "string" ) {
+                       func = dataTypeExpression;
+                       dataTypeExpression = "*";
+               }
+
+               var dataType,
+                       i = 0,
+                       dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+               if ( jQuery.isFunction( func ) ) {
+                       // For each dataType in the dataTypeExpression
+                       while ( (dataType = dataTypes[i++]) ) {
+                               // Prepend if requested
+                               if ( dataType.charAt( 0 ) === "+" ) {
+                                       dataType = dataType.slice( 1 ) || "*";
+                                       (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+                               // Otherwise append
+                               } else {
+                                       (structure[ dataType ] = structure[ dataType ] || []).push( func );
+                               }
+                       }
+               }
+       };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+       var inspected = {},
+               seekingTransport = ( structure === transports );
+
+       function inspect( dataType ) {
+               var selected;
+               inspected[ dataType ] = true;
+               jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+                       var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+                       if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+                               options.dataTypes.unshift( dataTypeOrTransport );
+                               inspect( dataTypeOrTransport );
+                               return false;
+                       } else if ( seekingTransport ) {
+                               return !( selected = dataTypeOrTransport );
+                       }
+               });
+               return selected;
+       }
+
+       return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+       var deep, key,
+               flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+       for ( key in src ) {
+               if ( src[ key ] !== undefined ) {
+                       ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+               }
+       }
+       if ( deep ) {
+               jQuery.extend( true, target, deep );
+       }
+
+       return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+       var firstDataType, ct, finalDataType, type,
+               contents = s.contents,
+               dataTypes = s.dataTypes;
+
+       // Remove auto dataType and get content-type in the process
+       while ( dataTypes[ 0 ] === "*" ) {
+               dataTypes.shift();
+               if ( ct === undefined ) {
+                       ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+               }
+       }
+
+       // Check if we're dealing with a known content-type
+       if ( ct ) {
+               for ( type in contents ) {
+                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                               dataTypes.unshift( type );
+                               break;
+                       }
+               }
+       }
+
+       // Check to see if we have a response for the expected dataType
+       if ( dataTypes[ 0 ] in responses ) {
+               finalDataType = dataTypes[ 0 ];
+       } else {
+               // Try convertible dataTypes
+               for ( type in responses ) {
+                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+                               finalDataType = type;
+                               break;
+                       }
+                       if ( !firstDataType ) {
+                               firstDataType = type;
+                       }
+               }
+               // Or just use first one
+               finalDataType = finalDataType || firstDataType;
+       }
+
+       // If we found a dataType
+       // We add the dataType to the list if needed
+       // and return the corresponding response
+       if ( finalDataType ) {
+               if ( finalDataType !== dataTypes[ 0 ] ) {
+                       dataTypes.unshift( finalDataType );
+               }
+               return responses[ finalDataType ];
+       }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+       var conv2, current, conv, tmp, prev,
+               converters = {},
+               // Work with a copy of dataTypes in case we need to modify it for conversion
+               dataTypes = s.dataTypes.slice();
+
+       // Create converters map with lowercased keys
+       if ( dataTypes[ 1 ] ) {
+               for ( conv in s.converters ) {
+                       converters[ conv.toLowerCase() ] = s.converters[ conv ];
+               }
+       }
+
+       current = dataTypes.shift();
+
+       // Convert to each sequential dataType
+       while ( current ) {
+
+               if ( s.responseFields[ current ] ) {
+                       jqXHR[ s.responseFields[ current ] ] = response;
+               }
+
+               // Apply the dataFilter if provided
+               if ( !prev && isSuccess && s.dataFilter ) {
+                       response = s.dataFilter( response, s.dataType );
+               }
+
+               prev = current;
+               current = dataTypes.shift();
+
+               if ( current ) {
+
+                       // There's only work to do if current dataType is non-auto
+                       if ( current === "*" ) {
+
+                               current = prev;
+
+                       // Convert response if prev dataType is non-auto and differs from current
+                       } else if ( prev !== "*" && prev !== current ) {
+
+                               // Seek a direct converter
+                               conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+                               // If none found, seek a pair
+                               if ( !conv ) {
+                                       for ( conv2 in converters ) {
+
+                                               // If conv2 outputs current
+                                               tmp = conv2.split( " " );
+                                               if ( tmp[ 1 ] === current ) {
+
+                                                       // If prev can be converted to accepted input
+                                                       conv = converters[ prev + " " + tmp[ 0 ] ] ||
+                                                               converters[ "* " + tmp[ 0 ] ];
+                                                       if ( conv ) {
+                                                               // Condense equivalence converters
+                                                               if ( conv === true ) {
+                                                                       conv = converters[ conv2 ];
+
+                                                               // Otherwise, insert the intermediate dataType
+                                                               } else if ( converters[ conv2 ] !== true ) {
+                                                                       current = tmp[ 0 ];
+                                                                       dataTypes.unshift( tmp[ 1 ] );
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Apply converter (if not an equivalence)
+                               if ( conv !== true ) {
+
+                                       // Unless errors are allowed to bubble, catch and return them
+                                       if ( conv && s[ "throws" ] ) {
+                                               response = conv( response );
+                                       } else {
+                                               try {
+                                                       response = conv( response );
+                                               } catch ( e ) {
+                                                       return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+       // Counter for holding the number of active queries
+       active: 0,
+
+       // Last-Modified header cache for next request
+       lastModified: {},
+       etag: {},
+
+       ajaxSettings: {
+               url: ajaxLocation,
+               type: "GET",
+               isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+               global: true,
+               processData: true,
+               async: true,
+               contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+               /*
+               timeout: 0,
+               data: null,
+               dataType: null,
+               username: null,
+               password: null,
+               cache: null,
+               throws: false,
+               traditional: false,
+               headers: {},
+               */
+
+               accepts: {
+                       "*": allTypes,
+                       text: "text/plain",
+                       html: "text/html",
+                       xml: "application/xml, text/xml",
+                       json: "application/json, text/javascript"
+               },
+
+               contents: {
+                       xml: /xml/,
+                       html: /html/,
+                       json: /json/
+               },
+
+               responseFields: {
+                       xml: "responseXML",
+                       text: "responseText",
+                       json: "responseJSON"
+               },
+
+               // Data converters
+               // Keys separate source (or catchall "*") and destination types with a single space
+               converters: {
+
+                       // Convert anything to text
+                       "* text": String,
+
+                       // Text to html (true = no transformation)
+                       "text html": true,
+
+                       // Evaluate text as a json expression
+                       "text json": jQuery.parseJSON,
+
+                       // Parse text as xml
+                       "text xml": jQuery.parseXML
+               },
+
+               // For options that shouldn't be deep extended:
+               // you can add your own custom options here if
+               // and when you create one that shouldn't be
+               // deep extended (see ajaxExtend)
+               flatOptions: {
+                       url: true,
+                       context: true
+               }
+       },
+
+       // Creates a full fledged settings object into target
+       // with both ajaxSettings and settings fields.
+       // If target is omitted, writes into ajaxSettings.
+       ajaxSetup: function( target, settings ) {
+               return settings ?
+
+                       // Building a settings object
+                       ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+                       // Extending ajaxSettings
+                       ajaxExtend( jQuery.ajaxSettings, target );
+       },
+
+       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+       ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+       // Main method
+       ajax: function( url, options ) {
+
+               // If url is an object, simulate pre-1.5 signature
+               if ( typeof url === "object" ) {
+                       options = url;
+                       url = undefined;
+               }
+
+               // Force options to be an object
+               options = options || {};
+
+               var // Cross-domain detection vars
+                       parts,
+                       // Loop variable
+                       i,
+                       // URL without anti-cache param
+                       cacheURL,
+                       // Response headers as string
+                       responseHeadersString,
+                       // timeout handle
+                       timeoutTimer,
+
+                       // To know if global events are to be dispatched
+                       fireGlobals,
+
+                       transport,
+                       // Response headers
+                       responseHeaders,
+                       // Create the final options object
+                       s = jQuery.ajaxSetup( {}, options ),
+                       // Callbacks context
+                       callbackContext = s.context || s,
+                       // Context for global events is callbackContext if it is a DOM node or jQuery collection
+                       globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+                               jQuery( callbackContext ) :
+                               jQuery.event,
+                       // Deferreds
+                       deferred = jQuery.Deferred(),
+                       completeDeferred = jQuery.Callbacks("once memory"),
+                       // Status-dependent callbacks
+                       statusCode = s.statusCode || {},
+                       // Headers (they are sent all at once)
+                       requestHeaders = {},
+                       requestHeadersNames = {},
+                       // The jqXHR state
+                       state = 0,
+                       // Default abort message
+                       strAbort = "canceled",
+                       // Fake xhr
+                       jqXHR = {
+                               readyState: 0,
+
+                               // Builds headers hashtable if needed
+                               getResponseHeader: function( key ) {
+                                       var match;
+                                       if ( state === 2 ) {
+                                               if ( !responseHeaders ) {
+                                                       responseHeaders = {};
+                                                       while ( (match = rheaders.exec( responseHeadersString )) ) {
+                                                               responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                                       }
+                                               }
+                                               match = responseHeaders[ key.toLowerCase() ];
+                                       }
+                                       return match == null ? null : match;
+                               },
+
+                               // Raw string
+                               getAllResponseHeaders: function() {
+                                       return state === 2 ? responseHeadersString : null;
+                               },
+
+                               // Caches the header
+                               setRequestHeader: function( name, value ) {
+                                       var lname = name.toLowerCase();
+                                       if ( !state ) {
+                                               name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+                                               requestHeaders[ name ] = value;
+                                       }
+                                       return this;
+                               },
+
+                               // Overrides response content-type header
+                               overrideMimeType: function( type ) {
+                                       if ( !state ) {
+                                               s.mimeType = type;
+                                       }
+                                       return this;
+                               },
+
+                               // Status-dependent callbacks
+                               statusCode: function( map ) {
+                                       var code;
+                                       if ( map ) {
+                                               if ( state < 2 ) {
+                                                       for ( code in map ) {
+                                                               // Lazy-add the new callback in a way that preserves old ones
+                                                               statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+                                                       }
+                                               } else {
+                                                       // Execute the appropriate callbacks
+                                                       jqXHR.always( map[ jqXHR.status ] );
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // Cancel the request
+                               abort: function( statusText ) {
+                                       var finalText = statusText || strAbort;
+                                       if ( transport ) {
+                                               transport.abort( finalText );
+                                       }
+                                       done( 0, finalText );
+                                       return this;
+                               }
+                       };
+
+               // Attach deferreds
+               deferred.promise( jqXHR ).complete = completeDeferred.add;
+               jqXHR.success = jqXHR.done;
+               jqXHR.error = jqXHR.fail;
+
+               // Remove hash character (#7531: and string promotion)
+               // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+               // Handle falsy url in the settings object (#10093: consistency with old signature)
+               // We also use the url parameter if available
+               s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+               // Alias method option to type as per ticket #12004
+               s.type = options.method || options.type || s.method || s.type;
+
+               // Extract dataTypes list
+               s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+               // A cross-domain request is in order when we have a protocol:host:port mismatch
+               if ( s.crossDomain == null ) {
+                       parts = rurl.exec( s.url.toLowerCase() );
+                       s.crossDomain = !!( parts &&
+                               ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+                                       ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+                                               ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+                       );
+               }
+
+               // Convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" ) {
+                       s.data = jQuery.param( s.data, s.traditional );
+               }
+
+               // Apply prefilters
+               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+               // If request was aborted inside a prefilter, stop there
+               if ( state === 2 ) {
+                       return jqXHR;
+               }
+
+               // We can fire global events as of now if asked to
+               fireGlobals = s.global;
+
+               // Watch for a new set of requests
+               if ( fireGlobals && jQuery.active++ === 0 ) {
+                       jQuery.event.trigger("ajaxStart");
+               }
+
+               // Uppercase the type
+               s.type = s.type.toUpperCase();
+
+               // Determine if request has content
+               s.hasContent = !rnoContent.test( s.type );
+
+               // Save the URL in case we're toying with the If-Modified-Since
+               // and/or If-None-Match header later on
+               cacheURL = s.url;
+
+               // More options handling for requests with no content
+               if ( !s.hasContent ) {
+
+                       // If data is available, append data to url
+                       if ( s.data ) {
+                               cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+                               // #9682: remove data so that it's not used in an eventual retry
+                               delete s.data;
+                       }
+
+                       // Add anti-cache in url if needed
+                       if ( s.cache === false ) {
+                               s.url = rts.test( cacheURL ) ?
+
+                                       // If there is already a '_' parameter, set its value
+                                       cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+                                       // Otherwise add one to the end
+                                       cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+                       }
+               }
+
+               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+               if ( s.ifModified ) {
+                       if ( jQuery.lastModified[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+                       }
+                       if ( jQuery.etag[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+                       }
+               }
+
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                       jqXHR.setRequestHeader( "Content-Type", s.contentType );
+               }
+
+               // Set the Accepts header for the server, depending on the dataType
+               jqXHR.setRequestHeader(
+                       "Accept",
+                       s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                               s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                               s.accepts[ "*" ]
+               );
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       jqXHR.setRequestHeader( i, s.headers[ i ] );
+               }
+
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+                       // Abort if not done already and return
+                       return jqXHR.abort();
+               }
+
+               // aborting is no longer a cancellation
+               strAbort = "abort";
+
+               // Install callbacks on deferreds
+               for ( i in { success: 1, error: 1, complete: 1 } ) {
+                       jqXHR[ i ]( s[ i ] );
+               }
+
+               // Get transport
+               transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+               // If no transport, we auto-abort
+               if ( !transport ) {
+                       done( -1, "No Transport" );
+               } else {
+                       jqXHR.readyState = 1;
+
+                       // Send global event
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                       }
+                       // Timeout
+                       if ( s.async && s.timeout > 0 ) {
+                               timeoutTimer = setTimeout(function() {
+                                       jqXHR.abort("timeout");
+                               }, s.timeout );
+                       }
+
+                       try {
+                               state = 1;
+                               transport.send( requestHeaders, done );
+                       } catch ( e ) {
+                               // Propagate exception as error if not done
+                               if ( state < 2 ) {
+                                       done( -1, e );
+                               // Simply rethrow otherwise
+                               } else {
+                                       throw e;
+                               }
+                       }
+               }
+
+               // Callback for when everything is done
+               function done( status, nativeStatusText, responses, headers ) {
+                       var isSuccess, success, error, response, modified,
+                               statusText = nativeStatusText;
+
+                       // Called once
+                       if ( state === 2 ) {
+                               return;
+                       }
+
+                       // State is "done" now
+                       state = 2;
+
+                       // Clear timeout if it exists
+                       if ( timeoutTimer ) {
+                               clearTimeout( timeoutTimer );
+                       }
+
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jqXHR object will be used)
+                       transport = undefined;
+
+                       // Cache response headers
+                       responseHeadersString = headers || "";
+
+                       // Set readyState
+                       jqXHR.readyState = status > 0 ? 4 : 0;
+
+                       // Determine if successful
+                       isSuccess = status >= 200 && status < 300 || status === 304;
+
+                       // Get response data
+                       if ( responses ) {
+                               response = ajaxHandleResponses( s, jqXHR, responses );
+                       }
+
+                       // Convert no matter what (that way responseXXX fields are always set)
+                       response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+                       // If successful, handle type chaining
+                       if ( isSuccess ) {
+
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       modified = jqXHR.getResponseHeader("Last-Modified");
+                                       if ( modified ) {
+                                               jQuery.lastModified[ cacheURL ] = modified;
+                                       }
+                                       modified = jqXHR.getResponseHeader("etag");
+                                       if ( modified ) {
+                                               jQuery.etag[ cacheURL ] = modified;
+                                       }
+                               }
+
+                               // if no content
+                               if ( status === 204 || s.type === "HEAD" ) {
+                                       statusText = "nocontent";
+
+                               // if not modified
+                               } else if ( status === 304 ) {
+                                       statusText = "notmodified";
+
+                               // If we have data, let's convert it
+                               } else {
+                                       statusText = response.state;
+                                       success = response.data;
+                                       error = response.error;
+                                       isSuccess = !error;
+                               }
+                       } else {
+                               // We extract error from statusText
+                               // then normalize statusText and status for non-aborts
+                               error = statusText;
+                               if ( status || !statusText ) {
+                                       statusText = "error";
+                                       if ( status < 0 ) {
+                                               status = 0;
+                                       }
+                               }
+                       }
+
+                       // Set data for the fake xhr object
+                       jqXHR.status = status;
+                       jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+                       // Success/Error
+                       if ( isSuccess ) {
+                               deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                       } else {
+                               deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                       }
+
+                       // Status-dependent callbacks
+                       jqXHR.statusCode( statusCode );
+                       statusCode = undefined;
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+                                       [ jqXHR, s, isSuccess ? success : error ] );
+                       }
+
+                       // Complete
+                       completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+                               // Handle the global AJAX counter
+                               if ( !( --jQuery.active ) ) {
+                                       jQuery.event.trigger("ajaxStop");
+                               }
+                       }
+               }
+
+               return jqXHR;
+       },
+
+       getJSON: function( url, data, callback ) {
+               return jQuery.get( url, data, callback, "json" );
+       },
+
+       getScript: function( url, callback ) {
+               return jQuery.get( url, undefined, callback, "script" );
+       }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+       jQuery[ method ] = function( url, data, callback, type ) {
+               // shift arguments if data argument was omitted
+               if ( jQuery.isFunction( data ) ) {
+                       type = type || callback;
+                       callback = data;
+                       data = undefined;
+               }
+
+               return jQuery.ajax({
+                       url: url,
+                       type: method,
+                       dataType: type,
+                       data: data,
+                       success: callback
+               });
+       };
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+       jQuery.fn[ type ] = function( fn ) {
+               return this.on( type, fn );
+       };
+});
+
+
+jQuery._evalUrl = function( url ) {
+       return jQuery.ajax({
+               url: url,
+               type: "GET",
+               dataType: "script",
+               async: false,
+               global: false,
+               "throws": true
+       });
+};
+
+
+jQuery.fn.extend({
+       wrapAll: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function(i) {
+                               jQuery(this).wrapAll( html.call(this, i) );
+                       });
+               }
+
+               if ( this[0] ) {
+                       // The elements to wrap the target around
+                       var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+                       if ( this[0].parentNode ) {
+                               wrap.insertBefore( this[0] );
+                       }
+
+                       wrap.map(function() {
+                               var elem = this;
+
+                               while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+                                       elem = elem.firstChild;
+                               }
+
+                               return elem;
+                       }).append( this );
+               }
+
+               return this;
+       },
+
+       wrapInner: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function(i) {
+                               jQuery(this).wrapInner( html.call(this, i) );
+                       });
+               }
+
+               return this.each(function() {
+                       var self = jQuery( this ),
+                               contents = self.contents();
+
+                       if ( contents.length ) {
+                               contents.wrapAll( html );
+
+                       } else {
+                               self.append( html );
+                       }
+               });
+       },
+
+       wrap: function( html ) {
+               var isFunction = jQuery.isFunction( html );
+
+               return this.each(function(i) {
+                       jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+               });
+       },
+
+       unwrap: function() {
+               return this.parent().each(function() {
+                       if ( !jQuery.nodeName( this, "body" ) ) {
+                               jQuery( this ).replaceWith( this.childNodes );
+                       }
+               }).end();
+       }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+       // Support: Opera <= 12.12
+       // Opera reports offsetWidths and offsetHeights less than zero on some elements
+       return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+               (!support.reliableHiddenOffsets() &&
+                       ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+       return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+       rbracket = /\[\]$/,
+       rCRLF = /\r?\n/g,
+       rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+       rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+       var name;
+
+       if ( jQuery.isArray( obj ) ) {
+               // Serialize array item.
+               jQuery.each( obj, function( i, v ) {
+                       if ( traditional || rbracket.test( prefix ) ) {
+                               // Treat each array item as a scalar.
+                               add( prefix, v );
+
+                       } else {
+                               // Item is non-scalar (array or object), encode its numeric index.
+                               buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+                       }
+               });
+
+       } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+               // Serialize object item.
+               for ( name in obj ) {
+                       buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+               }
+
+       } else {
+               // Serialize scalar item.
+               add( prefix, obj );
+       }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+       var prefix,
+               s = [],
+               add = function( key, value ) {
+                       // If value is a function, invoke it and return its value
+                       value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+                       s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+               };
+
+       // Set traditional to true for jQuery <= 1.3.2 behavior.
+       if ( traditional === undefined ) {
+               traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+       }
+
+       // If an array was passed in, assume that it is an array of form elements.
+       if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+               // Serialize the form elements
+               jQuery.each( a, function() {
+                       add( this.name, this.value );
+               });
+
+       } else {
+               // If traditional, encode the "old" way (the way 1.3.2 or older
+               // did it), otherwise encode params recursively.
+               for ( prefix in a ) {
+                       buildParams( prefix, a[ prefix ], traditional, add );
+               }
+       }
+
+       // Return the resulting serialization
+       return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+       serialize: function() {
+               return jQuery.param( this.serializeArray() );
+       },
+       serializeArray: function() {
+               return this.map(function() {
+                       // Can add propHook for "elements" to filter or add form elements
+                       var elements = jQuery.prop( this, "elements" );
+                       return elements ? jQuery.makeArray( elements ) : this;
+               })
+               .filter(function() {
+                       var type = this.type;
+                       // Use .is(":disabled") so that fieldset[disabled] works
+                       return this.name && !jQuery( this ).is( ":disabled" ) &&
+                               rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+                               ( this.checked || !rcheckableType.test( type ) );
+               })
+               .map(function( i, elem ) {
+                       var val = jQuery( this ).val();
+
+                       return val == null ?
+                               null :
+                               jQuery.isArray( val ) ?
+                                       jQuery.map( val, function( val ) {
+                                               return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                                       }) :
+                                       { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+               }).get();
+       }
+});
+
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+       // Support: IE6+
+       function() {
+
+               // XHR cannot access local files, always use ActiveX for that case
+               return !this.isLocal &&
+
+                       // Support: IE7-8
+                       // oldIE XHR does not support non-RFC2616 methods (#13240)
+                       // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+                       // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+                       // Although this check for six methods instead of eight
+                       // since IE also does not support "trace" and "connect"
+                       /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+                       createStandardXHR() || createActiveXHR();
+       } :
+       // For all other browsers, use the standard XMLHttpRequest object
+       createStandardXHR;
+
+var xhrId = 0,
+       xhrCallbacks = {},
+       xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+if ( window.ActiveXObject ) {
+       jQuery( window ).on( "unload", function() {
+               for ( var key in xhrCallbacks ) {
+                       xhrCallbacks[ key ]( undefined, true );
+               }
+       });
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+       jQuery.ajaxTransport(function( options ) {
+               // Cross domain only allowed if supported through XMLHttpRequest
+               if ( !options.crossDomain || support.cors ) {
+
+                       var callback;
+
+                       return {
+                               send: function( headers, complete ) {
+                                       var i,
+                                               xhr = options.xhr(),
+                                               id = ++xhrId;
+
+                                       // Open the socket
+                                       xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+                                       // Apply custom fields if provided
+                                       if ( options.xhrFields ) {
+                                               for ( i in options.xhrFields ) {
+                                                       xhr[ i ] = options.xhrFields[ i ];
+                                               }
+                                       }
+
+                                       // Override mime type if needed
+                                       if ( options.mimeType && xhr.overrideMimeType ) {
+                                               xhr.overrideMimeType( options.mimeType );
+                                       }
+
+                                       // X-Requested-With header
+                                       // For cross-domain requests, seeing as conditions for a preflight are
+                                       // akin to a jigsaw puzzle, we simply never set it to be sure.
+                                       // (it can always be set on a per-request basis or even using ajaxSetup)
+                                       // For same-domain requests, won't change header if already provided.
+                                       if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+                                               headers["X-Requested-With"] = "XMLHttpRequest";
+                                       }
+
+                                       // Set headers
+                                       for ( i in headers ) {
+                                               // Support: IE<9
+                                               // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+                                               // request header to a null-value.
+                                               //
+                                               // To keep consistent with other XHR implementations, cast the value
+                                               // to string and ignore `undefined`.
+                                               if ( headers[ i ] !== undefined ) {
+                                                       xhr.setRequestHeader( i, headers[ i ] + "" );
+                                               }
+                                       }
+
+                                       // Do send the request
+                                       // This may raise an exception which is actually
+                                       // handled in jQuery.ajax (so no try/catch here)
+                                       xhr.send( ( options.hasContent && options.data ) || null );
+
+                                       // Listener
+                                       callback = function( _, isAbort ) {
+                                               var status, statusText, responses;
+
+                                               // Was never called and is aborted or complete
+                                               if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+                                                       // Clean up
+                                                       delete xhrCallbacks[ id ];
+                                                       callback = undefined;
+                                                       xhr.onreadystatechange = jQuery.noop;
+
+                                                       // Abort manually if needed
+                                                       if ( isAbort ) {
+                                                               if ( xhr.readyState !== 4 ) {
+                                                                       xhr.abort();
+                                                               }
+                                                       } else {
+                                                               responses = {};
+                                                               status = xhr.status;
+
+                                                               // Support: IE<10
+                                                               // Accessing binary-data responseText throws an exception
+                                                               // (#11426)
+                                                               if ( typeof xhr.responseText === "string" ) {
+                                                                       responses.text = xhr.responseText;
+                                                               }
+
+                                                               // Firefox throws an exception when accessing
+                                                               // statusText for faulty cross-domain requests
+                                                               try {
+                                                                       statusText = xhr.statusText;
+                                                               } catch( e ) {
+                                                                       // We normalize with Webkit giving an empty statusText
+                                                                       statusText = "";
+                                                               }
+
+                                                               // Filter status for non standard behaviors
+
+                                                               // If the request is local and we have data: assume a success
+                                                               // (success with no data won't get notified, that's the best we
+                                                               // can do given current implementations)
+                                                               if ( !status && options.isLocal && !options.crossDomain ) {
+                                                                       status = responses.text ? 200 : 404;
+                                                               // IE - #1450: sometimes returns 1223 when it should be 204
+                                                               } else if ( status === 1223 ) {
+                                                                       status = 204;
+                                                               }
+                                                       }
+                                               }
+
+                                               // Call complete if needed
+                                               if ( responses ) {
+                                                       complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+                                               }
+                                       };
+
+                                       if ( !options.async ) {
+                                               // if we're in sync mode we fire the callback
+                                               callback();
+                                       } else if ( xhr.readyState === 4 ) {
+                                               // (IE6 & IE7) if it's in cache and has been
+                                               // retrieved directly we need to fire the callback
+                                               setTimeout( callback );
+                                       } else {
+                                               // Add to the list of active xhr callbacks
+                                               xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+                                       }
+                               },
+
+                               abort: function() {
+                                       if ( callback ) {
+                                               callback( undefined, true );
+                                       }
+                               }
+                       };
+               }
+       });
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+       try {
+               return new window.XMLHttpRequest();
+       } catch( e ) {}
+}
+
+function createActiveXHR() {
+       try {
+               return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+       } catch( e ) {}
+}
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+       accepts: {
+               script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+       },
+       contents: {
+               script: /(?:java|ecma)script/
+       },
+       converters: {
+               "text script": function( text ) {
+                       jQuery.globalEval( text );
+                       return text;
+               }
+       }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+       if ( s.cache === undefined ) {
+               s.cache = false;
+       }
+       if ( s.crossDomain ) {
+               s.type = "GET";
+               s.global = false;
+       }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+       // This transport only deals with cross domain requests
+       if ( s.crossDomain ) {
+
+               var script,
+                       head = document.head || jQuery("head")[0] || document.documentElement;
+
+               return {
+
+                       send: function( _, callback ) {
+
+                               script = document.createElement("script");
+
+                               script.async = true;
+
+                               if ( s.scriptCharset ) {
+                                       script.charset = s.scriptCharset;
+                               }
+
+                               script.src = s.url;
+
+                               // Attach handlers for all browsers
+                               script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+                                       if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+                                               // Handle memory leak in IE
+                                               script.onload = script.onreadystatechange = null;
+
+                                               // Remove the script
+                                               if ( script.parentNode ) {
+                                                       script.parentNode.removeChild( script );
+                                               }
+
+                                               // Dereference the script
+                                               script = null;
+
+                                               // Callback if not abort
+                                               if ( !isAbort ) {
+                                                       callback( 200, "success" );
+                                               }
+                                       }
+                               };
+
+                               // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+                               // Use native DOM manipulation to avoid our domManip AJAX trickery
+                               head.insertBefore( script, head.firstChild );
+                       },
+
+                       abort: function() {
+                               if ( script ) {
+                                       script.onload( undefined, true );
+                               }
+                       }
+               };
+       }
+});
+
+
+
+
+var oldCallbacks = [],
+       rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+       jsonp: "callback",
+       jsonpCallback: function() {
+               var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+               this[ callback ] = true;
+               return callback;
+       }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+       var callbackName, overwritten, responseContainer,
+               jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+                       "url" :
+                       typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+               );
+
+       // Handle iff the expected data type is "jsonp" or we have a parameter to set
+       if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+               // Get callback name, remembering preexisting value associated with it
+               callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+                       s.jsonpCallback() :
+                       s.jsonpCallback;
+
+               // Insert callback into url or form data
+               if ( jsonProp ) {
+                       s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+               } else if ( s.jsonp !== false ) {
+                       s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+               }
+
+               // Use data converter to retrieve json after script execution
+               s.converters["script json"] = function() {
+                       if ( !responseContainer ) {
+                               jQuery.error( callbackName + " was not called" );
+                       }
+                       return responseContainer[ 0 ];
+               };
+
+               // force json dataType
+               s.dataTypes[ 0 ] = "json";
+
+               // Install callback
+               overwritten = window[ callbackName ];
+               window[ callbackName ] = function() {
+                       responseContainer = arguments;
+               };
+
+               // Clean-up function (fires after converters)
+               jqXHR.always(function() {
+                       // Restore preexisting value
+                       window[ callbackName ] = overwritten;
+
+                       // Save back as free
+                       if ( s[ callbackName ] ) {
+                               // make sure that re-using the options doesn't screw things around
+                               s.jsonpCallback = originalSettings.jsonpCallback;
+
+                               // save the callback name for future use
+                               oldCallbacks.push( callbackName );
+                       }
+
+                       // Call if it was a function and we have a response
+                       if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+                               overwritten( responseContainer[ 0 ] );
+                       }
+
+                       responseContainer = overwritten = undefined;
+               });
+
+               // Delegate to script
+               return "script";
+       }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+       if ( !data || typeof data !== "string" ) {
+               return null;
+       }
+       if ( typeof context === "boolean" ) {
+               keepScripts = context;
+               context = false;
+       }
+       context = context || document;
+
+       var parsed = rsingleTag.exec( data ),
+               scripts = !keepScripts && [];
+
+       // Single tag
+       if ( parsed ) {
+               return [ context.createElement( parsed[1] ) ];
+       }
+
+       parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+       if ( scripts && scripts.length ) {
+               jQuery( scripts ).remove();
+       }
+
+       return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+       if ( typeof url !== "string" && _load ) {
+               return _load.apply( this, arguments );
+       }
+
+       var selector, response, type,
+               self = this,
+               off = url.indexOf(" ");
+
+       if ( off >= 0 ) {
+               selector = jQuery.trim( url.slice( off, url.length ) );
+               url = url.slice( 0, off );
+       }
+
+       // If it's a function
+       if ( jQuery.isFunction( params ) ) {
+
+               // We assume that it's the callback
+               callback = params;
+               params = undefined;
+
+       // Otherwise, build a param string
+       } else if ( params && typeof params === "object" ) {
+               type = "POST";
+       }
+
+       // If we have elements to modify, make the request
+       if ( self.length > 0 ) {
+               jQuery.ajax({
+                       url: url,
+
+                       // if "type" variable is undefined, then "GET" method will be used
+                       type: type,
+                       dataType: "html",
+                       data: params
+               }).done(function( responseText ) {
+
+                       // Save response for use in complete callback
+                       response = arguments;
+
+                       self.html( selector ?
+
+                               // If a selector was specified, locate the right elements in a dummy div
+                               // Exclude scripts to avoid IE 'Permission Denied' errors
+                               jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+                               // Otherwise use the full result
+                               responseText );
+
+               }).complete( callback && function( jqXHR, status ) {
+                       self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+               });
+       }
+
+       return this;
+};
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+       return jQuery.grep(jQuery.timers, function( fn ) {
+               return elem === fn.elem;
+       }).length;
+};
+
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+       return jQuery.isWindow( elem ) ?
+               elem :
+               elem.nodeType === 9 ?
+                       elem.defaultView || elem.parentWindow :
+                       false;
+}
+
+jQuery.offset = {
+       setOffset: function( elem, options, i ) {
+               var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+                       position = jQuery.css( elem, "position" ),
+                       curElem = jQuery( elem ),
+                       props = {};
+
+               // set position first, in-case top/left are set even on static elem
+               if ( position === "static" ) {
+                       elem.style.position = "relative";
+               }
+
+               curOffset = curElem.offset();
+               curCSSTop = jQuery.css( elem, "top" );
+               curCSSLeft = jQuery.css( elem, "left" );
+               calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+                       jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+               // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+               if ( calculatePosition ) {
+                       curPosition = curElem.position();
+                       curTop = curPosition.top;
+                       curLeft = curPosition.left;
+               } else {
+                       curTop = parseFloat( curCSSTop ) || 0;
+                       curLeft = parseFloat( curCSSLeft ) || 0;
+               }
+
+               if ( jQuery.isFunction( options ) ) {
+                       options = options.call( elem, i, curOffset );
+               }
+
+               if ( options.top != null ) {
+                       props.top = ( options.top - curOffset.top ) + curTop;
+               }
+               if ( options.left != null ) {
+                       props.left = ( options.left - curOffset.left ) + curLeft;
+               }
+
+               if ( "using" in options ) {
+                       options.using.call( elem, props );
+               } else {
+                       curElem.css( props );
+               }
+       }
+};
+
+jQuery.fn.extend({
+       offset: function( options ) {
+               if ( arguments.length ) {
+                       return options === undefined ?
+                               this :
+                               this.each(function( i ) {
+                                       jQuery.offset.setOffset( this, options, i );
+                               });
+               }
+
+               var docElem, win,
+                       box = { top: 0, left: 0 },
+                       elem = this[ 0 ],
+                       doc = elem && elem.ownerDocument;
+
+               if ( !doc ) {
+                       return;
+               }
+
+               docElem = doc.documentElement;
+
+               // Make sure it's not a disconnected DOM node
+               if ( !jQuery.contains( docElem, elem ) ) {
+                       return box;
+               }
+
+               // If we don't have gBCR, just use 0,0 rather than error
+               // BlackBerry 5, iOS 3 (original iPhone)
+               if ( typeof elem.getBoundingClientRect !== strundefined ) {
+                       box = elem.getBoundingClientRect();
+               }
+               win = getWindow( doc );
+               return {
+                       top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
+                       left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+               };
+       },
+
+       position: function() {
+               if ( !this[ 0 ] ) {
+                       return;
+               }
+
+               var offsetParent, offset,
+                       parentOffset = { top: 0, left: 0 },
+                       elem = this[ 0 ];
+
+               // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+               if ( jQuery.css( elem, "position" ) === "fixed" ) {
+                       // we assume that getBoundingClientRect is available when computed position is fixed
+                       offset = elem.getBoundingClientRect();
+               } else {
+                       // Get *real* offsetParent
+                       offsetParent = this.offsetParent();
+
+                       // Get correct offsets
+                       offset = this.offset();
+                       if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+                               parentOffset = offsetParent.offset();
+                       }
+
+                       // Add offsetParent borders
+                       parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+                       parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+               }
+
+               // Subtract parent offsets and element margins
+               // note: when an element has margin: auto the offsetLeft and marginLeft
+               // are the same in Safari causing offset.left to incorrectly be 0
+               return {
+                       top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+                       left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+               };
+       },
+
+       offsetParent: function() {
+               return this.map(function() {
+                       var offsetParent = this.offsetParent || docElem;
+
+                       while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+                               offsetParent = offsetParent.offsetParent;
+                       }
+                       return offsetParent || docElem;
+               });
+       }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+       var top = /Y/.test( prop );
+
+       jQuery.fn[ method ] = function( val ) {
+               return access( this, function( elem, method, val ) {
+                       var win = getWindow( elem );
+
+                       if ( val === undefined ) {
+                               return win ? (prop in win) ? win[ prop ] :
+                                       win.document.documentElement[ method ] :
+                                       elem[ method ];
+                       }
+
+                       if ( win ) {
+                               win.scrollTo(
+                                       !top ? val : jQuery( win ).scrollLeft(),
+                                       top ? val : jQuery( win ).scrollTop()
+                               );
+
+                       } else {
+                               elem[ method ] = val;
+                       }
+               }, method, val, arguments.length, null );
+       };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+       jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+               function( elem, computed ) {
+                       if ( computed ) {
+                               computed = curCSS( elem, prop );
+                               // if curCSS returns percentage, fallback to offset
+                               return rnumnonpx.test( computed ) ?
+                                       jQuery( elem ).position()[ prop ] + "px" :
+                                       computed;
+                       }
+               }
+       );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+       jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+               // margin is only for outerHeight, outerWidth
+               jQuery.fn[ funcName ] = function( margin, value ) {
+                       var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+                               extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+                       return access( this, function( elem, type, value ) {
+                               var doc;
+
+                               if ( jQuery.isWindow( elem ) ) {
+                                       // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+                                       // isn't a whole lot we can do. See pull request at this URL for discussion:
+                                       // https://github.com/jquery/jquery/pull/764
+                                       return elem.document.documentElement[ "client" + name ];
+                               }
+
+                               // Get document width or height
+                               if ( elem.nodeType === 9 ) {
+                                       doc = elem.documentElement;
+
+                                       // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+                                       // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+                                       return Math.max(
+                                               elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+                                               elem.body[ "offset" + name ], doc[ "offset" + name ],
+                                               doc[ "client" + name ]
+                                       );
+                               }
+
+                               return value === undefined ?
+                                       // Get width or height on the element, requesting but not forcing parseFloat
+                                       jQuery.css( elem, type, extra ) :
+
+                                       // Set width or height on the element
+                                       jQuery.style( elem, type, value, extra );
+                       }, type, chainable ? margin : undefined, chainable, null );
+               };
+       });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+       return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+       define( "jquery", [], function() {
+               return jQuery;
+       });
+}
+
+
+
+
+var
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+
+       // Map over the $ in case of overwrite
+       _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+       if ( window.$ === jQuery ) {
+               window.$ = _$;
+       }
+
+       if ( deep && window.jQuery === jQuery ) {
+               window.jQuery = _jQuery;
+       }
+
+       return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+       window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/doc/_static/jquery.js b/doc/_static/jquery.js
new file mode 100644 (file)
index 0000000..ab28a24
--- /dev/null
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
diff --git a/doc/_static/makoLogo.png b/doc/_static/makoLogo.png
new file mode 100644 (file)
index 0000000..c43c087
Binary files /dev/null and b/doc/_static/makoLogo.png differ
diff --git a/doc/_static/minus.png b/doc/_static/minus.png
new file mode 100644 (file)
index 0000000..0f22b16
Binary files /dev/null and b/doc/_static/minus.png differ
diff --git a/doc/_static/plus.png b/doc/_static/plus.png
new file mode 100644 (file)
index 0000000..0cfe084
Binary files /dev/null and b/doc/_static/plus.png differ
diff --git a/doc/_static/pygments.css b/doc/_static/pygments.css
new file mode 100644 (file)
index 0000000..8213e90
--- /dev/null
@@ -0,0 +1,65 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight  { background: #eeffcc; }
+.highlight .c { color: #408090; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #007020; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #007020 } /* Comment.Preproc */
+.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #333333 } /* Generic.Output */
+.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #007020 } /* Keyword.Pseudo */
+.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #902000 } /* Keyword.Type */
+.highlight .m { color: #208050 } /* Literal.Number */
+.highlight .s { color: #4070a0 } /* Literal.String */
+.highlight .na { color: #4070a0 } /* Name.Attribute */
+.highlight .nb { color: #007020 } /* Name.Builtin */
+.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.highlight .no { color: #60add5 } /* Name.Constant */
+.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #007020 } /* Name.Exception */
+.highlight .nf { color: #06287e } /* Name.Function */
+.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
+.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #bb60d5 } /* Name.Variable */
+.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #208050 } /* Literal.Number.Bin */
+.highlight .mf { color: #208050 } /* Literal.Number.Float */
+.highlight .mh { color: #208050 } /* Literal.Number.Hex */
+.highlight .mi { color: #208050 } /* Literal.Number.Integer */
+.highlight .mo { color: #208050 } /* Literal.Number.Oct */
+.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
+.highlight .sc { color: #4070a0 } /* Literal.String.Char */
+.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
+.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
+.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.highlight .sx { color: #c65d09 } /* Literal.String.Other */
+.highlight .sr { color: #235388 } /* Literal.String.Regex */
+.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
+.highlight .ss { color: #517918 } /* Literal.String.Symbol */
+.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
+.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
+.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
+.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/doc/_static/searchtools.js b/doc/_static/searchtools.js
new file mode 100644 (file)
index 0000000..066857c
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * searchtools.js_t
+ * ~~~~~~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for the full-text search.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+
+/* Non-minified version JS is _stemmer.js if file is provided */ 
+/**
+ * Porter Stemmer
+ */
+var Stemmer = function() {
+
+  var step2list = {
+    ational: 'ate',
+    tional: 'tion',
+    enci: 'ence',
+    anci: 'ance',
+    izer: 'ize',
+    bli: 'ble',
+    alli: 'al',
+    entli: 'ent',
+    eli: 'e',
+    ousli: 'ous',
+    ization: 'ize',
+    ation: 'ate',
+    ator: 'ate',
+    alism: 'al',
+    iveness: 'ive',
+    fulness: 'ful',
+    ousness: 'ous',
+    aliti: 'al',
+    iviti: 'ive',
+    biliti: 'ble',
+    logi: 'log'
+  };
+
+  var step3list = {
+    icate: 'ic',
+    ative: '',
+    alize: 'al',
+    iciti: 'ic',
+    ical: 'ic',
+    ful: '',
+    ness: ''
+  };
+
+  var c = "[^aeiou]";          // consonant
+  var v = "[aeiouy]";          // vowel
+  var C = c + "[^aeiouy]*";    // consonant sequence
+  var V = v + "[aeiou]*";      // vowel sequence
+
+  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
+  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
+  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
+  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
+
+  this.stemWord = function (w) {
+    var stem;
+    var suffix;
+    var firstch;
+    var origword = w;
+
+    if (w.length < 3)
+      return w;
+
+    var re;
+    var re2;
+    var re3;
+    var re4;
+
+    firstch = w.substr(0,1);
+    if (firstch == "y")
+      w = firstch.toUpperCase() + w.substr(1);
+
+    // Step 1a
+    re = /^(.+?)(ss|i)es$/;
+    re2 = /^(.+?)([^s])s$/;
+
+    if (re.test(w))
+      w = w.replace(re,"$1$2");
+    else if (re2.test(w))
+      w = w.replace(re2,"$1$2");
+
+    // Step 1b
+    re = /^(.+?)eed$/;
+    re2 = /^(.+?)(ed|ing)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      re = new RegExp(mgr0);
+      if (re.test(fp[1])) {
+        re = /.$/;
+        w = w.replace(re,"");
+      }
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1];
+      re2 = new RegExp(s_v);
+      if (re2.test(stem)) {
+        w = stem;
+        re2 = /(at|bl|iz)$/;
+        re3 = new RegExp("([^aeiouylsz])\\1$");
+        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+        if (re2.test(w))
+          w = w + "e";
+        else if (re3.test(w)) {
+          re = /.$/;
+          w = w.replace(re,"");
+        }
+        else if (re4.test(w))
+          w = w + "e";
+      }
+    }
+
+    // Step 1c
+    re = /^(.+?)y$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(s_v);
+      if (re.test(stem))
+        w = stem + "i";
+    }
+
+    // Step 2
+    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step2list[suffix];
+    }
+
+    // Step 3
+    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step3list[suffix];
+    }
+
+    // Step 4
+    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+    re2 = /^(.+?)(s|t)(ion)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      if (re.test(stem))
+        w = stem;
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1] + fp[2];
+      re2 = new RegExp(mgr1);
+      if (re2.test(stem))
+        w = stem;
+    }
+
+    // Step 5
+    re = /^(.+?)e$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      re2 = new RegExp(meq1);
+      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+        w = stem;
+    }
+    re = /ll$/;
+    re2 = new RegExp(mgr1);
+    if (re.test(w) && re2.test(w)) {
+      re = /.$/;
+      w = w.replace(re,"");
+    }
+
+    // and turn initial Y back to y
+    if (firstch == "y")
+      w = firstch.toLowerCase() + w.substr(1);
+    return w;
+  }
+}
+
+
+
+/**
+ * Simple result scoring code.
+ */
+var Scorer = {
+  // Implement the following function to further tweak the score for each result
+  // The function takes a result array [filename, title, anchor, descr, score]
+  // and returns the new score.
+  /*
+  score: function(result) {
+    return result[4];
+  },
+  */
+
+  // query matches the full name of an object
+  objNameMatch: 11,
+  // or matches in the last dotted part of the object name
+  objPartialMatch: 6,
+  // Additive scores depending on the priority of the object
+  objPrio: {0:  15,   // used to be importantResults
+            1:  5,   // used to be objectResults
+            2: -5},  // used to be unimportantResults
+  //  Used when the priority is not in the mapping.
+  objPrioDefault: 0,
+
+  // query found in title
+  title: 15,
+  // query found in terms
+  term: 5
+};
+
+
+/**
+ * Search Module
+ */
+var Search = {
+
+  _index : null,
+  _queued_query : null,
+  _pulse_status : -1,
+
+  init : function() {
+      var params = $.getQueryParameters();
+      if (params.q) {
+          var query = params.q[0];
+          $('input[name="q"]')[0].value = query;
+          this.performSearch(query);
+      }
+  },
+
+  loadIndex : function(url) {
+    $.ajax({type: "GET", url: url, data: null,
+            dataType: "script", cache: true,
+            complete: function(jqxhr, textstatus) {
+              if (textstatus != "success") {
+                document.getElementById("searchindexloader").src = url;
+              }
+            }});
+  },
+
+  setIndex : function(index) {
+    var q;
+    this._index = index;
+    if ((q = this._queued_query) !== null) {
+      this._queued_query = null;
+      Search.query(q);
+    }
+  },
+
+  hasIndex : function() {
+      return this._index !== null;
+  },
+
+  deferQuery : function(query) {
+      this._queued_query = query;
+  },
+
+  stopPulse : function() {
+      this._pulse_status = 0;
+  },
+
+  startPulse : function() {
+    if (this._pulse_status >= 0)
+        return;
+    function pulse() {
+      var i;
+      Search._pulse_status = (Search._pulse_status + 1) % 4;
+      var dotString = '';
+      for (i = 0; i < Search._pulse_status; i++)
+        dotString += '.';
+      Search.dots.text(dotString);
+      if (Search._pulse_status > -1)
+        window.setTimeout(pulse, 500);
+    }
+    pulse();
+  },
+
+  /**
+   * perform a search for something (or wait until index is loaded)
+   */
+  performSearch : function(query) {
+    // create the required interface elements
+    this.out = $('#search-results');
+    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
+    this.dots = $('<span></span>').appendTo(this.title);
+    this.status = $('<p style="display: none"></p>').appendTo(this.out);
+    this.output = $('<ul class="search"/>').appendTo(this.out);
+
+    $('#search-progress').text(_('Preparing search...'));
+    this.startPulse();
+
+    // index already loaded, the browser was quick!
+    if (this.hasIndex())
+      this.query(query);
+    else
+      this.deferQuery(query);
+  },
+
+  /**
+   * execute search (requires search index to be loaded)
+   */
+  query : function(query) {
+    var i;
+    var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
+
+    // stem the searchterms and add them to the correct list
+    var stemmer = new Stemmer();
+    var searchterms = [];
+    var excluded = [];
+    var hlterms = [];
+    var tmp = query.split(/\s+/);
+    var objectterms = [];
+    for (i = 0; i < tmp.length; i++) {
+      if (tmp[i] !== "") {
+          objectterms.push(tmp[i].toLowerCase());
+      }
+
+      if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
+          tmp[i] === "") {
+        // skip this "word"
+        continue;
+      }
+      // stem the word
+      var word = stemmer.stemWord(tmp[i].toLowerCase());
+      var toAppend;
+      // select the correct list
+      if (word[0] == '-') {
+        toAppend = excluded;
+        word = word.substr(1);
+      }
+      else {
+        toAppend = searchterms;
+        hlterms.push(tmp[i].toLowerCase());
+      }
+      // only add if not already in the list
+      if (!$u.contains(toAppend, word))
+        toAppend.push(word);
+    }
+    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
+
+    // console.debug('SEARCH: searching for:');
+    // console.info('required: ', searchterms);
+    // console.info('excluded: ', excluded);
+
+    // prepare search
+    var terms = this._index.terms;
+    var titleterms = this._index.titleterms;
+
+    // array of [filename, title, anchor, descr, score]
+    var results = [];
+    $('#search-progress').empty();
+
+    // lookup as object
+    for (i = 0; i < objectterms.length; i++) {
+      var others = [].concat(objectterms.slice(0, i),
+                             objectterms.slice(i+1, objectterms.length));
+      results = results.concat(this.performObjectSearch(objectterms[i], others));
+    }
+
+    // lookup as search terms in fulltext
+    results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
+
+    // let the scorer override scores with a custom scoring function
+    if (Scorer.score) {
+      for (i = 0; i < results.length; i++)
+        results[i][4] = Scorer.score(results[i]);
+    }
+
+    // now sort the results by score (in opposite order of appearance, since the
+    // display function below uses pop() to retrieve items) and then
+    // alphabetically
+    results.sort(function(a, b) {
+      var left = a[4];
+      var right = b[4];
+      if (left > right) {
+        return 1;
+      } else if (left < right) {
+        return -1;
+      } else {
+        // same score: sort alphabetically
+        left = a[1].toLowerCase();
+        right = b[1].toLowerCase();
+        return (left > right) ? -1 : ((left < right) ? 1 : 0);
+      }
+    });
+
+    // for debugging
+    //Search.lastresults = results.slice();  // a copy
+    //console.info('search results:', Search.lastresults);
+
+    // print the results
+    var resultCount = results.length;
+    function displayNextItem() {
+      // results left, load the summary and display it
+      if (results.length) {
+        var item = results.pop();
+        var listItem = $('<li style="display:none"></li>');
+        if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
+          // dirhtml builder
+          var dirname = item[0] + '/';
+          if (dirname.match(/\/index\/$/)) {
+            dirname = dirname.substring(0, dirname.length-6);
+          } else if (dirname == 'index/') {
+            dirname = '';
+          }
+          listItem.append($('<a/>').attr('href',
+            DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
+            highlightstring + item[2]).html(item[1]));
+        } else {
+          // normal html builders
+          listItem.append($('<a/>').attr('href',
+            item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
+            highlightstring + item[2]).html(item[1]));
+        }
+        if (item[3]) {
+          listItem.append($('<span> (' + item[3] + ')</span>'));
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
+          $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
+                  dataType: "text",
+                  complete: function(jqxhr, textstatus) {
+                    var data = jqxhr.responseText;
+                    if (data !== '' && data !== undefined) {
+                      listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
+                    }
+                    Search.output.append(listItem);
+                    listItem.slideDown(5, function() {
+                      displayNextItem();
+                    });
+                  }});
+        } else {
+          // no source available, just display title
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        }
+      }
+      // search finished, update title and status message
+      else {
+        Search.stopPulse();
+        Search.title.text(_('Search Results'));
+        if (!resultCount)
+          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
+        else
+            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
+        Search.status.fadeIn(500);
+      }
+    }
+    displayNextItem();
+  },
+
+  /**
+   * search for object names
+   */
+  performObjectSearch : function(object, otherterms) {
+    var filenames = this._index.filenames;
+    var objects = this._index.objects;
+    var objnames = this._index.objnames;
+    var titles = this._index.titles;
+
+    var i;
+    var results = [];
+
+    for (var prefix in objects) {
+      for (var name in objects[prefix]) {
+        var fullname = (prefix ? prefix + '.' : '') + name;
+        if (fullname.toLowerCase().indexOf(object) > -1) {
+          var score = 0;
+          var parts = fullname.split('.');
+          // check for different match types: exact matches of full name or
+          // "last name" (i.e. last dotted part)
+          if (fullname == object || parts[parts.length - 1] == object) {
+            score += Scorer.objNameMatch;
+          // matches in last name
+          } else if (parts[parts.length - 1].indexOf(object) > -1) {
+            score += Scorer.objPartialMatch;
+          }
+          var match = objects[prefix][name];
+          var objname = objnames[match[1]][2];
+          var title = titles[match[0]];
+          // If more than one term searched for, we require other words to be
+          // found in the name/title/description
+          if (otherterms.length > 0) {
+            var haystack = (prefix + ' ' + name + ' ' +
+                            objname + ' ' + title).toLowerCase();
+            var allfound = true;
+            for (i = 0; i < otherterms.length; i++) {
+              if (haystack.indexOf(otherterms[i]) == -1) {
+                allfound = false;
+                break;
+              }
+            }
+            if (!allfound) {
+              continue;
+            }
+          }
+          var descr = objname + _(', in ') + title;
+
+          var anchor = match[3];
+          if (anchor === '')
+            anchor = fullname;
+          else if (anchor == '-')
+            anchor = objnames[match[1]][1] + '-' + fullname;
+          // add custom score for some objects according to scorer
+          if (Scorer.objPrio.hasOwnProperty(match[2])) {
+            score += Scorer.objPrio[match[2]];
+          } else {
+            score += Scorer.objPrioDefault;
+          }
+          results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
+        }
+      }
+    }
+
+    return results;
+  },
+
+  /**
+   * search for full-text terms in the index
+   */
+  performTermsSearch : function(searchterms, excluded, terms, titleterms) {
+    var filenames = this._index.filenames;
+    var titles = this._index.titles;
+
+    var i, j, file;
+    var fileMap = {};
+    var scoreMap = {};
+    var results = [];
+
+    // perform the search on the required terms
+    for (i = 0; i < searchterms.length; i++) {
+      var word = searchterms[i];
+      var files = [];
+      var _o = [
+        {files: terms[word], score: Scorer.term},
+        {files: titleterms[word], score: Scorer.title}
+      ];
+
+      // no match but word was a required one
+      if ($u.every(_o, function(o){return o.files === undefined;})) {
+        break;
+      }
+      // found search word in contents
+      $u.each(_o, function(o) {
+        var _files = o.files;
+        if (_files === undefined)
+          return
+
+        if (_files.length === undefined)
+          _files = [_files];
+        files = files.concat(_files);
+
+        // set score for the word in each file to Scorer.term
+        for (j = 0; j < _files.length; j++) {
+          file = _files[j];
+          if (!(file in scoreMap))
+            scoreMap[file] = {}
+          scoreMap[file][word] = o.score;
+        }
+      });
+
+      // create the mapping
+      for (j = 0; j < files.length; j++) {
+        file = files[j];
+        if (file in fileMap)
+          fileMap[file].push(word);
+        else
+          fileMap[file] = [word];
+      }
+    }
+
+    // now check if the files don't contain excluded terms
+    for (file in fileMap) {
+      var valid = true;
+
+      // check if all requirements are matched
+      if (fileMap[file].length != searchterms.length)
+          continue;
+
+      // ensure that none of the excluded terms is in the search result
+      for (i = 0; i < excluded.length; i++) {
+        if (terms[excluded[i]] == file ||
+            titleterms[excluded[i]] == file ||
+            $u.contains(terms[excluded[i]] || [], file) ||
+            $u.contains(titleterms[excluded[i]] || [], file)) {
+          valid = false;
+          break;
+        }
+      }
+
+      // if we have still a valid result we can add it to the result list
+      if (valid) {
+        // select one (max) score for the file.
+        // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
+        var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
+        results.push([filenames[file], titles[file], '', null, score]);
+      }
+    }
+    return results;
+  },
+
+  /**
+   * helper function to return a node containing the
+   * search summary for a given text. keywords is a list
+   * of stemmed words, hlwords is the list of normal, unstemmed
+   * words. the first one is used to find the occurrence, the
+   * latter for highlighting it.
+   */
+  makeSearchSummary : function(text, keywords, hlwords) {
+    var textLower = text.toLowerCase();
+    var start = 0;
+    $.each(keywords, function() {
+      var i = textLower.indexOf(this.toLowerCase());
+      if (i > -1)
+        start = i;
+    });
+    start = Math.max(start - 120, 0);
+    var excerpt = ((start > 0) ? '...' : '') +
+      $.trim(text.substr(start, 240)) +
+      ((start + 240 - text.length) ? '...' : '');
+    var rv = $('<div class="context"></div>').text(excerpt);
+    $.each(hlwords, function() {
+      rv = rv.highlightText(this, 'highlighted');
+    });
+    return rv;
+  }
+};
+
+$(document).ready(function() {
+  Search.init();
+});
\ No newline at end of file
diff --git a/doc/_static/sidebar.js b/doc/_static/sidebar.js
new file mode 100644 (file)
index 0000000..4282fe9
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * sidebar.js
+ * ~~~~~~~~~~
+ *
+ * This script makes the Sphinx sidebar collapsible.
+ *
+ * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds
+ * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
+ * used to collapse and expand the sidebar.
+ *
+ * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
+ * and the width of the sidebar and the margin-left of the document
+ * are decreased. When the sidebar is expanded the opposite happens.
+ * This script saves a per-browser/per-session cookie used to
+ * remember the position of the sidebar among the pages.
+ * Once the browser is closed the cookie is deleted and the position
+ * reset to the default (expanded).
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+$(function() {
+  
+  
+  
+  
+  
+  
+  
+
+  // global elements used by the functions.
+  // the 'sidebarbutton' element is defined as global after its
+  // creation, in the add_sidebar_button function
+  var bodywrapper = $('.bodywrapper');
+  var sidebar = $('.sphinxsidebar');
+  var sidebarwrapper = $('.sphinxsidebarwrapper');
+
+  // for some reason, the document has no sidebar; do not run into errors
+  if (!sidebar.length) return;
+
+  // original margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar expanded
+  var bw_margin_expanded = bodywrapper.css('margin-left');
+  var ssb_width_expanded = sidebar.width();
+
+  // margin-left of the bodywrapper and width of the sidebar
+  // with the sidebar collapsed
+  var bw_margin_collapsed = '.8em';
+  var ssb_width_collapsed = '.8em';
+
+  // colors used by the current theme
+  var dark_color = $('.related').css('background-color');
+  var light_color = $('.document').css('background-color');
+
+  function sidebar_is_collapsed() {
+    return sidebarwrapper.is(':not(:visible)');
+  }
+
+  function toggle_sidebar() {
+    if (sidebar_is_collapsed())
+      expand_sidebar();
+    else
+      collapse_sidebar();
+  }
+
+  function collapse_sidebar() {
+    sidebarwrapper.hide();
+    sidebar.css('width', ssb_width_collapsed);
+    bodywrapper.css('margin-left', bw_margin_collapsed);
+    sidebarbutton.css({
+        'margin-left': '0',
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('»');
+    sidebarbutton.attr('title', _('Expand sidebar'));
+    document.cookie = 'sidebar=collapsed';
+  }
+
+  function expand_sidebar() {
+    bodywrapper.css('margin-left', bw_margin_expanded);
+    sidebar.css('width', ssb_width_expanded);
+    sidebarwrapper.show();
+    sidebarbutton.css({
+        'margin-left': ssb_width_expanded-12,
+        'height': bodywrapper.height()
+    });
+    sidebarbutton.find('span').text('«');
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    document.cookie = 'sidebar=expanded';
+  }
+
+  function add_sidebar_button() {
+    sidebarwrapper.css({
+        'float': 'left',
+        'margin-right': '0',
+        'width': ssb_width_expanded - 28
+    });
+    // create the button
+    sidebar.append(
+        '<div id="sidebarbutton"><span>&laquo;</span></div>'
+    );
+    var sidebarbutton = $('#sidebarbutton');
+    light_color = sidebarbutton.css('background-color');
+    // find the height of the viewport to center the '<<' in the page
+    var viewport_height;
+    if (window.innerHeight)
+         viewport_height = window.innerHeight;
+    else
+         viewport_height = $(window).height();
+    sidebarbutton.find('span').css({
+        'display': 'block',
+        'margin-top': (viewport_height - sidebar.position().top - 20) / 2
+    });
+
+    sidebarbutton.click(toggle_sidebar);
+    sidebarbutton.attr('title', _('Collapse sidebar'));
+    sidebarbutton.css({
+        'color': '#FFFFFF',
+        'border-left': '1px solid ' + dark_color,
+        'font-size': '1.2em',
+        'cursor': 'pointer',
+        'height': bodywrapper.height(),
+        'padding-top': '1px',
+        'margin-left': ssb_width_expanded - 12
+    });
+
+    sidebarbutton.hover(
+      function () {
+          $(this).css('background-color', dark_color);
+      },
+      function () {
+          $(this).css('background-color', light_color);
+      }
+    );
+  }
+
+  function set_position_from_cookie() {
+    if (!document.cookie)
+      return;
+    var items = document.cookie.split(';');
+    for(var k=0; k<items.length; k++) {
+      var key_val = items[k].split('=');
+      var key = key_val[0].replace(/ /, "");  // strip leading spaces
+      if (key == 'sidebar') {
+        var value = key_val[1];
+        if ((value == 'collapsed') && (!sidebar_is_collapsed()))
+          collapse_sidebar();
+        else if ((value == 'expanded') && (sidebar_is_collapsed()))
+          expand_sidebar();
+      }
+    }
+  }
+
+  add_sidebar_button();
+  var sidebarbutton = $('#sidebarbutton');
+  set_position_from_cookie();
+});
\ No newline at end of file
diff --git a/doc/_static/site.css b/doc/_static/site.css
new file mode 100644 (file)
index 0000000..5b12b22
--- /dev/null
@@ -0,0 +1,86 @@
+body {
+    font-family: Tahoma, Geneva, sans-serif;
+    line-height:1.4em;
+    margin:15px;
+    background-color:#FFFFFF;
+}
+img {border:none;}
+a { text-decoration: none;}
+a:visited  { color: #2929ff;}
+a:hover { color: #0000ff;}
+
+#wrap {
+    margin:0 auto;
+    max-width:1024px;
+    min-width:480px;
+    position:relative;
+
+}
+h1 {
+    font-size:1.6em;
+    font-weight:bold;
+}
+
+h2 {
+    font-size:1.1em;
+    font-weight:bold;
+    margin:10px 0px 10px 0px;
+}
+
+.clearfix{
+    clear:both;
+}
+
+.red {
+       font-weight:bold;
+       color:#FF0000;
+}
+.rightbar {
+    float:right;
+}
+.slogan {
+    margin-top:10px;
+}
+#gittip_nav {
+    float:right;
+    margin:10px 0px 0px 0px;
+}
+
+.toolbar {
+    margin-top:20px;
+}
+.copyright {
+    font-size:.8em;
+    text-align:center;
+    color:909090;
+}
+.pylogo {
+       text-align:right;
+       float:right;
+}
+.code {
+    font-family:monospace;
+}
+
+li {
+    margin:1px 0px 1px 0px;
+}
+
+.speedchart td {
+    font-size:small;
+}
+
+pre.codesample {
+    margin: 1.5em;
+    padding: .5em;
+    font-size: .95em;
+    line-height:1em;
+    background-color: #eee;
+    border: 1px solid #ccc;
+    width:450px;
+    overflow:auto;
+}
+
+#speedchart {
+    margin:5px 10px 5px 10px;
+}
diff --git a/doc/_static/sphinx_paramlinks.css b/doc/_static/sphinx_paramlinks.css
new file mode 100644 (file)
index 0000000..be75d7a
--- /dev/null
@@ -0,0 +1,7 @@
+a.paramlink {
+       visibility: hidden;
+}
+
+li:hover > a.paramlink {
+   visibility: visible;
+}
diff --git a/doc/_static/underscore-1.3.1.js b/doc/_static/underscore-1.3.1.js
new file mode 100644 (file)
index 0000000..208d4cd
--- /dev/null
@@ -0,0 +1,999 @@
+//     Underscore.js 1.3.1
+//     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+//     Underscore is freely distributable under the MIT license.
+//     Portions of Underscore are inspired or borrowed from Prototype,
+//     Oliver Steele's Functional, and John Resig's Micro-Templating.
+//     For all details and documentation:
+//     http://documentcloud.github.com/underscore
+
+(function() {
+
+  // Baseline setup
+  // --------------
+
+  // Establish the root object, `window` in the browser, or `global` on the server.
+  var root = this;
+
+  // Save the previous value of the `_` variable.
+  var previousUnderscore = root._;
+
+  // Establish the object that gets returned to break out of a loop iteration.
+  var breaker = {};
+
+  // Save bytes in the minified (but not gzipped) version:
+  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
+
+  // Create quick reference variables for speed access to core prototypes.
+  var slice            = ArrayProto.slice,
+      unshift          = ArrayProto.unshift,
+      toString         = ObjProto.toString,
+      hasOwnProperty   = ObjProto.hasOwnProperty;
+
+  // All **ECMAScript 5** native function implementations that we hope to use
+  // are declared here.
+  var
+    nativeForEach      = ArrayProto.forEach,
+    nativeMap          = ArrayProto.map,
+    nativeReduce       = ArrayProto.reduce,
+    nativeReduceRight  = ArrayProto.reduceRight,
+    nativeFilter       = ArrayProto.filter,
+    nativeEvery        = ArrayProto.every,
+    nativeSome         = ArrayProto.some,
+    nativeIndexOf      = ArrayProto.indexOf,
+    nativeLastIndexOf  = ArrayProto.lastIndexOf,
+    nativeIsArray      = Array.isArray,
+    nativeKeys         = Object.keys,
+    nativeBind         = FuncProto.bind;
+
+  // Create a safe reference to the Underscore object for use below.
+  var _ = function(obj) { return new wrapper(obj); };
+
+  // Export the Underscore object for **Node.js**, with
+  // backwards-compatibility for the old `require()` API. If we're in
+  // the browser, add `_` as a global object via a string identifier,
+  // for Closure Compiler "advanced" mode.
+  if (typeof exports !== 'undefined') {
+    if (typeof module !== 'undefined' && module.exports) {
+      exports = module.exports = _;
+    }
+    exports._ = _;
+  } else {
+    root['_'] = _;
+  }
+
+  // Current version.
+  _.VERSION = '1.3.1';
+
+  // Collection Functions
+  // --------------------
+
+  // The cornerstone, an `each` implementation, aka `forEach`.
+  // Handles objects with the built-in `forEach`, arrays, and raw objects.
+  // Delegates to **ECMAScript 5**'s native `forEach` if available.
+  var each = _.each = _.forEach = function(obj, iterator, context) {
+    if (obj == null) return;
+    if (nativeForEach && obj.forEach === nativeForEach) {
+      obj.forEach(iterator, context);
+    } else if (obj.length === +obj.length) {
+      for (var i = 0, l = obj.length; i < l; i++) {
+        if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
+      }
+    } else {
+      for (var key in obj) {
+        if (_.has(obj, key)) {
+          if (iterator.call(context, obj[key], key, obj) === breaker) return;
+        }
+      }
+    }
+  };
+
+  // Return the results of applying the iterator to each element.
+  // Delegates to **ECMAScript 5**'s native `map` if available.
+  _.map = _.collect = function(obj, iterator, context) {
+    var results = [];
+    if (obj == null) return results;
+    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
+    each(obj, function(value, index, list) {
+      results[results.length] = iterator.call(context, value, index, list);
+    });
+    if (obj.length === +obj.length) results.length = obj.length;
+    return results;
+  };
+
+  // **Reduce** builds up a single result from a list of values, aka `inject`,
+  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
+  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
+    var initial = arguments.length > 2;
+    if (obj == null) obj = [];
+    if (nativeReduce && obj.reduce === nativeReduce) {
+      if (context) iterator = _.bind(iterator, context);
+      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+    }
+    each(obj, function(value, index, list) {
+      if (!initial) {
+        memo = value;
+        initial = true;
+      } else {
+        memo = iterator.call(context, memo, value, index, list);
+      }
+    });
+    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
+    return memo;
+  };
+
+  // The right-associative version of reduce, also known as `foldr`.
+  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
+  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
+    var initial = arguments.length > 2;
+    if (obj == null) obj = [];
+    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+      if (context) iterator = _.bind(iterator, context);
+      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+    }
+    var reversed = _.toArray(obj).reverse();
+    if (context && !initial) iterator = _.bind(iterator, context);
+    return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
+  };
+
+  // Return the first value which passes a truth test. Aliased as `detect`.
+  _.find = _.detect = function(obj, iterator, context) {
+    var result;
+    any(obj, function(value, index, list) {
+      if (iterator.call(context, value, index, list)) {
+        result = value;
+        return true;
+      }
+    });
+    return result;
+  };
+
+  // Return all the elements that pass a truth test.
+  // Delegates to **ECMAScript 5**'s native `filter` if available.
+  // Aliased as `select`.
+  _.filter = _.select = function(obj, iterator, context) {
+    var results = [];
+    if (obj == null) return results;
+    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
+    each(obj, function(value, index, list) {
+      if (iterator.call(context, value, index, list)) results[results.length] = value;
+    });
+    return results;
+  };
+
+  // Return all the elements for which a truth test fails.
+  _.reject = function(obj, iterator, context) {
+    var results = [];
+    if (obj == null) return results;
+    each(obj, function(value, index, list) {
+      if (!iterator.call(context, value, index, list)) results[results.length] = value;
+    });
+    return results;
+  };
+
+  // Determine whether all of the elements match a truth test.
+  // Delegates to **ECMAScript 5**'s native `every` if available.
+  // Aliased as `all`.
+  _.every = _.all = function(obj, iterator, context) {
+    var result = true;
+    if (obj == null) return result;
+    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
+    each(obj, function(value, index, list) {
+      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
+    });
+    return result;
+  };
+
+  // Determine if at least one element in the object matches a truth test.
+  // Delegates to **ECMAScript 5**'s native `some` if available.
+  // Aliased as `any`.
+  var any = _.some = _.any = function(obj, iterator, context) {
+    iterator || (iterator = _.identity);
+    var result = false;
+    if (obj == null) return result;
+    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
+    each(obj, function(value, index, list) {
+      if (result || (result = iterator.call(context, value, index, list))) return breaker;
+    });
+    return !!result;
+  };
+
+  // Determine if a given value is included in the array or object using `===`.
+  // Aliased as `contains`.
+  _.include = _.contains = function(obj, target) {
+    var found = false;
+    if (obj == null) return found;
+    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+    found = any(obj, function(value) {
+      return value === target;
+    });
+    return found;
+  };
+
+  // Invoke a method (with arguments) on every item in a collection.
+  _.invoke = function(obj, method) {
+    var args = slice.call(arguments, 2);
+    return _.map(obj, function(value) {
+      return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
+    });
+  };
+
+  // Convenience version of a common use case of `map`: fetching a property.
+  _.pluck = function(obj, key) {
+    return _.map(obj, function(value){ return value[key]; });
+  };
+
+  // Return the maximum element or (element-based computation).
+  _.max = function(obj, iterator, context) {
+    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
+    if (!iterator && _.isEmpty(obj)) return -Infinity;
+    var result = {computed : -Infinity};
+    each(obj, function(value, index, list) {
+      var computed = iterator ? iterator.call(context, value, index, list) : value;
+      computed >= result.computed && (result = {value : value, computed : computed});
+    });
+    return result.value;
+  };
+
+  // Return the minimum element (or element-based computation).
+  _.min = function(obj, iterator, context) {
+    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
+    if (!iterator && _.isEmpty(obj)) return Infinity;
+    var result = {computed : Infinity};
+    each(obj, function(value, index, list) {
+      var computed = iterator ? iterator.call(context, value, index, list) : value;
+      computed < result.computed && (result = {value : value, computed : computed});
+    });
+    return result.value;
+  };
+
+  // Shuffle an array.
+  _.shuffle = function(obj) {
+    var shuffled = [], rand;
+    each(obj, function(value, index, list) {
+      if (index == 0) {
+        shuffled[0] = value;
+      } else {
+        rand = Math.floor(Math.random() * (index + 1));
+        shuffled[index] = shuffled[rand];
+        shuffled[rand] = value;
+      }
+    });
+    return shuffled;
+  };
+
+  // Sort the object's values by a criterion produced by an iterator.
+  _.sortBy = function(obj, iterator, context) {
+    return _.pluck(_.map(obj, function(value, index, list) {
+      return {
+        value : value,
+        criteria : iterator.call(context, value, index, list)
+      };
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }), 'value');
+  };
+
+  // Groups the object's values by a criterion. Pass either a string attribute
+  // to group by, or a function that returns the criterion.
+  _.groupBy = function(obj, val) {
+    var result = {};
+    var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
+    each(obj, function(value, index) {
+      var key = iterator(value, index);
+      (result[key] || (result[key] = [])).push(value);
+    });
+    return result;
+  };
+
+  // Use a comparator function to figure out at what index an object should
+  // be inserted so as to maintain order. Uses binary search.
+  _.sortedIndex = function(array, obj, iterator) {
+    iterator || (iterator = _.identity);
+    var low = 0, high = array.length;
+    while (low < high) {
+      var mid = (low + high) >> 1;
+      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+    }
+    return low;
+  };
+
+  // Safely convert anything iterable into a real, live array.
+  _.toArray = function(iterable) {
+    if (!iterable)                return [];
+    if (iterable.toArray)         return iterable.toArray();
+    if (_.isArray(iterable))      return slice.call(iterable);
+    if (_.isArguments(iterable))  return slice.call(iterable);
+    return _.values(iterable);
+  };
+
+  // Return the number of elements in an object.
+  _.size = function(obj) {
+    return _.toArray(obj).length;
+  };
+
+  // Array Functions
+  // ---------------
+
+  // Get the first element of an array. Passing **n** will return the first N
+  // values in the array. Aliased as `head`. The **guard** check allows it to work
+  // with `_.map`.
+  _.first = _.head = function(array, n, guard) {
+    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+  };
+
+  // Returns everything but the last entry of the array. Especcialy useful on
+  // the arguments object. Passing **n** will return all the values in
+  // the array, excluding the last N. The **guard** check allows it to work with
+  // `_.map`.
+  _.initial = function(array, n, guard) {
+    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+  };
+
+  // Get the last element of an array. Passing **n** will return the last N
+  // values in the array. The **guard** check allows it to work with `_.map`.
+  _.last = function(array, n, guard) {
+    if ((n != null) && !guard) {
+      return slice.call(array, Math.max(array.length - n, 0));
+    } else {
+      return array[array.length - 1];
+    }
+  };
+
+  // Returns everything but the first entry of the array. Aliased as `tail`.
+  // Especially useful on the arguments object. Passing an **index** will return
+  // the rest of the values in the array from that index onward. The **guard**
+  // check allows it to work with `_.map`.
+  _.rest = _.tail = function(array, index, guard) {
+    return slice.call(array, (index == null) || guard ? 1 : index);
+  };
+
+  // Trim out all falsy values from an array.
+  _.compact = function(array) {
+    return _.filter(array, function(value){ return !!value; });
+  };
+
+  // Return a completely flattened version of an array.
+  _.flatten = function(array, shallow) {
+    return _.reduce(array, function(memo, value) {
+      if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
+      memo[memo.length] = value;
+      return memo;
+    }, []);
+  };
+
+  // Return a version of the array that does not contain the specified value(s).
+  _.without = function(array) {
+    return _.difference(array, slice.call(arguments, 1));
+  };
+
+  // Produce a duplicate-free version of the array. If the array has already
+  // been sorted, you have the option of using a faster algorithm.
+  // Aliased as `unique`.
+  _.uniq = _.unique = function(array, isSorted, iterator) {
+    var initial = iterator ? _.map(array, iterator) : array;
+    var result = [];
+    _.reduce(initial, function(memo, el, i) {
+      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
+        memo[memo.length] = el;
+        result[result.length] = array[i];
+      }
+      return memo;
+    }, []);
+    return result;
+  };
+
+  // Produce an array that contains the union: each distinct element from all of
+  // the passed-in arrays.
+  _.union = function() {
+    return _.uniq(_.flatten(arguments, true));
+  };
+
+  // Produce an array that contains every item shared between all the
+  // passed-in arrays. (Aliased as "intersect" for back-compat.)
+  _.intersection = _.intersect = function(array) {
+    var rest = slice.call(arguments, 1);
+    return _.filter(_.uniq(array), function(item) {
+      return _.every(rest, function(other) {
+        return _.indexOf(other, item) >= 0;
+      });
+    });
+  };
+
+  // Take the difference between one array and a number of other arrays.
+  // Only the elements present in just the first array will remain.
+  _.difference = function(array) {
+    var rest = _.flatten(slice.call(arguments, 1));
+    return _.filter(array, function(value){ return !_.include(rest, value); });
+  };
+
+  // Zip together multiple lists into a single array -- elements that share
+  // an index go together.
+  _.zip = function() {
+    var args = slice.call(arguments);
+    var length = _.max(_.pluck(args, 'length'));
+    var results = new Array(length);
+    for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
+    return results;
+  };
+
+  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
+  // we need this function. Return the position of the first occurrence of an
+  // item in an array, or -1 if the item is not included in the array.
+  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+  // If the array is large and already in sort order, pass `true`
+  // for **isSorted** to use binary search.
+  _.indexOf = function(array, item, isSorted) {
+    if (array == null) return -1;
+    var i, l;
+    if (isSorted) {
+      i = _.sortedIndex(array, item);
+      return array[i] === item ? i : -1;
+    }
+    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
+    for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
+    return -1;
+  };
+
+  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
+  _.lastIndexOf = function(array, item) {
+    if (array == null) return -1;
+    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
+    var i = array.length;
+    while (i--) if (i in array && array[i] === item) return i;
+    return -1;
+  };
+
+  // Generate an integer Array containing an arithmetic progression. A port of
+  // the native Python `range()` function. See
+  // [the Python documentation](http://docs.python.org/library/functions.html#range).
+  _.range = function(start, stop, step) {
+    if (arguments.length <= 1) {
+      stop = start || 0;
+      start = 0;
+    }
+    step = arguments[2] || 1;
+
+    var len = Math.max(Math.ceil((stop - start) / step), 0);
+    var idx = 0;
+    var range = new Array(len);
+
+    while(idx < len) {
+      range[idx++] = start;
+      start += step;
+    }
+
+    return range;
+  };
+
+  // Function (ahem) Functions
+  // ------------------
+
+  // Reusable constructor function for prototype setting.
+  var ctor = function(){};
+
+  // Create a function bound to a given object (assigning `this`, and arguments,
+  // optionally). Binding with arguments is also known as `curry`.
+  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
+  // We check for `func.bind` first, to fail fast when `func` is undefined.
+  _.bind = function bind(func, context) {
+    var bound, args;
+    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+    if (!_.isFunction(func)) throw new TypeError;
+    args = slice.call(arguments, 2);
+    return bound = function() {
+      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
+      ctor.prototype = func.prototype;
+      var self = new ctor;
+      var result = func.apply(self, args.concat(slice.call(arguments)));
+      if (Object(result) === result) return result;
+      return self;
+    };
+  };
+
+  // Bind all of an object's methods to that object. Useful for ensuring that
+  // all callbacks defined on an object belong to it.
+  _.bindAll = function(obj) {
+    var funcs = slice.call(arguments, 1);
+    if (funcs.length == 0) funcs = _.functions(obj);
+    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+    return obj;
+  };
+
+  // Memoize an expensive function by storing its results.
+  _.memoize = function(func, hasher) {
+    var memo = {};
+    hasher || (hasher = _.identity);
+    return function() {
+      var key = hasher.apply(this, arguments);
+      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+    };
+  };
+
+  // Delays a function for the given number of milliseconds, and then calls
+  // it with the arguments supplied.
+  _.delay = function(func, wait) {
+    var args = slice.call(arguments, 2);
+    return setTimeout(function(){ return func.apply(func, args); }, wait);
+  };
+
+  // Defers a function, scheduling it to run after the current call stack has
+  // cleared.
+  _.defer = function(func) {
+    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
+  };
+
+  // Returns a function, that, when invoked, will only be triggered at most once
+  // during a given window of time.
+  _.throttle = function(func, wait) {
+    var context, args, timeout, throttling, more;
+    var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
+    return function() {
+      context = this; args = arguments;
+      var later = function() {
+        timeout = null;
+        if (more) func.apply(context, args);
+        whenDone();
+      };
+      if (!timeout) timeout = setTimeout(later, wait);
+      if (throttling) {
+        more = true;
+      } else {
+        func.apply(context, args);
+      }
+      whenDone();
+      throttling = true;
+    };
+  };
+
+  // Returns a function, that, as long as it continues to be invoked, will not
+  // be triggered. The function will be called after it stops being called for
+  // N milliseconds.
+  _.debounce = function(func, wait) {
+    var timeout;
+    return function() {
+      var context = this, args = arguments;
+      var later = function() {
+        timeout = null;
+        func.apply(context, args);
+      };
+      clearTimeout(timeout);
+      timeout = setTimeout(later, wait);
+    };
+  };
+
+  // Returns a function that will be executed at most one time, no matter how
+  // often you call it. Useful for lazy initialization.
+  _.once = function(func) {
+    var ran = false, memo;
+    return function() {
+      if (ran) return memo;
+      ran = true;
+      return memo = func.apply(this, arguments);
+    };
+  };
+
+  // Returns the first function passed as an argument to the second,
+  // allowing you to adjust arguments, run code before and after, and
+  // conditionally execute the original function.
+  _.wrap = function(func, wrapper) {
+    return function() {
+      var args = [func].concat(slice.call(arguments, 0));
+      return wrapper.apply(this, args);
+    };
+  };
+
+  // Returns a function that is the composition of a list of functions, each
+  // consuming the return value of the function that follows.
+  _.compose = function() {
+    var funcs = arguments;
+    return function() {
+      var args = arguments;
+      for (var i = funcs.length - 1; i >= 0; i--) {
+        args = [funcs[i].apply(this, args)];
+      }
+      return args[0];
+    };
+  };
+
+  // Returns a function that will only be executed after being called N times.
+  _.after = function(times, func) {
+    if (times <= 0) return func();
+    return function() {
+      if (--times < 1) { return func.apply(this, arguments); }
+    };
+  };
+
+  // Object Functions
+  // ----------------
+
+  // Retrieve the names of an object's properties.
+  // Delegates to **ECMAScript 5**'s native `Object.keys`
+  _.keys = nativeKeys || function(obj) {
+    if (obj !== Object(obj)) throw new TypeError('Invalid object');
+    var keys = [];
+    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
+    return keys;
+  };
+
+  // Retrieve the values of an object's properties.
+  _.values = function(obj) {
+    return _.map(obj, _.identity);
+  };
+
+  // Return a sorted list of the function names available on the object.
+  // Aliased as `methods`
+  _.functions = _.methods = function(obj) {
+    var names = [];
+    for (var key in obj) {
+      if (_.isFunction(obj[key])) names.push(key);
+    }
+    return names.sort();
+  };
+
+  // Extend a given object with all the properties in passed-in object(s).
+  _.extend = function(obj) {
+    each(slice.call(arguments, 1), function(source) {
+      for (var prop in source) {
+        obj[prop] = source[prop];
+      }
+    });
+    return obj;
+  };
+
+  // Fill in a given object with default properties.
+  _.defaults = function(obj) {
+    each(slice.call(arguments, 1), function(source) {
+      for (var prop in source) {
+        if (obj[prop] == null) obj[prop] = source[prop];
+      }
+    });
+    return obj;
+  };
+
+  // Create a (shallow-cloned) duplicate of an object.
+  _.clone = function(obj) {
+    if (!_.isObject(obj)) return obj;
+    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+  };
+
+  // Invokes interceptor with the obj, and then returns obj.
+  // The primary purpose of this method is to "tap into" a method chain, in
+  // order to perform operations on intermediate results within the chain.
+  _.tap = function(obj, interceptor) {
+    interceptor(obj);
+    return obj;
+  };
+
+  // Internal recursive comparison function.
+  function eq(a, b, stack) {
+    // Identical objects are equal. `0 === -0`, but they aren't identical.
+    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
+    if (a === b) return a !== 0 || 1 / a == 1 / b;
+    // A strict comparison is necessary because `null == undefined`.
+    if (a == null || b == null) return a === b;
+    // Unwrap any wrapped objects.
+    if (a._chain) a = a._wrapped;
+    if (b._chain) b = b._wrapped;
+    // Invoke a custom `isEqual` method if one is provided.
+    if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
+    if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
+    // Compare `[[Class]]` names.
+    var className = toString.call(a);
+    if (className != toString.call(b)) return false;
+    switch (className) {
+      // Strings, numbers, dates, and booleans are compared by value.
+      case '[object String]':
+        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+        // equivalent to `new String("5")`.
+        return a == String(b);
+      case '[object Number]':
+        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+        // other numeric values.
+        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
+      case '[object Date]':
+      case '[object Boolean]':
+        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+        // millisecond representations. Note that invalid dates with millisecond representations
+        // of `NaN` are not equivalent.
+        return +a == +b;
+      // RegExps are compared by their source patterns and flags.
+      case '[object RegExp]':
+        return a.source == b.source &&
+               a.global == b.global &&
+               a.multiline == b.multiline &&
+               a.ignoreCase == b.ignoreCase;
+    }
+    if (typeof a != 'object' || typeof b != 'object') return false;
+    // Assume equality for cyclic structures. The algorithm for detecting cyclic
+    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+    var length = stack.length;
+    while (length--) {
+      // Linear search. Performance is inversely proportional to the number of
+      // unique nested structures.
+      if (stack[length] == a) return true;
+    }
+    // Add the first object to the stack of traversed objects.
+    stack.push(a);
+    var size = 0, result = true;
+    // Recursively compare objects and arrays.
+    if (className == '[object Array]') {
+      // Compare array lengths to determine if a deep comparison is necessary.
+      size = a.length;
+      result = size == b.length;
+      if (result) {
+        // Deep compare the contents, ignoring non-numeric properties.
+        while (size--) {
+          // Ensure commutative equality for sparse arrays.
+          if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
+        }
+      }
+    } else {
+      // Objects with different constructors are not equivalent.
+      if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
+      // Deep compare objects.
+      for (var key in a) {
+        if (_.has(a, key)) {
+          // Count the expected number of properties.
+          size++;
+          // Deep compare each member.
+          if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
+        }
+      }
+      // Ensure that both objects contain the same number of properties.
+      if (result) {
+        for (key in b) {
+          if (_.has(b, key) && !(size--)) break;
+        }
+        result = !size;
+      }
+    }
+    // Remove the first object from the stack of traversed objects.
+    stack.pop();
+    return result;
+  }
+
+  // Perform a deep comparison to check if two objects are equal.
+  _.isEqual = function(a, b) {
+    return eq(a, b, []);
+  };
+
+  // Is a given array, string, or object empty?
+  // An "empty" object has no enumerable own-properties.
+  _.isEmpty = function(obj) {
+    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+    for (var key in obj) if (_.has(obj, key)) return false;
+    return true;
+  };
+
+  // Is a given value a DOM element?
+  _.isElement = function(obj) {
+    return !!(obj && obj.nodeType == 1);
+  };
+
+  // Is a given value an array?
+  // Delegates to ECMA5's native Array.isArray
+  _.isArray = nativeIsArray || function(obj) {
+    return toString.call(obj) == '[object Array]';
+  };
+
+  // Is a given variable an object?
+  _.isObject = function(obj) {
+    return obj === Object(obj);
+  };
+
+  // Is a given variable an arguments object?
+  _.isArguments = function(obj) {
+    return toString.call(obj) == '[object Arguments]';
+  };
+  if (!_.isArguments(arguments)) {
+    _.isArguments = function(obj) {
+      return !!(obj && _.has(obj, 'callee'));
+    };
+  }
+
+  // Is a given value a function?
+  _.isFunction = function(obj) {
+    return toString.call(obj) == '[object Function]';
+  };
+
+  // Is a given value a string?
+  _.isString = function(obj) {
+    return toString.call(obj) == '[object String]';
+  };
+
+  // Is a given value a number?
+  _.isNumber = function(obj) {
+    return toString.call(obj) == '[object Number]';
+  };
+
+  // Is the given value `NaN`?
+  _.isNaN = function(obj) {
+    // `NaN` is the only value for which `===` is not reflexive.
+    return obj !== obj;
+  };
+
+  // Is a given value a boolean?
+  _.isBoolean = function(obj) {
+    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+  };
+
+  // Is a given value a date?
+  _.isDate = function(obj) {
+    return toString.call(obj) == '[object Date]';
+  };
+
+  // Is the given value a regular expression?
+  _.isRegExp = function(obj) {
+    return toString.call(obj) == '[object RegExp]';
+  };
+
+  // Is a given value equal to null?
+  _.isNull = function(obj) {
+    return obj === null;
+  };
+
+  // Is a given variable undefined?
+  _.isUndefined = function(obj) {
+    return obj === void 0;
+  };
+
+  // Has own property?
+  _.has = function(obj, key) {
+    return hasOwnProperty.call(obj, key);
+  };
+
+  // Utility Functions
+  // -----------------
+
+  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+  // previous owner. Returns a reference to the Underscore object.
+  _.noConflict = function() {
+    root._ = previousUnderscore;
+    return this;
+  };
+
+  // Keep the identity function around for default iterators.
+  _.identity = function(value) {
+    return value;
+  };
+
+  // Run a function **n** times.
+  _.times = function (n, iterator, context) {
+    for (var i = 0; i < n; i++) iterator.call(context, i);
+  };
+
+  // Escape a string for HTML interpolation.
+  _.escape = function(string) {
+    return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
+  };
+
+  // Add your own custom functions to the Underscore object, ensuring that
+  // they're correctly added to the OOP wrapper as well.
+  _.mixin = function(obj) {
+    each(_.functions(obj), function(name){
+      addToWrapper(name, _[name] = obj[name]);
+    });
+  };
+
+  // Generate a unique integer id (unique within the entire client session).
+  // Useful for temporary DOM ids.
+  var idCounter = 0;
+  _.uniqueId = function(prefix) {
+    var id = idCounter++;
+    return prefix ? prefix + id : id;
+  };
+
+  // By default, Underscore uses ERB-style template delimiters, change the
+  // following template settings to use alternative delimiters.
+  _.templateSettings = {
+    evaluate    : /<%([\s\S]+?)%>/g,
+    interpolate : /<%=([\s\S]+?)%>/g,
+    escape      : /<%-([\s\S]+?)%>/g
+  };
+
+  // When customizing `templateSettings`, if you don't want to define an
+  // interpolation, evaluation or escaping regex, we need one that is
+  // guaranteed not to match.
+  var noMatch = /.^/;
+
+  // Within an interpolation, evaluation, or escaping, remove HTML escaping
+  // that had been previously added.
+  var unescape = function(code) {
+    return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
+  };
+
+  // JavaScript micro-templating, similar to John Resig's implementation.
+  // Underscore templating handles arbitrary delimiters, preserves whitespace,
+  // and correctly escapes quotes within interpolated code.
+  _.template = function(str, data) {
+    var c  = _.templateSettings;
+    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
+      'with(obj||{}){__p.push(\'' +
+      str.replace(/\\/g, '\\\\')
+         .replace(/'/g, "\\'")
+         .replace(c.escape || noMatch, function(match, code) {
+           return "',_.escape(" + unescape(code) + "),'";
+         })
+         .replace(c.interpolate || noMatch, function(match, code) {
+           return "'," + unescape(code) + ",'";
+         })
+         .replace(c.evaluate || noMatch, function(match, code) {
+           return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
+         })
+         .replace(/\r/g, '\\r')
+         .replace(/\n/g, '\\n')
+         .replace(/\t/g, '\\t')
+         + "');}return __p.join('');";
+    var func = new Function('obj', '_', tmpl);
+    if (data) return func(data, _);
+    return function(data) {
+      return func.call(this, data, _);
+    };
+  };
+
+  // Add a "chain" function, which will delegate to the wrapper.
+  _.chain = function(obj) {
+    return _(obj).chain();
+  };
+
+  // The OOP Wrapper
+  // ---------------
+
+  // If Underscore is called as a function, it returns a wrapped object that
+  // can be used OO-style. This wrapper holds altered versions of all the
+  // underscore functions. Wrapped objects may be chained.
+  var wrapper = function(obj) { this._wrapped = obj; };
+
+  // Expose `wrapper.prototype` as `_.prototype`
+  _.prototype = wrapper.prototype;
+
+  // Helper function to continue chaining intermediate results.
+  var result = function(obj, chain) {
+    return chain ? _(obj).chain() : obj;
+  };
+
+  // A method to easily add functions to the OOP wrapper.
+  var addToWrapper = function(name, func) {
+    wrapper.prototype[name] = function() {
+      var args = slice.call(arguments);
+      unshift.call(args, this._wrapped);
+      return result(func.apply(_, args), this._chain);
+    };
+  };
+
+  // Add all of the Underscore functions to the wrapper object.
+  _.mixin(_);
+
+  // Add all mutator Array functions to the wrapper.
+  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+    var method = ArrayProto[name];
+    wrapper.prototype[name] = function() {
+      var wrapped = this._wrapped;
+      method.apply(wrapped, arguments);
+      var length = wrapped.length;
+      if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
+      return result(wrapped, this._chain);
+    };
+  });
+
+  // Add all accessor Array functions to the wrapper.
+  each(['concat', 'join', 'slice'], function(name) {
+    var method = ArrayProto[name];
+    wrapper.prototype[name] = function() {
+      return result(method.apply(this._wrapped, arguments), this._chain);
+    };
+  });
+
+  // Start chaining a wrapped Underscore object.
+  wrapper.prototype.chain = function() {
+    this._chain = true;
+    return this;
+  };
+
+  // Extracts the result from a wrapped and chained object.
+  wrapper.prototype.value = function() {
+    return this._wrapped;
+  };
+
+}).call(this);
diff --git a/doc/_static/underscore.js b/doc/_static/underscore.js
new file mode 100644 (file)
index 0000000..5b55f32
--- /dev/null
@@ -0,0 +1,31 @@
+// Underscore.js 1.3.1
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
+h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
+b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
+null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
+function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
+e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
+return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
+c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
+b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
+return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
+d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
+var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
+c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
+a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
+b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
+1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
+b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
+b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
+function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
+u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
+function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
+true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
diff --git a/doc/_static/up-pressed.png b/doc/_static/up-pressed.png
new file mode 100644 (file)
index 0000000..99e7210
Binary files /dev/null and b/doc/_static/up-pressed.png differ
diff --git a/doc/_static/up.png b/doc/_static/up.png
new file mode 100644 (file)
index 0000000..26de002
Binary files /dev/null and b/doc/_static/up.png differ
diff --git a/doc/_static/websupport.js b/doc/_static/websupport.js
new file mode 100644 (file)
index 0000000..98e7f40
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ * websupport.js
+ * ~~~~~~~~~~~~~
+ *
+ * sphinx.websupport utilities for all documentation.
+ *
+ * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+(function($) {
+  $.fn.autogrow = function() {
+    return this.each(function() {
+    var textarea = this;
+
+    $.fn.autogrow.resize(textarea);
+
+    $(textarea)
+      .focus(function() {
+        textarea.interval = setInterval(function() {
+          $.fn.autogrow.resize(textarea);
+        }, 500);
+      })
+      .blur(function() {
+        clearInterval(textarea.interval);
+      });
+    });
+  };
+
+  $.fn.autogrow.resize = function(textarea) {
+    var lineHeight = parseInt($(textarea).css('line-height'), 10);
+    var lines = textarea.value.split('\n');
+    var columns = textarea.cols;
+    var lineCount = 0;
+    $.each(lines, function() {
+      lineCount += Math.ceil(this.length / columns) || 1;
+    });
+    var height = lineHeight * (lineCount + 1);
+    $(textarea).css('height', height);
+  };
+})(jQuery);
+
+(function($) {
+  var comp, by;
+
+  function init() {
+    initEvents();
+    initComparator();
+  }
+
+  function initEvents() {
+    $(document).on("click", 'a.comment-close', function(event) {
+      event.preventDefault();
+      hide($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.vote', function(event) {
+      event.preventDefault();
+      handleVote($(this));
+    });
+    $(document).on("click", 'a.reply', function(event) {
+      event.preventDefault();
+      openReply($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.close-reply', function(event) {
+      event.preventDefault();
+      closeReply($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.sort-option', function(event) {
+      event.preventDefault();
+      handleReSort($(this));
+    });
+    $(document).on("click", 'a.show-proposal', function(event) {
+      event.preventDefault();
+      showProposal($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.hide-proposal', function(event) {
+      event.preventDefault();
+      hideProposal($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.show-propose-change', function(event) {
+      event.preventDefault();
+      showProposeChange($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.hide-propose-change', function(event) {
+      event.preventDefault();
+      hideProposeChange($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.accept-comment', function(event) {
+      event.preventDefault();
+      acceptComment($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.delete-comment', function(event) {
+      event.preventDefault();
+      deleteComment($(this).attr('id').substring(2));
+    });
+    $(document).on("click", 'a.comment-markup', function(event) {
+      event.preventDefault();
+      toggleCommentMarkupBox($(this).attr('id').substring(2));
+    });
+  }
+
+  /**
+   * Set comp, which is a comparator function used for sorting and
+   * inserting comments into the list.
+   */
+  function setComparator() {
+    // If the first three letters are "asc", sort in ascending order
+    // and remove the prefix.
+    if (by.substring(0,3) == 'asc') {
+      var i = by.substring(3);
+      comp = function(a, b) { return a[i] - b[i]; };
+    } else {
+      // Otherwise sort in descending order.
+      comp = function(a, b) { return b[by] - a[by]; };
+    }
+
+    // Reset link styles and format the selected sort option.
+    $('a.sel').attr('href', '#').removeClass('sel');
+    $('a.by' + by).removeAttr('href').addClass('sel');
+  }
+
+  /**
+   * Create a comp function. If the user has preferences stored in
+   * the sortBy cookie, use those, otherwise use the default.
+   */
+  function initComparator() {
+    by = 'rating'; // Default to sort by rating.
+    // If the sortBy cookie is set, use that instead.
+    if (document.cookie.length > 0) {
+      var start = document.cookie.indexOf('sortBy=');
+      if (start != -1) {
+        start = start + 7;
+        var end = document.cookie.indexOf(";", start);
+        if (end == -1) {
+          end = document.cookie.length;
+          by = unescape(document.cookie.substring(start, end));
+        }
+      }
+    }
+    setComparator();
+  }
+
+  /**
+   * Show a comment div.
+   */
+  function show(id) {
+    $('#ao' + id).hide();
+    $('#ah' + id).show();
+    var context = $.extend({id: id}, opts);
+    var popup = $(renderTemplate(popupTemplate, context)).hide();
+    popup.find('textarea[name="proposal"]').hide();
+    popup.find('a.by' + by).addClass('sel');
+    var form = popup.find('#cf' + id);
+    form.submit(function(event) {
+      event.preventDefault();
+      addComment(form);
+    });
+    $('#s' + id).after(popup);
+    popup.slideDown('fast', function() {
+      getComments(id);
+    });
+  }
+
+  /**
+   * Hide a comment div.
+   */
+  function hide(id) {
+    $('#ah' + id).hide();
+    $('#ao' + id).show();
+    var div = $('#sc' + id);
+    div.slideUp('fast', function() {
+      div.remove();
+    });
+  }
+
+  /**
+   * Perform an ajax request to get comments for a node
+   * and insert the comments into the comments tree.
+   */
+  function getComments(id) {
+    $.ajax({
+     type: 'GET',
+     url: opts.getCommentsURL,
+     data: {node: id},
+     success: function(data, textStatus, request) {
+       var ul = $('#cl' + id);
+       var speed = 100;
+       $('#cf' + id)
+         .find('textarea[name="proposal"]')
+         .data('source', data.source);
+
+       if (data.comments.length === 0) {
+         ul.html('<li>No comments yet.</li>');
+         ul.data('empty', true);
+       } else {
+         // If there are comments, sort them and put them in the list.
+         var comments = sortComments(data.comments);
+         speed = data.comments.length * 100;
+         appendComments(comments, ul);
+         ul.data('empty', false);
+       }
+       $('#cn' + id).slideUp(speed + 200);
+       ul.slideDown(speed);
+     },
+     error: function(request, textStatus, error) {
+       showError('Oops, there was a problem retrieving the comments.');
+     },
+     dataType: 'json'
+    });
+  }
+
+  /**
+   * Add a comment via ajax and insert the comment into the comment tree.
+   */
+  function addComment(form) {
+    var node_id = form.find('input[name="node"]').val();
+    var parent_id = form.find('input[name="parent"]').val();
+    var text = form.find('textarea[name="comment"]').val();
+    var proposal = form.find('textarea[name="proposal"]').val();
+
+    if (text == '') {
+      showError('Please enter a comment.');
+      return;
+    }
+
+    // Disable the form that is being submitted.
+    form.find('textarea,input').attr('disabled', 'disabled');
+
+    // Send the comment to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.addCommentURL,
+      dataType: 'json',
+      data: {
+        node: node_id,
+        parent: parent_id,
+        text: text,
+        proposal: proposal
+      },
+      success: function(data, textStatus, error) {
+        // Reset the form.
+        if (node_id) {
+          hideProposeChange(node_id);
+        }
+        form.find('textarea')
+          .val('')
+          .add(form.find('input'))
+          .removeAttr('disabled');
+       var ul = $('#cl' + (node_id || parent_id));
+        if (ul.data('empty')) {
+          $(ul).empty();
+          ul.data('empty', false);
+        }
+        insertComment(data.comment);
+        var ao = $('#ao' + node_id);
+        ao.find('img').attr({'src': opts.commentBrightImage});
+        if (node_id) {
+          // if this was a "root" comment, remove the commenting box
+          // (the user can get it back by reopening the comment popup)
+          $('#ca' + node_id).slideUp();
+        }
+      },
+      error: function(request, textStatus, error) {
+        form.find('textarea,input').removeAttr('disabled');
+        showError('Oops, there was a problem adding the comment.');
+      }
+    });
+  }
+
+  /**
+   * Recursively append comments to the main comment list and children
+   * lists, creating the comment tree.
+   */
+  function appendComments(comments, ul) {
+    $.each(comments, function() {
+      var div = createCommentDiv(this);
+      ul.append($(document.createElement('li')).html(div));
+      appendComments(this.children, div.find('ul.comment-children'));
+      // To avoid stagnating data, don't store the comments children in data.
+      this.children = null;
+      div.data('comment', this);
+    });
+  }
+
+  /**
+   * After adding a new comment, it must be inserted in the correct
+   * location in the comment tree.
+   */
+  function insertComment(comment) {
+    var div = createCommentDiv(comment);
+
+    // To avoid stagnating data, don't store the comments children in data.
+    comment.children = null;
+    div.data('comment', comment);
+
+    var ul = $('#cl' + (comment.node || comment.parent));
+    var siblings = getChildren(ul);
+
+    var li = $(document.createElement('li'));
+    li.hide();
+
+    // Determine where in the parents children list to insert this comment.
+    for(i=0; i < siblings.length; i++) {
+      if (comp(comment, siblings[i]) <= 0) {
+        $('#cd' + siblings[i].id)
+          .parent()
+          .before(li.html(div));
+        li.slideDown('fast');
+        return;
+      }
+    }
+
+    // If we get here, this comment rates lower than all the others,
+    // or it is the only comment in the list.
+    ul.append(li.html(div));
+    li.slideDown('fast');
+  }
+
+  function acceptComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.acceptCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        $('#cm' + id).fadeOut('fast');
+        $('#cd' + id).removeClass('moderate');
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem accepting the comment.');
+      }
+    });
+  }
+
+  function deleteComment(id) {
+    $.ajax({
+      type: 'POST',
+      url: opts.deleteCommentURL,
+      data: {id: id},
+      success: function(data, textStatus, request) {
+        var div = $('#cd' + id);
+        if (data == 'delete') {
+          // Moderator mode: remove the comment and all children immediately
+          div.slideUp('fast', function() {
+            div.remove();
+          });
+          return;
+        }
+        // User mode: only mark the comment as deleted
+        div
+          .find('span.user-id:first')
+          .text('[deleted]').end()
+          .find('div.comment-text:first')
+          .text('[deleted]').end()
+          .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
+                ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
+          .remove();
+        var comment = div.data('comment');
+        comment.username = '[deleted]';
+        comment.text = '[deleted]';
+        div.data('comment', comment);
+      },
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem deleting the comment.');
+      }
+    });
+  }
+
+  function showProposal(id) {
+    $('#sp' + id).hide();
+    $('#hp' + id).show();
+    $('#pr' + id).slideDown('fast');
+  }
+
+  function hideProposal(id) {
+    $('#hp' + id).hide();
+    $('#sp' + id).show();
+    $('#pr' + id).slideUp('fast');
+  }
+
+  function showProposeChange(id) {
+    $('#pc' + id).hide();
+    $('#hc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val(textarea.data('source'));
+    $.fn.autogrow.resize(textarea[0]);
+    textarea.slideDown('fast');
+  }
+
+  function hideProposeChange(id) {
+    $('#hc' + id).hide();
+    $('#pc' + id).show();
+    var textarea = $('#pt' + id);
+    textarea.val('').removeAttr('disabled');
+    textarea.slideUp('fast');
+  }
+
+  function toggleCommentMarkupBox(id) {
+    $('#mb' + id).toggle();
+  }
+
+  /** Handle when the user clicks on a sort by link. */
+  function handleReSort(link) {
+    var classes = link.attr('class').split(/\s+/);
+    for (var i=0; i<classes.length; i++) {
+      if (classes[i] != 'sort-option') {
+       by = classes[i].substring(2);
+      }
+    }
+    setComparator();
+    // Save/update the sortBy cookie.
+    var expiration = new Date();
+    expiration.setDate(expiration.getDate() + 365);
+    document.cookie= 'sortBy=' + escape(by) +
+                     ';expires=' + expiration.toUTCString();
+    $('ul.comment-ul').each(function(index, ul) {
+      var comments = getChildren($(ul), true);
+      comments = sortComments(comments);
+      appendComments(comments, $(ul).empty());
+    });
+  }
+
+  /**
+   * Function to process a vote when a user clicks an arrow.
+   */
+  function handleVote(link) {
+    if (!opts.voting) {
+      showError("You'll need to login to vote.");
+      return;
+    }
+
+    var id = link.attr('id');
+    if (!id) {
+      // Didn't click on one of the voting arrows.
+      return;
+    }
+    // If it is an unvote, the new vote value is 0,
+    // Otherwise it's 1 for an upvote, or -1 for a downvote.
+    var value = 0;
+    if (id.charAt(1) != 'u') {
+      value = id.charAt(0) == 'u' ? 1 : -1;
+    }
+    // The data to be sent to the server.
+    var d = {
+      comment_id: id.substring(2),
+      value: value
+    };
+
+    // Swap the vote and unvote links.
+    link.hide();
+    $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
+      .show();
+
+    // The div the comment is displayed in.
+    var div = $('div#cd' + d.comment_id);
+    var data = div.data('comment');
+
+    // If this is not an unvote, and the other vote arrow has
+    // already been pressed, unpress it.
+    if ((d.value !== 0) && (data.vote === d.value * -1)) {
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
+      $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
+    }
+
+    // Update the comments rating in the local data.
+    data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
+    data.vote = d.value;
+    div.data('comment', data);
+
+    // Change the rating text.
+    div.find('.rating:first')
+      .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
+
+    // Send the vote information to the server.
+    $.ajax({
+      type: "POST",
+      url: opts.processVoteURL,
+      data: d,
+      error: function(request, textStatus, error) {
+        showError('Oops, there was a problem casting that vote.');
+      }
+    });
+  }
+
+  /**
+   * Open a reply form used to reply to an existing comment.
+   */
+  function openReply(id) {
+    // Swap out the reply link for the hide link
+    $('#rl' + id).hide();
+    $('#cr' + id).show();
+
+    // Add the reply li to the children ul.
+    var div = $(renderTemplate(replyTemplate, {id: id})).hide();
+    $('#cl' + id)
+      .prepend(div)
+      // Setup the submit handler for the reply form.
+      .find('#rf' + id)
+      .submit(function(event) {
+        event.preventDefault();
+        addComment($('#rf' + id));
+        closeReply(id);
+      })
+      .find('input[type=button]')
+      .click(function() {
+        closeReply(id);
+      });
+    div.slideDown('fast', function() {
+      $('#rf' + id).find('textarea').focus();
+    });
+  }
+
+  /**
+   * Close the reply form opened with openReply.
+   */
+  function closeReply(id) {
+    // Remove the reply div from the DOM.
+    $('#rd' + id).slideUp('fast', function() {
+      $(this).remove();
+    });
+
+    // Swap out the hide link for the reply link
+    $('#cr' + id).hide();
+    $('#rl' + id).show();
+  }
+
+  /**
+   * Recursively sort a tree of comments using the comp comparator.
+   */
+  function sortComments(comments) {
+    comments.sort(comp);
+    $.each(comments, function() {
+      this.children = sortComments(this.children);
+    });
+    return comments;
+  }
+
+  /**
+   * Get the children comments from a ul. If recursive is true,
+   * recursively include childrens' children.
+   */
+  function getChildren(ul, recursive) {
+    var children = [];
+    ul.children().children("[id^='cd']")
+      .each(function() {
+        var comment = $(this).data('comment');
+        if (recursive)
+          comment.children = getChildren($(this).find('#cl' + comment.id), true);
+        children.push(comment);
+      });
+    return children;
+  }
+
+  /** Create a div to display a comment in. */
+  function createCommentDiv(comment) {
+    if (!comment.displayed && !opts.moderator) {
+      return $('<div class="moderate">Thank you!  Your comment will show up '
+               + 'once it is has been approved by a moderator.</div>');
+    }
+    // Prettify the comment rating.
+    comment.pretty_rating = comment.rating + ' point' +
+      (comment.rating == 1 ? '' : 's');
+    // Make a class (for displaying not yet moderated comments differently)
+    comment.css_class = comment.displayed ? '' : ' moderate';
+    // Create a div for this comment.
+    var context = $.extend({}, opts, comment);
+    var div = $(renderTemplate(commentTemplate, context));
+
+    // If the user has voted on this comment, highlight the correct arrow.
+    if (comment.vote) {
+      var direction = (comment.vote == 1) ? 'u' : 'd';
+      div.find('#' + direction + 'v' + comment.id).hide();
+      div.find('#' + direction + 'u' + comment.id).show();
+    }
+
+    if (opts.moderator || comment.text != '[deleted]') {
+      div.find('a.reply').show();
+      if (comment.proposal_diff)
+        div.find('#sp' + comment.id).show();
+      if (opts.moderator && !comment.displayed)
+        div.find('#cm' + comment.id).show();
+      if (opts.moderator || (opts.username == comment.username))
+        div.find('#dc' + comment.id).show();
+    }
+    return div;
+  }
+
+  /**
+   * A simple template renderer. Placeholders such as <%id%> are replaced
+   * by context['id'] with items being escaped. Placeholders such as <#id#>
+   * are not escaped.
+   */
+  function renderTemplate(template, context) {
+    var esc = $(document.createElement('div'));
+
+    function handle(ph, escape) {
+      var cur = context;
+      $.each(ph.split('.'), function() {
+        cur = cur[this];
+      });
+      return escape ? esc.text(cur || "").html() : cur;
+    }
+
+    return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
+      return handle(arguments[2], arguments[1] == '%' ? true : false);
+    });
+  }
+
+  /** Flash an error message briefly. */
+  function showError(message) {
+    $(document.createElement('div')).attr({'class': 'popup-error'})
+      .append($(document.createElement('div'))
+               .attr({'class': 'error-message'}).text(message))
+      .appendTo('body')
+      .fadeIn("slow")
+      .delay(2000)
+      .fadeOut("slow");
+  }
+
+  /** Add a link the user uses to open the comments popup. */
+  $.fn.comment = function() {
+    return this.each(function() {
+      var id = $(this).attr('id').substring(1);
+      var count = COMMENT_METADATA[id];
+      var title = count + ' comment' + (count == 1 ? '' : 's');
+      var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
+      var addcls = count == 0 ? ' nocomment' : '';
+      $(this)
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-open' + addcls,
+            id: 'ao' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: image,
+              alt: 'comment',
+              title: title
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              show($(this).attr('id').substring(2));
+            })
+        )
+        .append(
+          $(document.createElement('a')).attr({
+            href: '#',
+            'class': 'sphinx-comment-close hidden',
+            id: 'ah' + id
+          })
+            .append($(document.createElement('img')).attr({
+              src: opts.closeCommentImage,
+              alt: 'close',
+              title: 'close'
+            }))
+            .click(function(event) {
+              event.preventDefault();
+              hide($(this).attr('id').substring(2));
+            })
+        );
+    });
+  };
+
+  var opts = {
+    processVoteURL: '/_process_vote',
+    addCommentURL: '/_add_comment',
+    getCommentsURL: '/_get_comments',
+    acceptCommentURL: '/_accept_comment',
+    deleteCommentURL: '/_delete_comment',
+    commentImage: '/static/_static/comment.png',
+    closeCommentImage: '/static/_static/comment-close.png',
+    loadingImage: '/static/_static/ajax-loader.gif',
+    commentBrightImage: '/static/_static/comment-bright.png',
+    upArrow: '/static/_static/up.png',
+    downArrow: '/static/_static/down.png',
+    upArrowPressed: '/static/_static/up-pressed.png',
+    downArrowPressed: '/static/_static/down-pressed.png',
+    voting: false,
+    moderator: false
+  };
+
+  if (typeof COMMENT_OPTIONS != "undefined") {
+    opts = jQuery.extend(opts, COMMENT_OPTIONS);
+  }
+
+  var popupTemplate = '\
+    <div class="sphinx-comments" id="sc<%id%>">\
+      <p class="sort-options">\
+        Sort by:\
+        <a href="#" class="sort-option byrating">best rated</a>\
+        <a href="#" class="sort-option byascage">newest</a>\
+        <a href="#" class="sort-option byage">oldest</a>\
+      </p>\
+      <div class="comment-header">Comments</div>\
+      <div class="comment-loading" id="cn<%id%>">\
+        loading comments... <img src="<%loadingImage%>" alt="" /></div>\
+      <ul id="cl<%id%>" class="comment-ul"></ul>\
+      <div id="ca<%id%>">\
+      <p class="add-a-comment">Add a comment\
+        (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
+      <div class="comment-markup-box" id="mb<%id%>">\
+        reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
+        <code>``code``</code>, \
+        code blocks: <code>::</code> and an indented block after blank line</div>\
+      <form method="post" id="cf<%id%>" class="comment-form" action="">\
+        <textarea name="comment" cols="80"></textarea>\
+        <p class="propose-button">\
+          <a href="#" id="pc<%id%>" class="show-propose-change">\
+            Propose a change &#9657;\
+          </a>\
+          <a href="#" id="hc<%id%>" class="hide-propose-change">\
+            Propose a change &#9663;\
+          </a>\
+        </p>\
+        <textarea name="proposal" id="pt<%id%>" cols="80"\
+                  spellcheck="false"></textarea>\
+        <input type="submit" value="Add comment" />\
+        <input type="hidden" name="node" value="<%id%>" />\
+        <input type="hidden" name="parent" value="" />\
+      </form>\
+      </div>\
+    </div>';
+
+  var commentTemplate = '\
+    <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
+      <div class="vote">\
+        <div class="arrow">\
+          <a href="#" id="uv<%id%>" class="vote" title="vote up">\
+            <img src="<%upArrow%>" />\
+          </a>\
+          <a href="#" id="uu<%id%>" class="un vote" title="vote up">\
+            <img src="<%upArrowPressed%>" />\
+          </a>\
+        </div>\
+        <div class="arrow">\
+          <a href="#" id="dv<%id%>" class="vote" title="vote down">\
+            <img src="<%downArrow%>" id="da<%id%>" />\
+          </a>\
+          <a href="#" id="du<%id%>" class="un vote" title="vote down">\
+            <img src="<%downArrowPressed%>" />\
+          </a>\
+        </div>\
+      </div>\
+      <div class="comment-content">\
+        <p class="tagline comment">\
+          <span class="user-id"><%username%></span>\
+          <span class="rating"><%pretty_rating%></span>\
+          <span class="delta"><%time.delta%></span>\
+        </p>\
+        <div class="comment-text comment"><#text#></div>\
+        <p class="comment-opts comment">\
+          <a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
+          <a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
+          <a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
+          <a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
+          <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
+          <span id="cm<%id%>" class="moderation hidden">\
+            <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
+          </span>\
+        </p>\
+        <pre class="proposal" id="pr<%id%>">\
+<#proposal_diff#>\
+        </pre>\
+          <ul class="comment-children" id="cl<%id%>"></ul>\
+        </div>\
+        <div class="clearleft"></div>\
+      </div>\
+    </div>';
+
+  var replyTemplate = '\
+    <li>\
+      <div class="reply-div" id="rd<%id%>">\
+        <form id="rf<%id%>">\
+          <textarea name="comment" cols="80"></textarea>\
+          <input type="submit" value="Add reply" />\
+          <input type="button" value="Cancel" />\
+          <input type="hidden" name="parent" value="<%id%>" />\
+          <input type="hidden" name="node" value="" />\
+        </form>\
+      </div>\
+    </li>';
+
+  $(document).ready(function() {
+    init();
+  });
+})(jQuery);
+
+$(document).ready(function() {
+  // add comment anchors for all paragraphs that are commentable
+  $('.sphinx-has-comment').comment();
+
+  // highlight search words in search results
+  $("div.context").each(function() {
+    var params = $.getQueryParameters();
+    var terms = (params.q) ? params.q[0].split(/\s+/) : [];
+    var result = $(this);
+    $.each(terms, function() {
+      result.highlightText(this.toLowerCase(), 'highlighted');
+    });
+  });
+
+  // directly open comment window if requested
+  var anchor = document.location.hash;
+  if (anchor.substring(0, 9) == '#comment-') {
+    $('#ao' + anchor.substring(9)).click();
+    document.location.hash = '#s' + anchor.substring(9);
+  }
+});
diff --git a/doc/build/Makefile b/doc/build/Makefile
new file mode 100644 (file)
index 0000000..1ca5b74
--- /dev/null
@@ -0,0 +1,137 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = output
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest dist-html site-mako
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dist-html  same as html, but places files in /doc"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+       -rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html -A mako_layout=html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dist-html:
+       $(SPHINXBUILD) -b html -A mako_layout=html $(ALLSPHINXOPTS) ..
+       @echo
+       @echo "Build finished.  The HTML pages are in ../."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SQLAlchemy.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SQLAlchemy.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/SQLAlchemy"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SQLAlchemy"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       cp texinputs/* $(BUILDDIR)/latex/
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       make -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) .
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/build/builder/__init__.py b/doc/build/builder/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/build/builder/builders.py b/doc/build/builder/builders.py
new file mode 100644 (file)
index 0000000..57c88ee
--- /dev/null
@@ -0,0 +1,97 @@
+from sphinx.application import TemplateBridge
+from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.highlighting import PygmentsBridge
+from sphinx.jinja2glue import BuiltinTemplateLoader
+from pygments import highlight
+from pygments.lexer import RegexLexer, bygroups, using
+from pygments.token import *
+from pygments.filter import Filter, apply_filters
+from pygments.lexers import PythonLexer, PythonConsoleLexer
+from pygments.formatters import HtmlFormatter, LatexFormatter
+import re
+import os
+from mako.lookup import TemplateLookup
+from mako.template import Template
+from mako.ext.pygmentplugin import MakoLexer
+
+rtd = os.environ.get('READTHEDOCS', None) == 'True'
+
+class MakoBridge(TemplateBridge):
+    def init(self, builder, *args, **kw):
+        self.jinja2_fallback = BuiltinTemplateLoader()
+        self.jinja2_fallback.init(builder, *args, **kw)
+
+        builder.config.html_context['site_base'] = builder.config['site_base']
+
+        self.lookup = TemplateLookup(
+            directories=builder.config.templates_path,
+            imports=[
+                "from builder import util"
+            ],
+            #format_exceptions=True,
+        )
+
+    def render(self, template, context):
+        template = template.replace(".html", ".mako")
+        context['prevtopic'] = context.pop('prev', None)
+        context['nexttopic'] = context.pop('next', None)
+
+        # RTD layout
+        if rtd:
+            # add variables if not present, such
+            # as if local test of READTHEDOCS variable
+            if 'MEDIA_URL' not in context:
+                context['MEDIA_URL'] = "http://media.readthedocs.org/"
+            if 'slug' not in context:
+                context['slug'] = "mako-test-slug"
+            if 'url' not in context:
+                context['url'] = "/some/test/url"
+            if 'current_version' not in context:
+                context['current_version'] = "some_version"
+            if 'versions' not in context:
+                context['versions'] = [('default', '/default/')]
+
+            context['docs_base'] = "http://readthedocs.org"
+            context['toolbar'] = True
+            context['layout'] = "rtd_layout.mako"
+            context['pdf_url'] = "%spdf/%s/%s/%s.pdf" % (
+                    context['MEDIA_URL'],
+                    context['slug'],
+                    context['current_version'],
+                    context['slug']
+            )
+        # local docs layout
+        else:
+            context['toolbar'] = False
+            context['docs_base'] = "/"
+            context['layout'] = "layout.mako"
+
+        context.setdefault('_', lambda x:x)
+        return self.lookup.get_template(template).render_unicode(**context)
+
+    def render_string(self, template, context):
+        # this is used for  .js, .css etc. and we don't have
+        # local copies of that stuff here so use the jinja render.
+        return self.jinja2_fallback.render_string(template, context)
+
+class StripDocTestFilter(Filter):
+    def filter(self, lexer, stream):
+        for ttype, value in stream:
+            if ttype is Token.Comment and re.match(r'#\s*doctest:', value):
+                continue
+            yield ttype, value
+
+
+def autodoc_skip_member(app, what, name, obj, skip, options):
+    if what == 'class' and skip and name == '__init__':
+        return False
+    else:
+        return skip
+
+def setup(app):
+#    app.connect('autodoc-skip-member', autodoc_skip_member)
+    # Mako is already in Pygments, adding the local
+    # lexer here so that the latest syntax is available
+    app.add_lexer('mako', MakoLexer())
+    app.add_config_value('site_base', "", True)
+
diff --git a/doc/build/builder/util.py b/doc/build/builder/util.py
new file mode 100644 (file)
index 0000000..75a5c72
--- /dev/null
@@ -0,0 +1,12 @@
+import re
+
+def striptags(text):
+    return re.compile(r'<[^>]*>').sub('', text)
+
+def go(m):
+    # .html with no anchor if present, otherwise "#" for top of page
+    return m.group(1) or '#'
+def strip_toplevel_anchors(text):
+    return re.compile(r'(\.html)?#[-\w]+-toplevel').sub(go, text)
diff --git a/doc/build/caching.rst b/doc/build/caching.rst
new file mode 100644 (file)
index 0000000..bfe4f41
--- /dev/null
@@ -0,0 +1,387 @@
+.. _caching_toplevel:
+
+=======
+Caching
+=======
+
+Any template or component can be cached using the ``cache``
+argument to the ``<%page>``, ``<%def>`` or ``<%block>`` directives:
+
+.. sourcecode:: mako
+
+    <%page cached="True"/>
+
+    template text
+
+The above template, after being executed the first time, will
+store its content within a cache that by default is scoped
+within memory. Subsequent calls to the template's :meth:`~.Template.render`
+method will return content directly from the cache. When the
+:class:`.Template` object itself falls out of scope, its corresponding
+cache is garbage collected along with the template.
+
+The caching system requires that a cache backend be installed; this
+includes either the `Beaker <http://beaker.readthedocs.org/>`_ package
+or the `dogpile.cache <http://dogpilecache.readthedocs.org>`_, as well as
+any other third-party caching libraries that feature Mako integration.
+
+By default, caching will attempt to make use of Beaker.
+To use dogpile.cache, the
+``cache_impl`` argument must be set; see this argument in the
+section :ref:`cache_arguments`.
+
+In addition to being available on the ``<%page>`` tag, the caching flag and all
+its options can be used with the ``<%def>`` tag as well:
+
+.. sourcecode:: mako
+
+    <%def name="mycomp" cached="True" cache_timeout="60">
+        other text
+    </%def>
+
+... and equivalently with the ``<%block>`` tag, anonymous or named:
+
+.. sourcecode:: mako
+
+    <%block cached="True" cache_timeout="60">
+        other text
+    </%block>
+
+
+.. _cache_arguments:
+
+Cache Arguments
+===============
+
+Mako has two cache arguments available on tags that are
+available in all cases.   The rest of the arguments
+available are specific to a backend.
+
+The two generic tags arguments are:
+
+* ``cached="True"`` - enable caching for this ``<%page>``,
+  ``<%def>``, or ``<%block>``.
+* ``cache_key`` - the "key" used to uniquely identify this content
+  in the cache.   Usually, this key is chosen automatically
+  based on the name of the rendering callable (i.e. ``body``
+  when used in ``<%page>``, the name of the def when using ``<%def>``,
+  the explicit or internally-generated name when using ``<%block>``).
+  Using the ``cache_key`` parameter, the key can be overridden
+  using a fixed or programmatically generated value.
+
+  For example, here's a page
+  that caches any page which inherits from it, based on the
+  filename of the calling template:
+
+  .. sourcecode:: mako
+
+     <%page cached="True" cache_key="${self.filename}"/>
+
+     ${next.body()}
+
+     ## rest of template
+
+On a :class:`.Template` or :class:`.TemplateLookup`, the
+caching can be configured using these arguments:
+
+* ``cache_enabled`` - Setting this
+  to ``False`` will disable all caching functionality
+  when the template renders.  Defaults to ``True``.
+  e.g.:
+
+  .. sourcecode:: python
+
+      lookup = TemplateLookup(
+                      directories='/path/to/templates',
+                      cache_enabled = False
+                      )
+
+* ``cache_impl`` - The string name of the cache backend
+  to use.   This defaults to ``'beaker'``, indicating
+  that the 'beaker' backend will be used.
+
+* ``cache_args`` - A dictionary of cache parameters that
+  will be consumed by the cache backend.   See
+  :ref:`beaker_backend` and :ref:`dogpile.cache_backend` for examples.
+
+
+Backend-Specific Cache Arguments
+--------------------------------
+
+The ``<%page>``, ``<%def>``, and ``<%block>`` tags
+accept any named argument that starts with the prefix ``"cache_"``.
+Those arguments are then packaged up and passed along to the
+underlying caching implementation, minus the ``"cache_"`` prefix.
+
+The actual arguments understood are determined by the backend.
+
+* :ref:`beaker_backend` - Includes arguments understood by
+  Beaker.
+* :ref:`dogpile.cache_backend` - Includes arguments understood by
+  dogpile.cache.
+
+.. _beaker_backend:
+
+Using the Beaker Cache Backend
+------------------------------
+
+When using Beaker, new implementations will want to make usage
+of **cache regions** so that cache configurations can be maintained
+externally to templates.  These configurations live under
+named "regions" that can be referred to within templates themselves.
+
+.. versionadded:: 0.6.0
+   Support for Beaker cache regions.
+
+For example, suppose we would like two regions.  One is a "short term"
+region that will store content in a memory-based dictionary,
+expiring after 60 seconds.   The other is a Memcached region,
+where values should expire in five minutes.   To configure
+our :class:`.TemplateLookup`, first we get a handle to a
+:class:`beaker.cache.CacheManager`:
+
+.. sourcecode:: python
+
+    from beaker.cache import CacheManager
+
+    manager = CacheManager(cache_regions={
+        'short_term':{
+            'type': 'memory',
+            'expire': 60
+        },
+        'long_term':{
+            'type': 'ext:memcached',
+            'url': '127.0.0.1:11211',
+            'expire': 300
+        }
+    })
+
+    lookup = TemplateLookup(
+                    directories=['/path/to/templates'],
+                    module_directory='/path/to/modules',
+                    cache_impl='beaker',
+                    cache_args={
+                        'manager':manager
+                    }
+            )
+
+Our templates can then opt to cache data in one of either region,
+using the ``cache_region`` argument.   Such as using ``short_term``
+at the ``<%page>`` level:
+
+.. sourcecode:: mako
+
+    <%page cached="True" cache_region="short_term">
+
+    ## ...
+
+Or, ``long_term`` at the ``<%block>`` level:
+
+.. sourcecode:: mako
+
+    <%block name="header" cached="True" cache_region="long_term">
+        other text
+    </%block>
+
+The Beaker backend also works without regions.   There are a
+variety of arguments that can be passed to the ``cache_args``
+dictionary, which are also allowable in templates via the
+``<%page>``, ``<%block>``,
+and ``<%def>`` tags specific to those sections.   The values
+given override those specified at the  :class:`.TemplateLookup`
+or :class:`.Template` level.
+
+With the possible exception
+of ``cache_timeout``, these arguments are probably better off
+staying at the template configuration level.  Each argument
+specified as ``cache_XYZ`` in a template tag is specified
+without the ``cache_`` prefix in the ``cache_args`` dictionary:
+
+* ``cache_timeout`` - number of seconds in which to invalidate the
+  cached data.  After this timeout, the content is re-generated
+  on the next call.  Available as ``timeout`` in the ``cache_args``
+  dictionary.
+* ``cache_type`` - type of caching. ``'memory'``, ``'file'``, ``'dbm'``, or
+  ``'ext:memcached'`` (note that  the string ``memcached`` is
+  also accepted by the dogpile.cache Mako plugin, though not by Beaker itself).
+  Available as ``type`` in the ``cache_args`` dictionary.
+* ``cache_url`` - (only used for ``memcached`` but required) a single
+  IP address or a semi-colon separated list of IP address of
+  memcache servers to use.  Available as ``url`` in the ``cache_args``
+  dictionary.
+* ``cache_dir`` - in the case of the ``'file'`` and ``'dbm'`` cache types,
+  this is the filesystem directory with which to store data
+  files. If this option is not present, the value of
+  ``module_directory`` is used (i.e. the directory where compiled
+  template modules are stored). If neither option is available
+  an exception is thrown.  Available as ``dir`` in the
+  ``cache_args`` dictionary.
+
+.. _dogpile.cache_backend:
+
+Using the dogpile.cache Backend
+-------------------------------
+
+`dogpile.cache`_ is a new replacement for Beaker.   It provides
+a modernized, slimmed down interface and is generally easier to use
+than Beaker.   As of this writing it has not yet been released.  dogpile.cache
+includes its own Mako cache plugin -- see :mod:`dogpile.cache.plugins.mako_cache` in the
+dogpile.cache documentation.
+
+Programmatic Cache Access
+=========================
+
+The :class:`.Template`, as well as any template-derived :class:`.Namespace`, has
+an accessor called ``cache`` which returns the :class:`.Cache` object
+for that template. This object is a facade on top of the underlying
+:class:`.CacheImpl` object, and provides some very rudimental
+capabilities, such as the ability to get and put arbitrary
+values:
+
+.. sourcecode:: mako
+
+    <%
+        local.cache.set("somekey", type="memory", "somevalue")
+    %>
+
+Above, the cache associated with the ``local`` namespace is
+accessed and a key is placed within a memory cache.
+
+More commonly, the ``cache`` object is used to invalidate cached
+sections programmatically:
+
+.. sourcecode:: python
+
+    template = lookup.get_template('/sometemplate.html')
+
+    # invalidate the "body" of the template
+    template.cache.invalidate_body()
+
+    # invalidate an individual def
+    template.cache.invalidate_def('somedef')
+
+    # invalidate an arbitrary key
+    template.cache.invalidate('somekey')
+
+You can access any special method or attribute of the :class:`.CacheImpl`
+itself using the :attr:`impl <.Cache.impl>` attribute:
+
+.. sourcecode:: python
+
+    template.cache.impl.do_something_special()
+
+Note that using implementation-specific methods will mean you can't
+swap in a different kind of :class:`.CacheImpl` implementation at a
+later time.
+
+.. _cache_plugins:
+
+Cache Plugins
+=============
+
+The mechanism used by caching can be plugged in
+using a :class:`.CacheImpl` subclass.    This class implements
+the rudimental methods Mako needs to implement the caching
+API.   Mako includes the :class:`.BeakerCacheImpl` class to
+provide the default implementation.  A :class:`.CacheImpl` class
+is acquired by Mako using a ``pkg_resources`` entrypoint, using
+the name given as the ``cache_impl`` argument to :class:`.Template`
+or :class:`.TemplateLookup`.    This entry point can be
+installed via the standard `setuptools`/``setup()`` procedure, underneath
+the `EntryPoint` group named ``"mako.cache"``.  It can also be
+installed at runtime via a convenience installer :func:`.register_plugin`
+which accomplishes essentially the same task.
+
+An example plugin that implements a local dictionary cache:
+
+.. sourcecode:: python
+
+    from mako.cache import Cacheimpl, register_plugin
+
+    class SimpleCacheImpl(CacheImpl):
+        def __init__(self, cache):
+            super(SimpleCacheImpl, self).__init__(cache)
+            self._cache = {}
+
+        def get_or_create(self, key, creation_function, **kw):
+            if key in self._cache:
+                return self._cache[key]
+            else:
+                self._cache[key] = value = creation_function()
+                return value
+
+        def set(self, key, value, **kwargs):
+            self._cache[key] = value
+
+        def get(self, key, **kwargs):
+            return self._cache.get(key)
+
+        def invalidate(self, key, **kwargs):
+            self._cache.pop(key, None)
+
+    # optional - register the class locally
+    register_plugin("simple", __name__, "SimpleCacheImpl")
+
+Enabling the above plugin in a template would look like:
+
+.. sourcecode:: python
+
+    t = Template("mytemplate",
+                 file="mytemplate.html",
+                 cache_impl='simple')
+
+Guidelines for Writing Cache Plugins
+------------------------------------
+
+* The :class:`.CacheImpl` is created on a per-:class:`.Template` basis.  The
+  class should ensure that only data for the parent :class:`.Template` is
+  persisted or returned by the cache methods.    The actual :class:`.Template`
+  is available via the ``self.cache.template`` attribute.   The ``self.cache.id``
+  attribute, which is essentially the unique modulename of the template, is
+  a good value to use in order to represent a unique namespace of keys specific
+  to the template.
+* Templates only use the :meth:`.CacheImpl.get_or_create()` method
+  in an implicit fashion.  The :meth:`.CacheImpl.set`,
+  :meth:`.CacheImpl.get`, and :meth:`.CacheImpl.invalidate` methods are
+  only used in response to direct programmatic access to the corresponding
+  methods on the :class:`.Cache` object.
+* :class:`.CacheImpl` will be accessed in a multithreaded fashion if the
+  :class:`.Template` itself is used multithreaded.  Care should be taken
+  to ensure caching implementations are threadsafe.
+* A library like `Dogpile <http://pypi.python.org/pypi/dogpile.core>`_, which
+  is a minimal locking system derived from Beaker, can be used to help
+  implement the :meth:`.CacheImpl.get_or_create` method in a threadsafe
+  way that can maximize effectiveness across multiple threads as well
+  as processes. :meth:`.CacheImpl.get_or_create` is the
+  key method used by templates.
+* All arguments passed to ``**kw`` come directly from the parameters
+  inside the ``<%def>``, ``<%block>``, or ``<%page>`` tags directly,
+  minus the ``"cache_"`` prefix, as strings, with the exception of
+  the argument ``cache_timeout``, which is passed to the plugin
+  as the name ``timeout`` with the value converted to an integer.
+  Arguments present in ``cache_args`` on :class:`.Template` or
+  :class:`.TemplateLookup` are passed directly, but are superseded
+  by those present in the most specific template tag.
+* The directory where :class:`.Template` places module files can
+  be acquired using the accessor ``self.cache.template.module_directory``.
+  This directory can be a good place to throw cache-related work
+  files, underneath a prefix like ``_my_cache_work`` so that name
+  conflicts with generated modules don't occur.
+
+API Reference
+=============
+
+.. autoclass:: mako.cache.Cache
+    :members:
+    :show-inheritance:
+
+.. autoclass:: mako.cache.CacheImpl
+    :members:
+    :show-inheritance:
+
+.. autofunction:: mako.cache.register_plugin
+
+.. autoclass:: mako.ext.beaker_cache.BeakerCacheImpl
+    :members:
+    :show-inheritance:
+
diff --git a/doc/build/changelog.rst b/doc/build/changelog.rst
new file mode 100644 (file)
index 0000000..7d110f3
--- /dev/null
@@ -0,0 +1,2126 @@
+=========
+Changelog
+=========
+
+1.0
+===
+
+.. changelog::
+    :version: 1.0.6
+    :released: Wed Nov 9 2016
+
+    .. change::
+        :tags: feature
+
+      Added new parameter :paramref:`.Template.include_error_handler` .
+      This works like :paramref:`.Template.error_handler` but indicates the
+      handler should take place when this template is included within another
+      template via the ``<%include>`` tag.  Pull request courtesy
+      Huayi Zhang.
+
+.. changelog::
+    :version: 1.0.5
+    :released: Wed Nov 2 2016
+
+    .. change::
+        :tags: bug
+
+      Updated the Sphinx documentation builder to work with recent
+      versions of Sphinx.
+
+.. changelog::
+    :version: 1.0.4
+    :released: Thu Mar 10 2016
+
+    .. change::
+        :tags: feature, test
+
+      The default test runner is now py.test.  Running "python setup.py test"
+      will make use of py.test instead of nose.  nose still works as a test
+      runner as well, however.
+
+    .. change::
+        :tags: bug, lexer
+        :pullreq: github:19
+
+      Major improvements to lexing of intricate Python sections which may
+      contain complex backslash sequences, as well as support for the bitwise
+      operator (e.g. pipe symbol) inside of expression sections distinct
+      from the Mako "filter" operator, provided the operator is enclosed
+      within parentheses or brackets.  Pull request courtesy Daniel Martin.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:16
+
+      Added new method :meth:`.Template.list_defs`.   Pull request courtesy
+      Jonathan Vanasco.
+
+.. changelog::
+    :version: 1.0.3
+    :released: Tue Oct 27 2015
+
+    .. change::
+        :tags: bug, babel
+        :pullreq: bitbucket:21
+
+      Fixed an issue where the Babel plugin would not handle a translation
+      symbol that contained non-ascii characters.  Pull request courtesy
+      Roman Imankulov.
+
+.. changelog::
+    :version: 1.0.2
+    :released: Wed Aug 26 2015
+
+    .. change::
+        :tags: bug, installation
+        :tickets: 249
+
+      The "universal wheel" marker is removed from setup.cfg, because
+      our setup.py currently makes use of conditional dependencies.
+      In :ticket:`249`, the discussion is ongoing on how to correct our
+      setup.cfg / setup.py fully so that we can handle the per-version
+      dependency changes while still maintaining optimal wheel settings,
+      so this issue is not yet fully resolved.
+
+    .. change::
+        :tags: bug, py3k
+        :tickets: 250
+
+      Repair some calls within the ast module that no longer work on Python3.5;
+      additionally replace the use of ``inspect.getargspec()`` under
+      Python 3 (seems to be called from the TG plugin) to avoid deprecation
+      warnings.
+
+    .. change::
+        :tags: bug
+        :pullreq: bitbucket:18
+
+      Update the Lingua translation extraction plugin to correctly
+      handle templates mixing Python control statements (such as if,
+      for and while) with template fragments. Pull request courtesy
+      Laurent Daverio.
+
+    .. change::
+        :tags: feature
+        :tickets: 236
+
+      Added ``STOP_RENDERING`` keyword for returning/exiting from a
+      template early, which is a synonym for an empty string ``""``.
+      Previously, the docs suggested a bare
+      ``return``, but this could cause ``None`` to appear in the
+      rendered template result.
+
+      .. seealso::
+
+        :ref:`syntax_exiting_early`
+
+.. changelog::
+    :version: 1.0.1
+    :released: Thu Jan 22 2015
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:9
+
+      Added support for Lingua, a translation extraction system as an
+      alternative to Babel.  Pull request courtesy Wichert Akkerman.
+
+    .. change::
+        :tags: bug, py3k
+        :pullreq: bitbucket:11
+
+      Modernized the examples/wsgi/run_wsgi.py file for Py3k.
+      Pull requset courtesy Cody Taylor.
+
+.. changelog::
+    :version: 1.0.0
+    :released: Sun Jun 8 2014
+
+    .. change::
+        :tags: bug, py2k
+        :pullreq: bitbucket:8
+
+      Improved the error re-raise operation when a custom
+      :paramref:`.Template.error_handler` is used that does not handle
+      the exception; the original stack trace etc. is now preserved.
+      Pull request courtesy Manfred Haltner.
+
+    .. change::
+        :tags: bug, py2k, filters
+        :pullreq: bitbucket:7
+
+      Added an html_escape filter that works in "non unicode" mode.
+      Previously, when using ``disable_unicode=True``, the ``u`` filter
+      would fail to handle non-ASCII bytes properly.  Pull request
+      courtesy George Xie.
+
+    .. change::
+        :tags: general
+
+      Compatibility changes; in order to modernize the codebase, Mako
+      is now dropping support for Python 2.4 and Python 2.5 altogether.
+      The source base is now targeted at Python 2.6 and forwards.
+
+    .. change::
+        :tags: feature
+
+      Template modules now generate a JSON "metadata" structure at the bottom
+      of the source file which includes parseable information about the
+      templates' source file, encoding etc. as well as a mapping of module
+      source lines to template lines, thus replacing the "# SOURCE LINE"
+      markers throughout the source code.  The structure also indicates those
+      lines that are explicitly not part of the template's source; the goal
+      here is to allow better integration with coverage and other tools.
+
+    .. change::
+        :tags: bug, py3k
+
+      Fixed bug in ``decode.<encoding>`` filter where a non-string object
+      would not be correctly interpreted in Python 3.
+
+    .. change::
+        :tags: bug, py3k
+        :tickets: 227
+
+      Fixed bug in Python parsing logic which would fail on Python 3
+      when a "try/except" targeted a tuple of exception types, rather
+      than a single exception.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:5
+
+      mako-render is now implemented as a setuptools entrypoint script;
+      a standalone mako.cmd.cmdline() callable is now available, and the
+      system also uses argparse now instead of optparse.  Pull request
+      courtesy Derek Harland.
+
+    .. change::
+        :tags: feature
+        :pullreq: bitbucket:4
+
+      The mako-render script will now catch exceptions and run them
+      into the text error handler, and exit with a non-zero exit code.
+      Pull request courtesy Derek Harland.
+
+    .. change::
+        :tags: bug
+        :pullreq: bitbucket:2
+
+      A rework of the mako-render script allows the script to run
+      correctly when given a file pathname that is outside of the current
+      directory, e.g. ``mako-render ../some_template.mako``.  In this case,
+      the "template root" defaults to the directory in which the template
+      is located, instead of ".".  The script also accepts a new argument
+      ``--template-dir`` which can be specified multiple times to establish
+      template lookup directories.  Standard input for templates also works
+      now too.  Pull request courtesy Derek Harland.
+
+    .. change::
+        :tags: feature, py3k
+        :pullreq: github:7
+
+      Support is added for Python 3 "keyword only" arguments, as used in
+      defs.  Pull request courtesy Eevee.
+
+
+0.9
+===
+
+.. changelog::
+    :version: 0.9.1
+    :released: Thu Dec 26 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 225
+
+      Fixed bug in Babel plugin where translator comments
+      would be lost if intervening text nodes were encountered.
+      Fix courtesy Ned Batchelder.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed TGPlugin.render method to support unicode template
+      names in Py2K - courtesy Vladimir Magamedov.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed an AST issue that was preventing correct operation
+      under alpha versions of Python 3.4.  Pullreq courtesy Zer0-.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Changed the format of the "source encoding" header output
+      by the code generator to use the format ``# -*- coding:%s -*-``
+      instead of ``# -*- encoding:%s -*-``; the former is more common
+      and compatible with emacs.  Courtesy Martin Geisler.
+
+    .. change::
+        :tags: bug
+        :tickets: 224
+
+      Fixed issue where an old lexer rule prevented a template line
+      which looked like "#*" from being correctly parsed.
+
+.. changelog::
+    :version: 0.9.0
+    :released: Tue Aug 27 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 219
+
+      The Context.locals_() method becomes a private underscored
+      method, as this method has a specific internal use. The purpose
+      of Context.kwargs has been clarified, in that it only delivers
+      top level keyword arguments originally passed to template.render().
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed the babel plugin to properly interpret ${} sections
+      inside of a "call" tag, i.e. <%self:some_tag attr="${_('foo')}"/>.
+      Code that's subject to babel escapes in here needs to be
+      specified as a Python expression, not a literal.  This change
+      is backwards incompatible vs. code that is relying upon a _('')
+      translation to be working within a call tag.
+
+    .. change::
+        :tags: bug
+        :tickets: 187
+
+      The Babel plugin has been repaired to work on Python 3.
+
+    .. change::
+        :tags: bug
+        :tickets: 207
+
+      Using <%namespace import="*" module="somemodule"/> now
+      skips over module elements that are not explcitly callable,
+      avoiding TypeError when trying to produce partials.
+
+    .. change::
+        :tags: bug
+        :tickets: 190
+
+      Fixed Py3K bug where a "lambda" expression was not
+      interpreted correctly within a template tag; also
+      fixed in Py2.4.
+
+0.8
+===
+
+.. changelog::
+    :version: 0.8.1
+    :released: Fri May 24 2013
+
+    .. change::
+        :tags: bug
+        :tickets: 216
+
+      Changed setup.py to skip installing markupsafe
+      if Python version is < 2.6 or is between 3.0 and
+      less than 3.3, as Markupsafe now only supports 2.6->2.X,
+      3.3->3.X.
+
+    .. change::
+        :tags: bug
+        :tickets: 214
+
+      Fixed regression where "entity" filter wasn't
+      converted for py3k properly (added tests.)
+
+    .. change::
+        :tags: bug
+        :tickets: 212
+
+      Fixed bug where mako-render script wasn't
+      compatible with Py3k.
+
+    .. change::
+        :tags: bug
+        :tickets: 213
+
+      Cleaned up all the various deprecation/
+      file warnings when running the tests under
+      various Pythons with warnings turned on.
+
+.. changelog::
+    :version: 0.8.0
+    :released: Wed Apr 10 2013
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Performance improvement to the
+      "legacy" HTML escape feature, used for XML
+      escaping and when markupsafe isn't present,
+      courtesy George Xie.
+
+    .. change::
+        :tags: bug
+        :tickets: 209
+
+      Fixed bug whereby an exception in Python 3
+      against a module compiled to the filesystem would
+      fail trying to produce a RichTraceback due to the
+      content being in bytes.
+
+    .. change::
+        :tags: bug
+        :tickets: 208
+
+      Change default for compile()->reserved_names
+      from tuple to frozenset, as this is expected to be
+      a set by default.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Code has been reworked to support Python 2.4->
+      Python 3.xx in place.  2to3 no longer needed.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added lexer_cls argument to Template,
+      TemplateLookup, allows alternate Lexer classes
+      to be used.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added future_imports parameter to Template
+      and TemplateLookup, renders the __future__ header
+      with desired capabilities at the top of the generated
+      template module.  Courtesy Ben Trofatter.
+
+0.7
+===
+
+.. changelog::
+    :version: 0.7.3
+    :released: Wed Nov 7 2012
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      legacy_html_escape function, used when
+      Markupsafe isn't installed, was using an inline-compiled
+      regexp which causes major slowdowns on Python 3.3;
+      is now precompiled.
+
+    .. change::
+        :tags: bug
+        :tickets: 201
+
+      AST supporting now supports tuple-packed
+      function arguments inside pure-python def
+      or lambda expressions.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed Py3K bug in the Babel extension.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed the "filter" attribute of the
+      <%text> tag so that it pulls locally specified
+      identifiers from the context the same
+      way as that of <%block> and <%filter>.
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Fixed bug in plugin loader to correctly
+      raise exception when non-existent plugin
+      is specified.
+
+.. changelog::
+    :version: 0.7.2
+    :released: Fri Jul 20 2012
+
+    .. change::
+        :tags: bug
+        :tickets: 193
+
+      Fixed regression in 0.7.1 where AST
+      parsing for Py2.4 was broken.
+
+.. changelog::
+    :version: 0.7.1
+    :released: Sun Jul 8 2012
+
+    .. change::
+        :tags: feature
+        :tickets: 146
+
+      Control lines with no bodies will
+      now succeed, as "pass" is added for these
+      when no statements are otherwise present.
+      Courtesy Ben Trofatter
+
+    .. change::
+        :tags: bug
+        :tickets: 192
+
+      Fixed some long-broken scoping behavior
+      involving variables declared in defs and such,
+      which only became apparent when
+      the strict_undefined flag was turned on.
+
+    .. change::
+        :tags: bug
+        :tickets: 191
+
+      Can now use strict_undefined at the
+      same time args passed to def() are used
+      by other elements of the <%def> tag.
+
+.. changelog::
+    :version: 0.7.0
+    :released: Fri Mar 30 2012
+
+    .. change::
+        :tags: feature
+        :tickets: 125
+
+      Added new "loop" variable to templates,
+      is provided within a % for block to provide
+      info about the loop such as index, first/last,
+      odd/even, etc.  A migration path is also provided
+      for legacy templates via the "enable_loop" argument
+      available on Template, TemplateLookup, and <%page>.
+      Thanks to Ben Trofatter for all
+      the work on this
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added a real check for "reserved"
+      names, that is names which are never pulled
+      from the context and cannot be passed to
+      the template.render() method.  Current names
+      are "context", "loop", "UNDEFINED".
+
+    .. change::
+        :tags: feature
+        :tickets: 95
+
+      The html_error_template() will now
+      apply Pygments highlighting to the source
+      code displayed in the traceback, if Pygments
+      if available.  Courtesy Ben Trofatter
+
+    .. change::
+        :tags: feature
+        :tickets: 147
+
+      Added support for context managers,
+      i.e. "% with x as e:/ % endwith" support.
+      Courtesy Ben Trofatter
+
+    .. change::
+        :tags: feature
+        :tickets: 185
+
+      Added class-level flag to CacheImpl
+      "pass_context"; when True, the keyword argument
+      'context' will be passed to get_or_create()
+      containing the Mako Context object.
+
+    .. change::
+        :tags: bug
+        :tickets: 182
+
+      Fixed some Py3K resource warnings due
+      to filehandles being implicitly closed.
+
+    .. change::
+        :tags: bug
+        :tickets: 186
+
+      Fixed endless recursion bug when
+      nesting multiple def-calls with content.
+      Thanks to Jeff Dairiki.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added Jinja2 to the example
+      benchmark suite, courtesy Vincent Férotin
+
+Older Versions
+==============
+
+.. changelog::
+    :version: 0.6.2
+    :released: Thu Feb 2 2012
+
+    .. change::
+        :tags: bug
+        :tickets: 86, 20
+
+      The ${{"foo":"bar"}} parsing issue is fixed!!
+      The legendary Eevee has slain the dragon!.  Also fixes quoting issue
+      at.
+
+.. changelog::
+    :version: 0.6.1
+    :released: Sat Jan 28 2012
+
+    .. change::
+        :tags: bug
+        :tickets:
+
+      Added special compatibility for the 0.5.0
+      Cache() constructor, which was preventing file
+      version checks and not allowing Mako 0.6 to
+      recompile the module files.
+
+.. changelog::
+    :version: 0.6.0
+    :released: Sat Jan 21 2012
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Template caching has been converted into a plugin
+      system, whereby the usage of Beaker is just the
+      default plugin.   Template and TemplateLookup
+      now accept a string "cache_impl" parameter which
+      refers to the name of a cache plugin, defaulting
+      to the name 'beaker'.  New plugins can be
+      registered as pkg_resources entrypoints under
+      the group "mako.cache", or registered directly
+      using mako.cache.register_plugin().  The
+      core plugin is the mako.cache.CacheImpl
+      class.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Added support for Beaker cache regions
+      in templates.   Usage of regions should be considered
+      as superseding the very obsolete idea of passing in
+      backend options, timeouts, etc. within templates.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      The 'put' method on Cache is now
+      'set'.  'put' is there for backwards compatibility.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      The <%def>, <%block> and <%page> tags now accept
+      any argument named "cache_*", and the key
+      minus the "cache_" prefix will be passed as keyword
+      arguments to the CacheImpl methods.
+
+    .. change::
+        :tags: feature
+        :tickets:
+
+      Template and TemplateLookup now accept an argument
+      cache_args, which refers to a dictionary containing
+      cache parameters.  The cache_dir, cache_url, cache_type,
+      cache_timeout arguments are deprecated (will probably
+      never be removed, however) and can be passed
+      now as cache_args={'url':<some url>, 'type':'memcached',
+      'timeout':50, 'dir':'/path/to/some/directory'}
+
+    .. change::
+        :tags: feature/bug
+        :tickets: 180
+
+      Can now refer to context variables
+      within extra arguments to <%block>, <%def>, i.e.
+      <%block name="foo" cache_key="${somekey}">.
+      Filters can also be used in this way, i.e.
+      <%def name="foo()" filter="myfilter">
+      then template.render(myfilter=some_callable)
+
+    .. change::
+        :tags: feature
+        :tickets: 178
+
+      Added "--var name=value" option to the mako-render
+      script, allows passing of kw to the template from
+      the command line.
+
+    .. change::
+        :tags: feature
+        :tickets: 181
+
+      Added module_writer argument to Template,
+      TemplateLookup, allows a callable to be passed which
+      takes over the writing of the template's module source
+      file, so that special environment-specific steps
+      can be taken.
+
+    .. change::
+        :tags: bug
+        :tickets: 142
+
+      The exception message in the html_error_template
+      is now escaped with the HTML filter.
+
+    .. change::
+        :tags: bug
+        :tickets: 173
+
+      Added "white-space:pre" style to html_error_template()
+      for code blocks so that indentation is preserved
+
+    .. change::
+        :tags: bug
+        :tickets: 175
+
+      The "benchmark" example is now Python 3 compatible
+      (even though several of those old template libs aren't
+      available on Py3K, so YMMV)
+
+
+.. changelog::
+    :version: 0.5.0
+    :released: Wed Sep 28 2011
+
+    .. change::
+        :tags:
+        :tickets: 174
+
+      A Template is explicitly disallowed
+      from having a url that normalizes to relative outside
+      of the root.   That is, if the Lookup is based
+      at /home/mytemplates, an include that would place
+      the ultimate template at
+      /home/mytemplates/../some_other_directory,
+      i.e. outside of /home/mytemplates,
+      is disallowed.   This usage was never intended
+      despite the lack of an explicit check.
+      The main issue this causes
+      is that module files can be written outside
+      of the module root (or raise an error, if file perms aren't
+      set up), and can also lead to the same template being
+      cached in the lookup under multiple, relative roots.
+      TemplateLookup instead has always supported multiple
+      file roots for this purpose.
+
+
+.. changelog::
+    :version: 0.4.2
+    :released: Fri Aug 5 2011
+
+    .. change::
+        :tags:
+        :tickets: 170
+
+      Fixed bug regarding <%call>/def calls w/ content
+      whereby the identity of the "caller" callable
+      inside the <%def> would be corrupted by the
+      presence of another <%call> in the same block.
+
+    .. change::
+        :tags:
+        :tickets: 169
+
+      Fixed the babel plugin to accommodate <%block>
+
+.. changelog::
+    :version: 0.4.1
+    :released: Wed Apr 6 2011
+
+    .. change::
+        :tags:
+        :tickets: 164
+
+      New tag: <%block>.  A variant on <%def> that
+      evaluates its contents in-place.
+      Can be named or anonymous,
+      the named version is intended for inheritance
+      layouts where any given section can be
+      surrounded by the <%block> tag in order for
+      it to become overrideable by inheriting
+      templates, without the need to specify a
+      top-level <%def> plus explicit call.
+      Modified scoping and argument rules as well as a
+      more strictly enforced usage scheme make it ideal
+      for this purpose without at all replacing most
+      other things that defs are still good for.
+      Lots of new docs.
+
+    .. change::
+        :tags:
+        :tickets: 165
+
+      a slight adjustment to the "highlight" logic
+      for generating template bound stacktraces.
+      Will stick to known template source lines
+      without any extra guessing.
+
+.. changelog::
+    :version: 0.4.0
+    :released: Sun Mar 6 2011
+
+    .. change::
+        :tags:
+        :tickets:
+
+      A 20% speedup for a basic two-page
+      inheritance setup rendering
+      a table of escaped data
+      (see http://techspot.zzzeek.org/2010/11/19/quick-mako-vs.-jinja-speed-test/).
+      A few configurational changes which
+      affect those in the I-don't-do-unicode
+      camp should be noted below.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The FastEncodingBuffer is now used
+      by default instead of cStringIO or StringIO,
+      regardless of whether output_encoding
+      is set to None or not.  FEB is faster than
+      both.  Only StringIO allows bytestrings
+      of unknown encoding to pass right
+      through, however - while it is of course
+      not recommended to send bytestrings of unknown
+      encoding to the output stream, this
+      mode of usage can be re-enabled by
+      setting the flag bytestring_passthrough
+      to True.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      disable_unicode mode requires that
+      output_encoding be set to None - it also
+      forces the bytestring_passthrough flag
+      to True.
+
+    .. change::
+        :tags:
+        :tickets: 156
+
+      the <%namespace> tag raises an error
+      if the 'template' and 'module' attributes
+      are specified at the same time in
+      one tag.  A different class is used
+      for each case which allows a reduction in
+      runtime conditional logic and function
+      call overhead.
+
+    .. change::
+        :tags:
+        :tickets: 159
+
+      the keys() in the Context, as well as
+      it's internal _data dictionary, now
+      include just what was specified to
+      render() as well as Mako builtins
+      'caller', 'capture'.  The contents
+      of __builtin__ are no longer copied.
+      Thanks to Daniel Lopez for pointing
+      this out.
+
+
+.. changelog::
+    :version: 0.3.6
+    :released: Sat Nov 13 2010
+
+    .. change::
+        :tags:
+        :tickets: 126
+
+      Documentation is on Sphinx.
+
+    .. change::
+        :tags:
+        :tickets: 154
+
+      Beaker is now part of "extras" in
+      setup.py instead of "install_requires".
+      This to produce a lighter weight install
+      for those who don't use the caching
+      as well as to conform to Pyramid
+      deployment practices.
+
+    .. change::
+        :tags:
+        :tickets: 153
+
+      The Beaker import (or attempt thereof)
+      is delayed until actually needed;
+      this to remove the performance penalty
+      from startup, particularly for
+      "single execution" environments
+      such as shell scripts.
+
+    .. change::
+        :tags:
+        :tickets: 155
+
+      Patch to lexer to not generate an empty
+      '' write in the case of backslash-ended
+      lines.
+
+    .. change::
+        :tags:
+        :tickets: 148
+
+      Fixed missing **extra collection in
+      setup.py which prevented setup.py
+      from running 2to3 on install.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      New flag on Template, TemplateLookup -
+      strict_undefined=True, will cause
+      variables not found in the context to
+      raise a NameError immediately, instead of
+      defaulting to the UNDEFINED value.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The range of Python identifiers that
+      are considered "undefined", meaning they
+      are pulled from the context, has been
+      trimmed back to not include variables
+      declared inside of expressions (i.e. from
+      list comprehensions), as well as
+      in the argument list of lambdas.  This
+      to better support the strict_undefined
+      feature.  The change should be
+      fully backwards-compatible but involved
+      a little bit of tinkering in the AST code,
+      which hadn't really been touched for
+      a couple of years, just FYI.
+
+.. changelog::
+    :version: 0.3.5
+    :released: Sun Oct 24 2010
+
+    .. change::
+        :tags:
+        :tickets: 141
+
+      The <%namespace> tag allows expressions
+      for the `file` argument, i.e. with ${}.
+      The `context` variable, if needed,
+      must be referenced explicitly.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      ${} expressions embedded in tags,
+      such as <%foo:bar x="${...}">, now
+      allow multiline Python expressions.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed previously non-covered regular
+      expression, such that using a ${} expression
+      inside of a tag element that doesn't allow
+      them raises a CompileException instead of
+      silently failing.
+
+    .. change::
+        :tags:
+        :tickets: 151
+
+      Added a try/except around "import markupsafe".
+      This to support GAE which can't run markupsafe. No idea whatsoever if the
+      install_requires in setup.py also breaks GAE,
+      couldn't get an answer on this.
+
+.. changelog::
+    :version: 0.3.4
+    :released: Tue Jun 22 2010
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Now using MarkupSafe for HTML escaping,
+      i.e. in place of cgi.escape().  Faster
+      C-based implementation and also escapes
+      single quotes for additional security.
+      Supports the __html__ attribute for
+      the given expression as well.
+
+      When using "disable_unicode" mode,
+      a pure Python HTML escaper function
+      is used which also quotes single quotes.
+
+      Note that Pylons by default doesn't
+      use Mako's filter - check your
+      environment.py file.
+
+    .. change::
+        :tags:
+        :tickets: 137
+
+      Fixed call to "unicode.strip" in
+      exceptions.text_error_template which
+      is not Py3k compatible.
+
+.. changelog::
+    :version: 0.3.3
+    :released: Mon May 31 2010
+
+    .. change::
+        :tags:
+        :tickets: 135
+
+      Added conditional to RichTraceback
+      such that if no traceback is passed
+      and sys.exc_info() has been reset,
+      the formatter just returns blank
+      for the "traceback" portion.
+
+    .. change::
+        :tags:
+        :tickets: 131
+
+      Fixed sometimes incorrect usage of
+      exc.__class__.__name__
+      in html/text error templates when using
+      Python 2.4
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed broken @property decorator on
+      template.last_modified
+
+    .. change::
+        :tags:
+        :tickets: 132
+
+      Fixed error formatting when a stacktrace
+      line contains no line number, as in when
+      inside an eval/exec-generated function.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      When a .py is being created, the tempfile
+      where the source is stored temporarily is
+      now made in the same directory as that of
+      the .py file.  This ensures that the two
+      files share the same filesystem, thus
+      avoiding cross-filesystem synchronization
+      issues.  Thanks to Charles Cazabon.
+
+.. changelog::
+    :version: 0.3.2
+    :released: Thu Mar 11 2010
+
+    .. change::
+        :tags:
+        :tickets: 116
+
+      Calling a def from the top, via
+      template.get_def(...).render() now checks the
+      argument signature the same way as it did in
+      0.2.5, so that TypeError is not raised.
+      reopen of
+
+.. changelog::
+    :version: 0.3.1
+    :released: Sun Mar 7 2010
+
+    .. change::
+        :tags:
+        :tickets: 129
+
+      Fixed incorrect dir name in setup.py
+
+.. changelog::
+    :version: 0.3.0
+    :released: Fri Mar 5 2010
+
+    .. change::
+        :tags:
+        :tickets: 123
+
+      Python 2.3 support is dropped.
+
+    .. change::
+        :tags:
+        :tickets: 119
+
+      Python 3 support is added ! See README.py3k
+      for installation and testing notes.
+
+    .. change::
+        :tags:
+        :tickets: 127
+
+      Unit tests now run with nose.
+
+    .. change::
+        :tags:
+        :tickets: 99
+
+      Source code escaping has been simplified.
+      In particular, module source files are now
+      generated with the Python "magic encoding
+      comment", and source code is passed through
+      mostly unescaped, except for that code which
+      is regenerated from parsed Python source.
+      This fixes usage of unicode in
+      <%namespace:defname> tags.
+
+    .. change::
+        :tags:
+        :tickets: 122
+
+      RichTraceback(), html_error_template().render(),
+      text_error_template().render() now accept "error"
+      and "traceback" as optional arguments, and
+      these are now actually used.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      The exception output generated when
+      format_exceptions=True will now be as a Python
+      unicode if it occurred during render_unicode(),
+      or an encoded string if during render().
+
+    .. change::
+        :tags:
+        :tickets: 112
+
+      A percent sign can be emitted as the first
+      non-whitespace character on a line by escaping
+      it as in "%%".
+
+    .. change::
+        :tags:
+        :tickets: 94
+
+      Template accepts empty control structure, i.e.
+      % if: %endif, etc.
+
+    .. change::
+        :tags:
+        :tickets: 116
+
+      The <%page args> tag can now be used in a base
+      inheriting template - the full set of render()
+      arguments are passed down through the inherits
+      chain.  Undeclared arguments go into **pageargs
+      as usual.
+
+    .. change::
+        :tags:
+        :tickets: 109
+
+      defs declared within a <%namespace> section, an
+      uncommon feature, have been improved.  The defs
+      no longer get doubly-rendered in the body() scope,
+      and now allow local variable assignment without
+      breakage.
+
+    .. change::
+        :tags:
+        :tickets: 128
+
+      Windows paths are handled correctly if a Template
+      is passed only an absolute filename (i.e. with c:
+      drive etc.)  and no URI - the URI is converted
+      to a forward-slash path and module_directory
+      is treated as a windows path.
+
+    .. change::
+        :tags:
+        :tickets: 73
+
+      TemplateLookup raises TopLevelLookupException for
+      a given path that is a directory, not a filename,
+      instead of passing through to the template to
+      generate IOError.
+
+
+.. changelog::
+    :version: 0.2.6
+    :released:
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fix mako function decorators to preserve the
+      original function's name in all cases. Patch
+      from Scott Torborg.
+
+    .. change::
+        :tags:
+        :tickets: 118
+
+      Support the <%namespacename:defname> syntax in
+      the babel extractor.
+
+    .. change::
+        :tags:
+        :tickets: 88
+
+      Further fixes to unicode handling of .py files with the
+      html_error_template.
+
+.. changelog::
+    :version: 0.2.5
+    :released: Mon Sep  7 2009
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Added a "decorator" kw argument to <%def>,
+      allows custom decoration functions to wrap
+      rendering callables.  Mainly intended for
+      custom caching algorithms, not sure what
+      other uses there may be (but there may be).
+      Examples are in the "filtering" docs.
+
+    .. change::
+        :tags:
+        :tickets: 101
+
+      When Mako creates subdirectories in which
+      to store templates, it uses the more
+      permissive mode of 0775 instead of 0750,
+      helping out with certain multi-process
+      scenarios. Note that the mode is always
+      subject to the restrictions of the existing
+      umask.
+
+    .. change::
+        :tags:
+        :tickets: 104
+
+      Fixed namespace.__getattr__() to raise
+      AttributeError on attribute not found
+      instead of RuntimeError.
+
+    .. change::
+        :tags:
+        :tickets: 97
+
+      Added last_modified accessor to Template,
+      returns the time.time() when the module
+      was created.
+
+    .. change::
+        :tags:
+        :tickets: 102
+
+      Fixed lexing support for whitespace
+      around '=' sign in defs.
+
+    .. change::
+        :tags:
+        :tickets: 108
+
+      Removed errant "lower()" in the lexer which
+      was causing tags to compile with
+      case-insensitive names, thus messing up
+      custom <%call> names.
+
+    .. change::
+        :tags:
+        :tickets: 110
+
+      added "mako.__version__" attribute to
+      the base module.
+
+.. changelog::
+    :version: 0.2.4
+    :released: Tue Dec 23 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Fixed compatibility with Jython 2.5b1.
+
+.. changelog::
+    :version: 0.2.3
+    :released: Sun Nov 23 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      the <%namespacename:defname> syntax described at
+      http://techspot.zzzeek.org/?p=28 has now
+      been added as a built in syntax, and is recommended
+      as a more modern syntax versus <%call expr="expression">.
+      The %call tag itself will always remain,
+      with <%namespacename:defname> presenting a more HTML-like
+      alternative to calling defs, both plain and
+      nested.  Many examples of the new syntax are in the
+      "Calling a def with embedded content" section
+      of the docs.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added support for Jython 2.5.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      cache module now uses Beaker's CacheManager
+      object directly, so that all cache types are included.
+      memcached is available as both "ext:memcached" and
+      "memcached", the latter for backwards compatibility.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "cache" accessor to Template, Namespace.
+      e.g.  ${local.cache.get('somekey')} or
+      template.cache.invalidate_body()
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "cache_enabled=True" flag to Template,
+      TemplateLookup.  Setting this to False causes cache
+      operations to "pass through" and execute every time;
+      this flag should be integrated in Pylons with its own
+      cache_enabled configuration setting.
+
+    .. change::
+        :tags:
+        :tickets: 92
+
+      the Cache object now supports invalidate_def(name),
+      invalidate_body(), invalidate_closure(name),
+      invalidate(key), which will remove the given key
+      from the cache, if it exists.  The cache arguments
+      (i.e. storage type) are derived from whatever has
+      been already persisted for that template.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      For cache changes to work fully, Beaker 1.1 is required.
+      1.0.1 and up will work as well with the exception of
+      cache expiry.  Note that Beaker 1.1 is **required**
+      for applications which use dynamically generated keys,
+      since previous versions will permanently store state in memory
+      for each individual key, thus consuming all available
+      memory for an arbitrarily large number of distinct
+      keys.
+
+    .. change::
+        :tags:
+        :tickets: 93
+
+      fixed bug whereby an <%included> template with
+      <%page> args named the same as a __builtin__ would not
+      honor the default value specified in <%page>
+
+    .. change::
+        :tags:
+        :tickets: 88
+
+      fixed the html_error_template not handling tracebacks from
+      normal .py files with a magic encoding comment
+
+    .. change::
+        :tags:
+        :tickets:
+
+      RichTraceback() now accepts an optional traceback object
+      to be used in place of sys.exc_info()[2].  html_error_template()
+      and text_error_template() accept an optional
+      render()-time argument "traceback" which is passed to the
+      RichTraceback object.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added ModuleTemplate class, which allows the construction
+      of a Template given a Python module generated by a previous
+      Template.   This allows Python modules alone to be used
+      as templates with no compilation step.   Source code
+      and template source are optional but allow error reporting
+      to work correctly.
+
+    .. change::
+        :tags:
+        :tickets: 90
+
+      fixed Python 2.3 compat. in mako.pyparser
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix Babel 0.9.3 compatibility; stripping comment tags is now
+      optional (and enabled by default).
+
+.. changelog::
+    :version: 0.2.2
+    :released: Mon Jun 23 2008
+
+    .. change::
+        :tags:
+        :tickets: 87
+
+      cached blocks now use the current context when rendering
+      an expired section, instead of the original context
+      passed in
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed a critical issue regarding caching, whereby
+      a cached block would raise an error when called within a
+      cache-refresh operation that was initiated after the
+      initiating template had completed rendering.
+
+.. changelog::
+    :version: 0.2.1
+    :released: Mon Jun 16 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed bug where 'output_encoding' parameter would prevent
+      render_unicode() from returning a unicode object.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      bumped magic number, which forces template recompile for
+      this version (fixes incompatible compile symbols from 0.1
+      series).
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added a few docs for cache options, specifically those that
+      help with memcached.
+
+.. changelog::
+    :version: 0.2.0
+    :released: Tue Jun  3 2008
+
+    .. change::
+        :tags:
+        :tickets:
+
+      Speed improvements (as though we needed them, but people
+      contributed and there you go):
+
+    .. change::
+        :tags:
+        :tickets: 77
+
+      added "bytestring passthru" mode, via
+      `disable_unicode=True` argument passed to Template or
+      TemplateLookup. All unicode-awareness and filtering is
+      turned off, and template modules are generated with
+      the appropriate magic encoding comment. In this mode,
+      template expressions can only receive raw bytestrings
+      or Unicode objects which represent straight ASCII, and
+      render_unicode() may not be used if multibyte
+      characters are present. When enabled, speed
+      improvement around 10-20%. (courtesy
+      anonymous guest)
+
+    .. change::
+        :tags:
+        :tickets: 76
+
+      inlined the "write" function of Context into a local
+      template variable. This affords a 12-30% speedup in
+      template render time. (idea courtesy same anonymous
+      guest)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      New Features, API changes:
+
+    .. change::
+        :tags:
+        :tickets: 62
+
+      added "attr" accessor to namespaces. Returns
+      attributes configured as module level attributes, i.e.
+      within <%! %> sections.  i.e.:
+
+      # somefile.html
+      <%!
+          foo = 27
+      %>
+
+      # some other template
+      <%namespace name="myns" file="somefile.html"/>
+      ${myns.attr.foo}
+
+      The slight backwards incompatibility here is, you
+      can't have namespace defs named "attr" since the
+      "attr" descriptor will occlude it.
+
+    .. change::
+        :tags:
+        :tickets: 78
+
+      cache_key argument can now render arguments passed
+      directly to the %page or %def, i.e. <%def
+      name="foo(x)" cached="True" cache_key="${x}"/>
+
+    .. change::
+        :tags:
+        :tickets:
+
+      some functions on Context are now private:
+      _push_buffer(), _pop_buffer(),
+      caller_stack._push_frame(), caller_stack._pop_frame().
+
+    .. change::
+        :tags:
+        :tickets: 56, 81
+
+      added a runner script "mako-render" which renders
+      standard input as a template to stdout
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 83, 84
+
+      can now use most names from __builtins__ as variable
+      names without explicit declaration (i.e. 'id',
+      'exception', 'range', etc.)
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 84
+
+      can also use builtin names as local variable names
+      (i.e. dict, locals) (came from fix for)
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 68
+
+      fixed bug in python generation when variable names are
+      used with identifiers like "else", "finally", etc.
+      inside them
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 69
+
+      fixed codegen bug which occured when using <%page>
+      level caching, combined with an expression-based
+      cache_key, combined with the usage of <%namespace
+      import="*"/> - fixed lexer exceptions not cleaning up
+      temporary files, which could lead to a maximum number
+      of file descriptors used in the process
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 71
+
+      fixed issue with inline format_exceptions that was
+      producing blank exception pages when an inheriting
+      template is present
+
+    .. change::
+        :tags: bugfixes
+        :tickets:
+
+      format_exceptions will apply the encoding options of
+      html_error_template() to the buffered output
+
+    .. change::
+        :tags: bugfixes
+        :tickets: 75
+
+      rewrote the "whitespace adjuster" function to work
+      with more elaborate combinations of quotes and
+      comments
+
+
+.. changelog::
+    :version: 0.1.10
+    :released:
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed propagation of 'caller' such that nested %def calls
+      within a <%call> tag's argument list propigates 'caller'
+      to the %call function itself (propigates to the inner
+      calls too, this is a slight side effect which previously
+      existed anyway)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed bug where local.get_namespace() could put an
+      incorrect "self" in the current context
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed another namespace bug where the namespace functions
+      did not have access to the correct context containing
+      their 'self' and 'parent'
+
+.. changelog::
+    :version: 0.1.9
+    :released:
+
+    .. change::
+        :tags:
+        :tickets: 47
+
+      filters.Decode filter can also accept a non-basestring
+      object and will call str() + unicode() on it
+
+    .. change::
+        :tags:
+        :tickets: 53
+
+      comments can be placed at the end of control lines,
+      i.e. if foo: # a comment,, thanks to
+      Paul Colomiets
+
+    .. change::
+        :tags:
+        :tickets: 16
+
+      fixed expressions and page tag arguments and with embedded
+      newlines in CRLF templates, follow up to, thanks
+      Eric Woroshow
+
+    .. change::
+        :tags:
+        :tickets: 51
+
+      added an IOError catch for source file not found in RichTraceback
+      exception reporter
+
+.. changelog::
+    :version: 0.1.8
+    :released: Tue Jun 26 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      variable names declared in render methods by internal
+      codegen prefixed by "__M_" to prevent name collisions
+      with user code
+
+    .. change::
+        :tags:
+        :tickets: 45
+
+      added a Babel (http://babel.edgewall.org/) extractor entry
+      point, allowing extraction of gettext messages directly from
+      mako templates via Babel
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to turbogears plugin to work with dot-separated names
+      (i.e. load_template('foo.bar')).  also takes file extension
+      as a keyword argument (default is 'mak').
+
+    .. change::
+        :tags:
+        :tickets: 35
+
+      more tg fix:  fixed, allowing string-based
+      templates with tgplugin even if non-compatible args were sent
+
+.. changelog::
+    :version: 0.1.7
+    :released: Wed Jun 13 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      one small fix to the unit tests to support python 2.3
+
+    .. change::
+        :tags:
+        :tickets:
+
+      a slight hack to how cache.py detects Beaker's memcached,
+      works around unexplained import behavior observed on some
+      python 2.3 installations
+
+.. changelog::
+    :version: 0.1.6
+    :released: Fri May 18 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      caching is now supplied directly by Beaker, which has
+      all of MyghtyUtils merged into it now.  The latest Beaker
+      (0.7.1) also fixes a bug related to how Mako was using the
+      cache API.
+
+    .. change::
+        :tags:
+        :tickets: 34
+
+      fix to module_directory path generation when the path is "./"
+
+    .. change::
+        :tags:
+        :tickets: 35
+
+      TGPlugin passes options to string-based templates
+
+    .. change::
+        :tags:
+        :tickets: 28
+
+      added an explicit stack frame step to template runtime, which
+      allows much simpler and hopefully bug-free tracking of 'caller',
+      fixes
+
+    .. change::
+        :tags:
+        :tickets:
+
+      if plain Python defs are used with <%call>, a decorator
+      @runtime.supports_callable exists to ensure that the "caller"
+      stack is properly handled for the def.
+
+    .. change::
+        :tags:
+        :tickets: 37
+
+      fix to RichTraceback and exception reporting to get template
+      source code as a unicode object
+
+    .. change::
+        :tags:
+        :tickets: 39
+
+      html_error_template includes options "full=True", "css=True"
+      which control generation of HTML tags, CSS
+
+    .. change::
+        :tags:
+        :tickets: 40
+
+      added the 'encoding_errors' parameter to Template/TemplateLookup
+      for specifying the error handler associated with encoding to
+      'output_encoding'
+
+    .. change::
+        :tags:
+        :tickets: 37
+
+      the Template returned by html_error_template now defaults to
+      output_encoding=sys.getdefaultencoding(),
+      encoding_errors='htmlentityreplace'
+
+    .. change::
+        :tags:
+        :tickets:
+
+      control lines, i.e. % lines, support backslashes to continue long
+      lines (#32)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed codegen bug when defining <%def> within <%call> within <%call>
+
+    .. change::
+        :tags:
+        :tickets:
+
+      leading utf-8 BOM in template files is honored according to pep-0263
+
+.. changelog::
+    :version: 0.1.5
+    :released: Sat Mar 31 2007
+
+    .. change::
+        :tags:
+        :tickets: 26
+
+      AST expression generation - added in just about everything
+      expression-wise from the AST module
+
+    .. change::
+        :tags:
+        :tickets: 27
+
+      AST parsing, properly detects imports of the form "import foo.bar"
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to lexing of <%docs> tag nested in other tags
+
+    .. change::
+        :tags:
+        :tickets: 29
+
+      fix to context-arguments inside of <%include> tag which broke
+      during 0.1.4
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "n" filter, disables *all* filters normally applied to an expression
+      via <%page> or default_filters (but not those within the filter)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added buffer_filters argument, defines filters applied to the return value
+      of buffered/cached/filtered %defs, after all filters defined with the %def
+      itself have been applied.  allows the creation of default expression filters
+      that let the output of return-valued %defs "opt out" of that filtering
+      via passing special attributes or objects.
+
+.. changelog::
+    :version: 0.1.4
+    :released: Sat Mar 10 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      got defs-within-defs to be cacheable
+
+    .. change::
+        :tags:
+        :tickets: 23
+
+      fixes to code parsing/whitespace adjusting where plain python comments
+      may contain quote characters
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to variable scoping for identifiers only referenced within
+      functions
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added a path normalization step to lookup so URIs like
+      "/foo/bar/../etc/../foo" pre-process the ".." tokens before checking
+      the filesystem
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fixed/improved "caller" semantics so that undefined caller is
+      "UNDEFINED", propigates __nonzero__ method so it evaulates to False if
+      not present, True otherwise. this way you can say % if caller:\n
+      ${caller.body()}\n% endif
+
+    .. change::
+        :tags:
+        :tickets:
+
+      <%include> has an "args" attribute that can pass arguments to the
+      called template (keyword arguments only, must be declared in that
+      page's <%page> tag.)
+
+    .. change::
+        :tags:
+        :tickets:
+
+      <%include> plus arguments is also programmatically available via
+      self.include_file(<filename>, **kwargs)
+
+    .. change::
+        :tags:
+        :tickets: 24
+
+      further escaping added for multibyte expressions in %def, %call
+      attributes
+
+.. changelog::
+    :version: 0.1.3
+    :released: Wed Feb 21 2007
+
+    .. change::
+        :tags:
+        :tickets:
+
+      ***Small Syntax Change*** - the single line comment character is now
+      *two* hash signs, i.e. "## this is a comment".  This avoids a common
+      collection with CSS selectors.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      the magic "coding" comment (i.e. # coding:utf-8) will still work with
+      either one "#" sign or two for now; two is preferred going forward, i.e.
+      ## coding:<someencoding>.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      new multiline comment form: "<%doc> a comment </%doc>"
+
+    .. change::
+        :tags:
+        :tickets:
+
+      UNDEFINED evaluates to False
+
+    .. change::
+        :tags:
+        :tickets:
+
+      improvement to scoping of "caller" variable when using <%call> tag
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added lexer error for unclosed control-line (%) line
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "preprocessor" argument to Template, TemplateLookup - is a single
+      callable or list of callables which will be applied to the template text
+      before lexing.  given the text as an argument, returns the new text.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added mako.ext.preprocessors package, contains one preprocessor so far:
+      'convert_comments', which will convert single # comments to the new ##
+      format
+
+.. changelog::
+    :version: 0.1.2
+    :released: Thu Feb  1 2007
+
+    .. change::
+        :tags:
+        :tickets: 11
+
+      fix to parsing of code/expression blocks to insure that non-ascii
+      characters, combined with a template that indicates a non-standard
+      encoding, are expanded into backslash-escaped glyphs before being AST
+      parsed
+
+    .. change::
+        :tags:
+        :tickets:
+
+      all template lexing converts the template to unicode first, to
+      immediately catch any encoding issues and ensure internal unicode
+      representation.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added module_filename argument to Template to allow specification of a
+      specific module file
+
+    .. change::
+        :tags:
+        :tickets: 14
+
+      added modulename_callable to TemplateLookup to allow a function to
+      determine module filenames (takes filename, uri arguments). used for
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added optional input_encoding flag to Template, to allow sending a
+      unicode() object with no magic encoding comment
+
+    .. change::
+        :tags:
+        :tickets:
+
+      "expression_filter" argument in <%page> applies only to expressions
+
+    .. change::
+        :tags: "unicode"
+        :tickets:
+
+      added "default_filters" argument to Template, TemplateLookup. applies only
+      to expressions, gets prepended to "expression_filter" arg from <%page>.
+      defaults to, so that all expressions get stringified into u''
+      by default (this is what Mako already does). By setting to [], expressions
+      are passed through raw.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      added "imports" argument to Template, TemplateLookup. so you can predefine
+      a list of import statements at the top of the template. can be used in
+      conjunction with default_filters.
+
+    .. change::
+        :tags:
+        :tickets: 16
+
+      support for CRLF templates...whoops ! welcome to all the windows users.
+
+    .. change::
+        :tags:
+        :tickets:
+
+      small fix to local variable propigation for locals that are conditionally
+      declared
+
+    .. change::
+        :tags:
+        :tickets:
+
+      got "top level" def calls to work, i.e. template.get_def("somedef").render()
+
+.. changelog::
+    :version: 0.1.1
+    :released: Sun Jan 14 2007
+
+    .. change::
+        :tags:
+        :tickets: 8
+
+      buffet plugin supports string-based templates, allows ToscaWidgets to work
+
+    .. change::
+        :tags:
+        :tickets:
+
+      AST parsing fixes: fixed TryExcept identifier parsing
+
+    .. change::
+        :tags:
+        :tickets:
+
+      removed textmate tmbundle from contrib and into separate SVN location;
+      windows users cant handle those files, setuptools not very good at
+      "pruning" certain directories
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix so that "cache_timeout" parameter is propigated
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to expression filters so that string conversion (actually unicode)
+      properly occurs before filtering
+
+    .. change::
+        :tags:
+        :tickets:
+
+      better error message when a lookup is attempted with a template that has no
+      lookup
+
+    .. change::
+        :tags:
+        :tickets:
+
+      implemented "module" attribute for namespace
+
+    .. change::
+        :tags:
+        :tickets:
+
+      fix to code generation to correctly track multiple defs with the same name
+
+    .. change::
+        :tags:
+        :tickets: 9
+
+      "directories" can be passed to TemplateLookup as a scalar in which case it
+      gets converted to a list
diff --git a/doc/build/conf.py b/doc/build/conf.py
new file mode 100644 (file)
index 0000000..807782b
--- /dev/null
@@ -0,0 +1,296 @@
+# -*- coding: utf-8 -*-
+#
+# Mako documentation build configuration file
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath('.'))
+
+import mako
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode',
+#                'sphinx.ext.doctest', 'builder.builders']
+
+extensions = ['sphinx.ext.autodoc','sphinx.ext.intersphinx',
+                'changelog', 'sphinx_paramlinks',
+                'builder.builders']
+
+changelog_render_ticket = "https://bitbucket.org/zzzeek/mako/issue/%s/"
+
+changelog_render_pullreq = {
+    "bitbucket": "https://bitbucket.org/zzzeek/mako/pull-request/%s",
+    "default": "https://bitbucket.org/zzzeek/mako/pull-request/%s",
+    "github": "https://github.com/zzzeek/mako/pull/%s",
+}
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+nitpicky = True
+
+site_base = "http://www.makotemplates.org"
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+template_bridge = "builder.builders.MakoBridge"
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Mako'
+copyright = u'the Mako authors and contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = mako.__version__
+# The full version, including alpha/beta/rc tags.
+release = mako.__version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "%s %s Documentation" % (project, release)
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%m/%d/%Y %H:%M:%S'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_domain_indices = False
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Makodoc'
+
+#autoclass_content = 'both'
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'mako_%s.tex' % release.replace('.', '_'), ur'Mako Documentation',
+   ur'Mike Bayer', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+# sets TOC depth to 2.
+latex_preamble = '\setcounter{tocdepth}{3}'
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+#latex_elements = {
+#    'papersize': 'letterpaper',
+#    'pointsize': '10pt',
+#}
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'mako', u'Mako Documentation',
+     [u'Mako authors'], 1)
+]
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'Mako'
+epub_author = u'Mako authors'
+epub_publisher = u'Mako authors'
+epub_copyright = u'Mako authors'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
+
+intersphinx_mapping = {
+    'dogpilecache':('http://dogpilecache.readthedocs.org/en/latest', None),
+    'beaker':('http://beaker.readthedocs.org/en/latest',None),
+}
diff --git a/doc/build/defs.rst b/doc/build/defs.rst
new file mode 100644 (file)
index 0000000..314e9b9
--- /dev/null
@@ -0,0 +1,622 @@
+.. _defs_toplevel:
+
+===============
+Defs and Blocks
+===============
+
+``<%def>`` and ``<%block>`` are two tags that both demarcate any block of text
+and/or code.   They both exist within generated Python as a callable function,
+i.e., a Python ``def``.   They differ in their scope and calling semantics.
+Whereas ``<%def>`` provides a construct that is very much like a named Python
+``def``, the ``<%block>`` is more layout oriented.
+
+Using Defs
+==========
+
+The ``<%def>`` tag requires a ``name`` attribute, where the ``name`` references
+a Python function signature:
+
+.. sourcecode:: mako
+
+    <%def name="hello()">
+        hello world
+    </%def>
+
+To invoke the ``<%def>``, it is normally called as an expression:
+
+.. sourcecode:: mako
+
+    the def:  ${hello()}
+
+If the ``<%def>`` is not nested inside of another ``<%def>``,
+it's known as a **top level def** and can be accessed anywhere in
+the template, including above where it was defined.
+
+All defs, top level or not, have access to the current
+contextual namespace in exactly the same way their containing
+template does. Suppose the template below is executed with the
+variables ``username`` and ``accountdata`` inside the context:
+
+.. sourcecode:: mako
+
+    Hello there ${username}, how are ya.  Lets see what your account says:
+
+    ${account()}
+
+    <%def name="account()">
+        Account for ${username}:<br/>
+
+        % for row in accountdata:
+            Value: ${row}<br/>
+        % endfor
+    </%def>
+
+The ``username`` and ``accountdata`` variables are present
+within the main template body as well as the body of the
+``account()`` def.
+
+Since defs are just Python functions, you can define and pass
+arguments to them as well:
+
+.. sourcecode:: mako
+
+    ${account(accountname='john')}
+
+    <%def name="account(accountname, type='regular')">
+        account name: ${accountname}, type: ${type}
+    </%def>
+
+When you declare an argument signature for your def, they are
+required to follow normal Python conventions (i.e., all
+arguments are required except keyword arguments with a default
+value). This is in contrast to using context-level variables,
+which evaluate to ``UNDEFINED`` if you reference a name that
+does not exist.
+
+Calling Defs from Other Files
+-----------------------------
+
+Top level ``<%def>``\ s are **exported** by your template's
+module, and can be called from the outside; including from other
+templates, as well as normal Python code. Calling a ``<%def>``
+from another template is something like using an ``<%include>``
+-- except you are calling a specific function within the
+template, not the whole template.
+
+The remote ``<%def>`` call is also a little bit like calling
+functions from other modules in Python. There is an "import"
+step to pull the names from another template into your own
+template; then the function or functions are available.
+
+To import another template, use the ``<%namespace>`` tag:
+
+.. sourcecode:: mako
+
+    <%namespace name="mystuff" file="mystuff.html"/>
+
+The above tag adds a local variable ``mystuff`` to the current
+scope.
+
+Then, just call the defs off of ``mystuff``:
+
+.. sourcecode:: mako
+
+    ${mystuff.somedef(x=5,y=7)}
+
+The ``<%namespace>`` tag also supports some of the other
+semantics of Python's ``import`` statement, including pulling
+names into the local variable space, or using ``*`` to represent
+all names, using the ``import`` attribute:
+
+.. sourcecode:: mako
+
+    <%namespace file="mystuff.html" import="foo, bar"/>
+
+This is just a quick intro to the concept of a **namespace**,
+which is a central Mako concept that has its own chapter in
+these docs. For more detail and examples, see
+:ref:`namespaces_toplevel`.
+
+Calling Defs Programmatically
+-----------------------------
+
+You can call defs programmatically from any :class:`.Template` object
+using the :meth:`~.Template.get_def()` method, which returns a :class:`.DefTemplate`
+object. This is a :class:`.Template` subclass which the parent
+:class:`.Template` creates, and is usable like any other template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    template = Template("""
+        <%def name="hi(name)">
+            hi ${name}!
+        </%def>
+
+        <%def name="bye(name)">
+            bye ${name}!
+        </%def>
+    """)
+
+    print(template.get_def("hi").render(name="ed"))
+    print(template.get_def("bye").render(name="ed"))
+
+Defs within Defs
+----------------
+
+The def model follows regular Python rules for closures.
+Declaring ``<%def>`` inside another ``<%def>`` declares it
+within the parent's **enclosing scope**:
+
+.. sourcecode:: mako
+
+    <%def name="mydef()">
+        <%def name="subdef()">
+            a sub def
+        </%def>
+
+        i'm the def, and the subcomponent is ${subdef()}
+    </%def>
+
+Just like Python, names that exist outside the inner ``<%def>``
+exist inside it as well:
+
+.. sourcecode:: mako
+
+    <%
+        x = 12
+    %>
+    <%def name="outer()">
+        <%
+            y = 15
+        %>
+        <%def name="inner()">
+            inner, x is ${x}, y is ${y}
+        </%def>
+
+        outer, x is ${x}, y is ${y}
+    </%def>
+
+Assigning to a name inside of a def declares that name as local
+to the scope of that def (again, like Python itself). This means
+the following code will raise an error:
+
+.. sourcecode:: mako
+
+    <%
+        x = 10
+    %>
+    <%def name="somedef()">
+        ## error !
+        somedef, x is ${x}
+        <%
+            x = 27
+        %>
+    </%def>
+
+...because the assignment to ``x`` declares ``x`` as local to the
+scope of ``somedef``, rendering the "outer" version unreachable
+in the expression that tries to render it.
+
+.. _defs_with_content:
+
+Calling a Def with Embedded Content and/or Other Defs
+-----------------------------------------------------
+
+A flip-side to def within def is a def call with content. This
+is where you call a def, and at the same time declare a block of
+content (or multiple blocks) that can be used by the def being
+called. The main point of such a call is to create custom,
+nestable tags, just like any other template language's
+custom-tag creation system -- where the external tag controls the
+execution of the nested tags and can communicate state to them.
+Only with Mako, you don't have to use any external Python
+modules, you can define arbitrarily nestable tags right in your
+templates.
+
+To achieve this, the target def is invoked using the form
+``<%namespacename:defname>`` instead of the normal ``${}``
+syntax. This syntax, introduced in Mako 0.2.3, is functionally
+equivalent to another tag known as ``%call``, which takes the form
+``<%call expr='namespacename.defname(args)'>``. While ``%call``
+is available in all versions of Mako, the newer style is
+probably more familiar looking. The ``namespace`` portion of the
+call is the name of the **namespace** in which the def is
+defined -- in the most simple cases, this can be ``local`` or
+``self`` to reference the current template's namespace (the
+difference between ``local`` and ``self`` is one of inheritance
+-- see :ref:`namespaces_builtin` for details).
+
+When the target def is invoked, a variable ``caller`` is placed
+in its context which contains another namespace containing the
+body and other defs defined by the caller. The body itself is
+referenced by the method ``body()``. Below, we build a ``%def``
+that operates upon ``caller.body()`` to invoke the body of the
+custom tag:
+
+.. sourcecode:: mako
+
+    <%def name="buildtable()">
+        <table>
+            <tr><td>
+                ${caller.body()}
+            </td></tr>
+        </table>
+    </%def>
+
+    <%self:buildtable>
+        I am the table body.
+    </%self:buildtable>
+
+This produces the output (whitespace formatted):
+
+.. sourcecode:: html
+
+    <table>
+        <tr><td>
+            I am the table body.
+        </td></tr>
+    </table>
+
+Using the older ``%call`` syntax looks like:
+
+.. sourcecode:: mako
+
+    <%def name="buildtable()">
+        <table>
+            <tr><td>
+                ${caller.body()}
+            </td></tr>
+        </table>
+    </%def>
+
+    <%call expr="buildtable()">
+        I am the table body.
+    </%call>
+
+The ``body()`` can be executed multiple times or not at all.
+This means you can use def-call-with-content to build iterators,
+conditionals, etc:
+
+.. sourcecode:: mako
+
+    <%def name="lister(count)">
+        % for x in range(count):
+            ${caller.body()}
+        % endfor
+    </%def>
+
+    <%self:lister count="${3}">
+        hi
+    </%self:lister>
+
+Produces:
+
+.. sourcecode:: html
+
+    hi
+    hi
+    hi
+
+Notice above we pass ``3`` as a Python expression, so that it
+remains as an integer.
+
+A custom "conditional" tag:
+
+.. sourcecode:: mako
+
+    <%def name="conditional(expression)">
+        % if expression:
+            ${caller.body()}
+        % endif
+    </%def>
+
+    <%self:conditional expression="${4==4}">
+        i'm the result
+    </%self:conditional>
+
+Produces:
+
+.. sourcecode:: html
+
+    i'm the result
+
+But that's not all. The ``body()`` function also can handle
+arguments, which will augment the local namespace of the body
+callable. The caller must define the arguments which it expects
+to receive from its target def using the ``args`` attribute,
+which is a comma-separated list of argument names. Below, our
+``<%def>`` calls the ``body()`` of its caller, passing in an
+element of data from its argument:
+
+.. sourcecode:: mako
+
+    <%def name="layoutdata(somedata)">
+        <table>
+        % for item in somedata:
+            <tr>
+            % for col in item:
+                <td>${caller.body(col=col)}</td>
+            % endfor
+            </tr>
+        % endfor
+        </table>
+    </%def>
+
+    <%self:layoutdata somedata="${[[1,2,3],[4,5,6],[7,8,9]]}" args="col">\
+    Body data: ${col}\
+    </%self:layoutdata>
+
+Produces:
+
+.. sourcecode:: html
+
+    <table>
+        <tr>
+            <td>Body data: 1</td>
+            <td>Body data: 2</td>
+            <td>Body data: 3</td>
+        </tr>
+        <tr>
+            <td>Body data: 4</td>
+            <td>Body data: 5</td>
+            <td>Body data: 6</td>
+        </tr>
+        <tr>
+            <td>Body data: 7</td>
+            <td>Body data: 8</td>
+            <td>Body data: 9</td>
+        </tr>
+    </table>
+
+You don't have to stick to calling just the ``body()`` function.
+The caller can define any number of callables, allowing the
+``<%call>`` tag to produce whole layouts:
+
+.. sourcecode:: mako
+
+    <%def name="layout()">
+        ## a layout def
+        <div class="mainlayout">
+            <div class="header">
+                ${caller.header()}
+            </div>
+
+            <div class="sidebar">
+                ${caller.sidebar()}
+            </div>
+
+            <div class="content">
+                ${caller.body()}
+            </div>
+        </div>
+    </%def>
+
+    ## calls the layout def
+    <%self:layout>
+        <%def name="header()">
+            I am the header
+        </%def>
+        <%def name="sidebar()">
+            <ul>
+                <li>sidebar 1</li>
+                <li>sidebar 2</li>
+            </ul>
+        </%def>
+
+            this is the body
+    </%self:layout>
+
+The above layout would produce:
+
+.. sourcecode:: html
+
+    <div class="mainlayout">
+        <div class="header">
+        I am the header
+        </div>
+
+        <div class="sidebar">
+        <ul>
+            <li>sidebar 1</li>
+            <li>sidebar 2</li>
+        </ul>
+        </div>
+
+        <div class="content">
+        this is the body
+        </div>
+    </div>
+
+The number of things you can do with ``<%call>`` and/or the
+``<%namespacename:defname>`` calling syntax is enormous. You can
+create form widget libraries, such as an enclosing ``<FORM>``
+tag and nested HTML input elements, or portable wrapping schemes
+using ``<div>`` or other elements. You can create tags that
+interpret rows of data, such as from a database, providing the
+individual columns of each row to a ``body()`` callable which
+lays out the row any way it wants. Basically anything you'd do
+with a "custom tag" or tag library in some other system, Mako
+provides via ``<%def>`` tags and plain Python callables which are
+invoked via ``<%namespacename:defname>`` or ``<%call>``.
+
+.. _blocks:
+
+Using Blocks
+============
+
+The ``<%block>`` tag introduces some new twists on the
+``<%def>`` tag which make it more closely tailored towards layout.
+
+.. versionadded:: 0.4.1
+
+An example of a block:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block>
+                this is a block.
+            </%block>
+        </body>
+    </html>
+
+In the above example, we define a simple block.  The block renders its content in the place
+that it's defined.  Since the block is called for us, it doesn't need a name and the above
+is referred to as an **anonymous block**.  So the output of the above template will be:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+                this is a block.
+        </body>
+    </html>
+
+So in fact the above block has absolutely no effect.  Its usefulness comes when we start
+using modifiers.  Such as, we can apply a filter to our block:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block filter="h">
+                <html>this is some escaped html.</html>
+            </%block>
+        </body>
+    </html>
+
+or perhaps a caching directive:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+            <%block cached="True" cache_timeout="60">
+                This content will be cached for 60 seconds.
+            </%block>
+        </body>
+    </html>
+
+Blocks also work in iterations, conditionals, just like defs:
+
+.. sourcecode:: mako
+
+    % if some_condition:
+        <%block>condition is met</%block>
+    % endif
+
+While the block renders at the point it is defined in the template,
+the underlying function is present in the generated Python code only
+once, so there's no issue with placing a block inside of a loop or
+similar. Anonymous blocks are defined as closures in the local
+rendering body, so have access to local variable scope:
+
+.. sourcecode:: mako
+
+    % for i in range(1, 4):
+        <%block>i is ${i}</%block>
+    % endfor
+
+Using Named Blocks
+------------------
+
+Possibly the more important area where blocks are useful is when we
+do actually give them names. Named blocks are tailored to behave
+somewhat closely to Jinja2's block tag, in that they define an area
+of a layout which can be overridden by an inheriting template. In
+sharp contrast to the ``<%def>`` tag, the name given to a block is
+global for the entire template regardless of how deeply it's nested:
+
+.. sourcecode:: mako
+
+    <html>
+    <%block name="header">
+        <head>
+            <title>
+                <%block name="title">Title</%block>
+            </title>
+        </head>
+    </%block>
+    <body>
+        ${next.body()}
+    </body>
+    </html>
+
+The above example has two named blocks "``header``" and "``title``", both of which can be referred to
+by an inheriting template. A detailed walkthrough of this usage can be found at :ref:`inheritance_toplevel`.
+
+Note above that named blocks don't have any argument declaration the way defs do. They still implement themselves
+as Python functions, however, so they can be invoked additional times beyond their initial definition:
+
+.. sourcecode:: mako
+
+    <div name="page">
+        <%block name="pagecontrol">
+            <a href="">previous page</a> |
+            <a href="">next page</a>
+        </%block>
+
+        <table>
+            ## some content
+        </table>
+
+        ${pagecontrol()}
+    </div>
+
+The content referenced by ``pagecontrol`` above will be rendered both above and below the ``<table>`` tags.
+
+To keep things sane, named blocks have restrictions that defs do not:
+
+* The ``<%block>`` declaration cannot have any argument signature.
+* The name of a ``<%block>`` can only be defined once in a template -- an error is raised if two blocks of the same
+  name occur anywhere in a single template, regardless of nesting.  A similar error is raised if a top level def
+  shares the same name as that of a block.
+* A named ``<%block>`` cannot be defined within a ``<%def>``, or inside the body of a "call", i.e.
+  ``<%call>`` or ``<%namespacename:defname>`` tag.  Anonymous blocks can, however.
+
+Using Page Arguments in Named Blocks
+------------------------------------
+
+A named block is very much like a top level def. It has a similar
+restriction to these types of defs in that arguments passed to the
+template via the ``<%page>`` tag aren't automatically available.
+Using arguments with the ``<%page>`` tag is described in the section
+:ref:`namespaces_body`, and refers to scenarios such as when the
+``body()`` method of a template is called from an inherited template passing
+arguments, or the template is invoked from an ``<%include>`` tag
+with arguments. To allow a named block to share the same arguments
+passed to the page, the ``args`` attribute can be used:
+
+.. sourcecode:: mako
+
+    <%page args="post"/>
+
+    <a name="${post.title}" />
+
+    <span class="post_prose">
+        <%block name="post_prose" args="post">
+            ${post.content}
+        </%block>
+    </span>
+
+Where above, if the template is called via a directive like
+``<%include file="post.mako" args="post=post" />``, the ``post``
+variable is available both in the main body as well as the
+``post_prose`` block.
+
+Similarly, the ``**pageargs`` variable is present, in named blocks only,
+for those arguments not explicit in the ``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%block name="post_prose">
+        ${pageargs['post'].content}
+    </%block>
+
+The ``args`` attribute is only allowed with named blocks. With
+anonymous blocks, the Python function is always rendered in the same
+scope as the call itself, so anything available directly outside the
+anonymous block is available inside as well.
diff --git a/doc/build/filtering.rst b/doc/build/filtering.rst
new file mode 100644 (file)
index 0000000..3bcb25a
--- /dev/null
@@ -0,0 +1,344 @@
+.. _filtering_toplevel:
+
+=======================
+Filtering and Buffering
+=======================
+
+Expression Filtering
+====================
+
+As described in the chapter :ref:`syntax_toplevel`, the "``|``" operator can be
+applied to a "``${}``" expression to apply escape filters to the
+output:
+
+.. sourcecode:: mako
+
+    ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``.
+
+The built-in escape flags are:
+
+* ``u`` : URL escaping, provided by
+  ``urllib.quote_plus(string.encode('utf-8'))``
+* ``h`` : HTML escaping, provided by
+  ``markupsafe.escape(string)``
+
+  .. versionadded:: 0.3.4
+     Prior versions use ``cgi.escape(string, True)``.
+
+* ``x`` : XML escaping
+* ``trim`` : whitespace trimming, provided by ``string.strip()``
+* ``entity`` : produces HTML entity references for applicable
+  strings, derived from ``htmlentitydefs``
+* ``unicode`` (``str`` on Python 3): produces a Python unicode
+  string (this function is applied by default)
+* ``decode.<some encoding>``: decode input into a Python
+  unicode with the specified encoding
+* ``n`` : disable all default filtering; only filters specified
+  in the local expression tag will be applied.
+
+To apply more than one filter, separate them by a comma:
+
+.. sourcecode:: mako
+
+    ${" <tag>some value</tag> " | h,trim}
+
+The above produces ``&lt;tag&gt;some value&lt;/tag&gt;``, with
+no leading or trailing whitespace. The HTML escaping function is
+applied first, the "trim" function second.
+
+Naturally, you can make your own filters too. A filter is just a
+Python function that accepts a single string argument, and
+returns the filtered result. The expressions after the ``|``
+operator draw upon the local namespace of the template in which
+they appear, meaning you can define escaping functions locally:
+
+.. sourcecode:: mako
+
+    <%!
+        def myescape(text):
+            return "<TAG>" + text + "</TAG>"
+    %>
+
+    Here's some tagged text: ${"text" | myescape}
+
+Or from any Python module:
+
+.. sourcecode:: mako
+
+    <%!
+        import myfilters
+    %>
+
+    Here's some tagged text: ${"text" | myfilters.tagfilter}
+
+A page can apply a default set of filters to all expression tags
+using the ``expression_filter`` argument to the ``%page`` tag:
+
+.. sourcecode:: mako
+
+    <%page expression_filter="h"/>
+
+    Escaped text:  ${"<html>some html</html>"}
+
+Result:
+
+.. sourcecode:: html
+
+    Escaped text: &lt;html&gt;some html&lt;/html&gt;
+
+.. _filtering_default_filters:
+
+The ``default_filters`` Argument
+--------------------------------
+
+In addition to the ``expression_filter`` argument, the
+``default_filters`` argument to both :class:`.Template` and
+:class:`.TemplateLookup` can specify filtering for all expression tags
+at the programmatic level. This array-based argument, when given
+its default argument of ``None``, will be internally set to
+``["unicode"]`` (or ``["str"]`` on Python 3), except when
+``disable_unicode=True`` is set in which case it defaults to
+``["str"]``:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=['unicode'])
+
+To replace the usual ``unicode``/``str`` function with a
+specific encoding, the ``decode`` filter can be substituted:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=['decode.utf8'])
+
+To disable ``default_filters`` entirely, set it to an empty
+list:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'], default_filters=[])
+
+Any string name can be added to ``default_filters`` where it
+will be added to all expressions as a filter. The filters are
+applied from left to right, meaning the leftmost filter is
+applied first.
+
+.. sourcecode:: python
+
+    t = Template(templatetext, default_filters=['unicode', 'myfilter'])
+
+To ease the usage of ``default_filters`` with custom filters,
+you can also add imports (or other code) to all templates using
+the ``imports`` argument:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['/tmp'],
+                       default_filters=['unicode', 'myfilter'],
+                       imports=['from mypackage import myfilter'])
+
+The above will generate templates something like this:
+
+.. sourcecode:: python
+
+    # ....
+    from mypackage import myfilter
+
+    def render_body(context):
+        context.write(myfilter(unicode("some text")))
+
+Turning off Filtering with the ``n`` Filter
+-------------------------------------------
+
+In all cases the special ``n`` filter, used locally within an
+expression, will **disable** all filters declared in the
+``<%page>`` tag as well as in ``default_filters``. Such as:
+
+.. sourcecode:: mako
+
+    ${'myexpression' | n}
+
+will render ``myexpression`` with no filtering of any kind, and:
+
+.. sourcecode:: mako
+
+    ${'myexpression' | n,trim}
+
+will render ``myexpression`` using the ``trim`` filter only.
+
+Filtering Defs and Blocks
+=========================
+
+The ``%def`` and ``%block`` tags have an argument called ``filter`` which will apply the
+given list of filter functions to the output of the ``%def``:
+
+.. sourcecode:: mako
+
+    <%def name="foo()" filter="h, trim">
+        <b>this is bold</b>
+    </%def>
+
+When the ``filter`` attribute is applied to a def as above, the def
+is automatically **buffered** as well. This is described next.
+
+Buffering
+=========
+
+One of Mako's central design goals is speed. To this end, all of
+the textual content within a template and its various callables
+is by default piped directly to the single buffer that is stored
+within the :class:`.Context` object. While this normally is easy to
+miss, it has certain side effects. The main one is that when you
+call a def using the normal expression syntax, i.e.
+``${somedef()}``, it may appear that the return value of the
+function is the content it produced, which is then delivered to
+your template just like any other expression substitution,
+except that normally, this is not the case; the return value of
+``${somedef()}`` is simply the empty string ``''``. By the time
+you receive this empty string, the output of ``somedef()`` has
+been sent to the underlying buffer.
+
+You may not want this effect, if for example you are doing
+something like this:
+
+.. sourcecode:: mako
+
+    ${" results " + somedef() + " more results "}
+
+If the ``somedef()`` function produced the content "``somedef's
+results``", the above template would produce this output:
+
+.. sourcecode:: html
+
+    somedef's results results more results
+
+This is because ``somedef()`` fully executes before the
+expression returns the results of its concatenation; the
+concatenation in turn receives just the empty string as its
+middle expression.
+
+Mako provides two ways to work around this. One is by applying
+buffering to the ``%def`` itself:
+
+.. sourcecode:: mako
+
+    <%def name="somedef()" buffered="True">
+        somedef's results
+    </%def>
+
+The above definition will generate code similar to this:
+
+.. sourcecode:: python
+
+    def somedef():
+        context.push_buffer()
+        try:
+            context.write("somedef's results")
+        finally:
+            buf = context.pop_buffer()
+        return buf.getvalue()
+
+So that the content of ``somedef()`` is sent to a second buffer,
+which is then popped off the stack and its value returned. The
+speed hit inherent in buffering the output of a def is also
+apparent.
+
+Note that the ``filter`` argument on ``%def`` also causes the def to
+be buffered. This is so that the final content of the ``%def`` can
+be delivered to the escaping function in one batch, which
+reduces method calls and also produces more deterministic
+behavior for the filtering function itself, which can possibly
+be useful for a filtering function that wishes to apply a
+transformation to the text as a whole.
+
+The other way to buffer the output of a def or any Mako callable
+is by using the built-in ``capture`` function. This function
+performs an operation similar to the above buffering operation
+except it is specified by the caller.
+
+.. sourcecode:: mako
+
+    ${" results " + capture(somedef) + " more results "}
+
+Note that the first argument to the ``capture`` function is
+**the function itself**, not the result of calling it. This is
+because the ``capture`` function takes over the job of actually
+calling the target function, after setting up a buffered
+environment. To send arguments to the function, just send them
+to ``capture`` instead:
+
+.. sourcecode:: mako
+
+    ${capture(somedef, 17, 'hi', use_paging=True)}
+
+The above call is equivalent to the unbuffered call:
+
+.. sourcecode:: mako
+
+    ${somedef(17, 'hi', use_paging=True)}
+
+Decorating
+==========
+
+.. versionadded:: 0.2.5
+
+Somewhat like a filter for a ``%def`` but more flexible, the ``decorator``
+argument to ``%def`` allows the creation of a function that will
+work in a similar manner to a Python decorator. The function can
+control whether or not the function executes. The original
+intent of this function is to allow the creation of custom cache
+logic, but there may be other uses as well.
+
+``decorator`` is intended to be used with a regular Python
+function, such as one defined in a library module. Here we'll
+illustrate the python function defined in the template for
+simplicities' sake:
+
+.. sourcecode:: mako
+
+    <%!
+        def bar(fn):
+            def decorate(context, *args, **kw):
+                context.write("BAR")
+                fn(*args, **kw)
+                context.write("BAR")
+                return ''
+            return decorate
+    %>
+
+    <%def name="foo()" decorator="bar">
+        this is foo
+    </%def>
+
+    ${foo()}
+
+The above template will return, with more whitespace than this,
+``"BAR this is foo BAR"``. The function is the render callable
+itself (or possibly a wrapper around it), and by default will
+write to the context. To capture its output, use the :func:`.capture`
+callable in the ``mako.runtime`` module (available in templates
+as just ``runtime``):
+
+.. sourcecode:: mako
+
+    <%!
+        def bar(fn):
+            def decorate(context, *args, **kw):
+                return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR"
+            return decorate
+    %>
+
+    <%def name="foo()" decorator="bar">
+        this is foo
+    </%def>
+
+    ${foo()}
+
+The decorator can be used with top-level defs as well as nested
+defs, and blocks too. Note that when calling a top-level def from the
+:class:`.Template` API, i.e. ``template.get_def('somedef').render()``,
+the decorator has to write the output to the ``context``, i.e.
+as in the first example. The return value gets discarded.
diff --git a/doc/build/index.rst b/doc/build/index.rst
new file mode 100644 (file)
index 0000000..3104ca9
--- /dev/null
@@ -0,0 +1,23 @@
+Table of Contents
+=================
+
+.. toctree::
+    :maxdepth: 2
+
+    usage
+    syntax
+    defs
+    runtime
+    namespaces
+    inheritance
+    filtering
+    unicode
+    caching
+    changelog
+
+Indices and Tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/doc/build/inheritance.rst b/doc/build/inheritance.rst
new file mode 100644 (file)
index 0000000..5b29574
--- /dev/null
@@ -0,0 +1,647 @@
+.. _inheritance_toplevel:
+
+===========
+Inheritance
+===========
+
+.. note::  Most of the inheritance examples here take advantage of a feature that's
+    new in Mako as of version 0.4.1 called the "block".  This tag is very similar to
+    the "def" tag but is more streamlined for usage with inheritance.  Note that
+    all of the examples here which use blocks can also use defs instead.  Contrasting
+    usages will be illustrated.
+
+Using template inheritance, two or more templates can organize
+themselves into an **inheritance chain**, where content and
+functions from all involved templates can be intermixed. The
+general paradigm of template inheritance is this: if a template
+``A`` inherits from template ``B``, then template ``A`` agrees
+to send the executional control to template ``B`` at runtime
+(``A`` is called the **inheriting** template). Template ``B``,
+the **inherited** template, then makes decisions as to what
+resources from ``A`` shall be executed.
+
+In practice, it looks like this. Here's a hypothetical inheriting
+template, ``index.html``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%block name="header">
+        this is some header content
+    </%block>
+
+    this is the body content.
+
+And ``base.html``, the inherited template:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header"/>
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+Here is a breakdown of the execution:
+
+#. When ``index.html`` is rendered, control immediately passes to
+   ``base.html``.
+#. ``base.html`` then renders the top part of an HTML document,
+   then invokes the ``<%block name="header">`` block.  It invokes the
+   underlying ``header()`` function off of a built-in namespace
+   called ``self`` (this namespace was first introduced in the
+   :doc:`Namespaces chapter <namespaces>` in :ref:`namespace_self`). Since
+   ``index.html`` is the topmost template and also defines a block
+   called ``header``, it's this ``header`` block that ultimately gets
+   executed -- instead of the one that's present in ``base.html``.
+#. Control comes back to ``base.html``. Some more HTML is
+   rendered.
+#. ``base.html`` executes ``self.body()``. The ``body()``
+   function on all template-based namespaces refers to the main
+   body of the template, therefore the main body of
+   ``index.html`` is rendered.
+#. When ``<%block name="header">`` is encountered in ``index.html``
+   during the ``self.body()`` call, a conditional is checked -- does the
+   current inherited template, i.e. ``base.html``, also define this block? If yes,
+   the ``<%block>`` is **not** executed here -- the inheritance
+   mechanism knows that the parent template is responsible for rendering
+   this block (and in fact it already has).  In other words a block
+   only renders in its *basemost scope*.
+#. Control comes back to ``base.html``. More HTML is rendered,
+   then the ``<%block name="footer">`` expression is invoked.
+#. The ``footer`` block is only defined in ``base.html``, so being
+   the topmost definition of ``footer``, it's the one that
+   executes. If ``index.html`` also specified ``footer``, then
+   its version would **override** that of the base.
+#. ``base.html`` finishes up rendering its HTML and the template
+   is complete, producing:
+
+   .. sourcecode:: html
+
+        <html>
+            <body>
+                <div class="header">
+                    this is some header content
+                </div>
+
+                this is the body content.
+
+                <div class="footer">
+                    this is the footer
+                </div>
+            </body>
+        </html>
+
+...and that is template inheritance in a nutshell. The main idea
+is that the methods that you call upon ``self`` always
+correspond to the topmost definition of that method. Very much
+the way ``self`` works in a Python class, even though Mako is
+not actually using Python class inheritance to implement this
+functionality. (Mako doesn't take the "inheritance" metaphor too
+seriously; while useful to setup some commonly recognized
+semantics, a textual template is not very much like an
+object-oriented class construct in practice).
+
+Nesting Blocks
+==============
+
+The named blocks defined in an inherited template can also be nested within
+other blocks.  The name given to each block is globally accessible via any inheriting
+template.  We can add a new block ``title`` to our ``header`` block:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header">
+                    <h2>
+                        <%block name="title"/>
+                    </h2>
+                </%block>
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+The inheriting template can name either or both of ``header`` and ``title``, separately
+or nested themselves:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%block name="header">
+        this is some header content
+        ${parent.header()}
+    </%block>
+
+    <%block name="title">
+        this is the title
+    </%block>
+
+    this is the body content.
+
+Note when we overrode ``header``, we added an extra call ``${parent.header()}`` in order to invoke
+the parent's ``header`` block in addition to our own.  That's described in more detail below,
+in :ref:`parent_namespace`.
+
+Rendering a Named Block Multiple Times
+======================================
+
+Recall from the section :ref:`blocks` that a named block is just like a ``<%def>``,
+with some different usage rules.  We can call one of our named sections distinctly, for example
+a section that is used more than once, such as the title of a page:
+
+.. sourcecode:: mako
+
+    <html>
+        <head>
+            <title>${self.title()}</title>
+        </head>
+        <body>
+        <%block name="header">
+            <h2><%block name="title"/></h2>
+        </%block>
+        ${self.body()}
+        </body>
+    </html>
+
+Where above an inheriting template can define ``<%block name="title">`` just once, and it will be
+used in the base template both in the ``<title>`` section as well as the ``<h2>``.
+
+
+
+But what about Defs?
+====================
+
+The previous example used the ``<%block>`` tag to produce areas of content
+to be overridden.  Before Mako 0.4.1, there wasn't any such tag -- instead
+there was only the ``<%def>`` tag.   As it turns out, named blocks and defs are
+largely interchangeable.  The def simply doesn't call itself automatically,
+and has more open-ended naming and scoping rules that are more flexible and similar
+to Python itself, but less suited towards layout.  The first example from
+this chapter using defs would look like:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+
+    <%def name="header()">
+        this is some header content
+    </%def>
+
+    this is the body content.
+
+And ``base.html``, the inherited template:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                ${self.header()}
+            </div>
+
+            ${self.body()}
+
+            <div class="footer">
+                ${self.footer()}
+            </div>
+        </body>
+    </html>
+
+    <%def name="header()"/>
+    <%def name="footer()">
+        this is the footer
+    </%def>
+
+Above, we illustrate that defs differ from blocks in that their definition
+and invocation are defined in two separate places, instead of at once. You can *almost* do exactly what a
+block does if you put the two together:
+
+.. sourcecode:: mako
+
+    <div class="header">
+        <%def name="header()"></%def>${self.header()}
+    </div>
+
+The ``<%block>`` is obviously more streamlined than the ``<%def>`` for this kind
+of usage.  In addition,
+the above "inline" approach with ``<%def>`` does not work with nesting:
+
+.. sourcecode:: mako
+
+    <head>
+        <%def name="header()">
+            <title>
+            ## this won't work !
+            <%def name="title()">default title</%def>${self.title()}
+            </title>
+        </%def>${self.header()}
+    </head>
+
+Where above, the ``title()`` def, because it's a def within a def, is not part of the
+template's exported namespace and will not be part of ``self``.  If the inherited template
+did define its own ``title`` def at the top level, it would be called, but the "default title"
+above is not present at all on ``self`` no matter what.  For this to work as expected
+you'd instead need to say:
+
+.. sourcecode:: mako
+
+    <head>
+        <%def name="header()">
+            <title>
+            ${self.title()}
+            </title>
+        </%def>${self.header()}
+
+        <%def name="title()"/>
+    </head>
+
+That is, ``title`` is defined outside of any other defs so that it is in the ``self`` namespace.
+It works, but the definition needs to be potentially far away from the point of render.
+
+A named block is always placed in the ``self`` namespace, regardless of nesting,
+so this restriction is lifted:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <head>
+        <%block name="header">
+            <title>
+            <%block name="title"/>
+            </title>
+        </%block>
+    </head>
+
+The above template defines ``title`` inside of ``header``, and an inheriting template can define
+one or both in **any** configuration, nested inside each other or not, in order for them to be used:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="base.html"/>
+    <%block name="title">
+        the title
+    </%block>
+    <%block name="header">
+        the header
+    </%block>
+
+So while the ``<%block>`` tag lifts the restriction of nested blocks not being available externally,
+in order to achieve this it *adds* the restriction that all block names in a single template need
+to be globally unique within the template, and additionally that a ``<%block>`` can't be defined
+inside of a ``<%def>``. It's a more restricted tag suited towards a more specific use case than ``<%def>``.
+
+Using the ``next`` Namespace to Produce Content Wrapping
+========================================================
+
+Sometimes you have an inheritance chain that spans more than two
+templates. Or maybe you don't, but you'd like to build your
+system such that extra inherited templates can be inserted in
+the middle of a chain where they would be smoothly integrated.
+If each template wants to define its layout just within its main
+body, you can't just call ``self.body()`` to get at the
+inheriting template's body, since that is only the topmost body.
+To get at the body of the *next* template, you call upon the
+namespace ``next``, which is the namespace of the template
+**immediately following** the current template.
+
+Lets change the line in ``base.html`` which calls upon
+``self.body()`` to instead call upon ``next.body()``:
+
+.. sourcecode:: mako
+
+    ## base.html
+    <html>
+        <body>
+            <div class="header">
+                <%block name="header"/>
+            </div>
+
+            ${next.body()}
+
+            <div class="footer">
+                <%block name="footer">
+                    this is the footer
+                </%block>
+            </div>
+        </body>
+    </html>
+
+
+Lets also add an intermediate template called ``layout.html``,
+which inherits from ``base.html``:
+
+.. sourcecode:: mako
+
+    ## layout.html
+    <%inherit file="base.html"/>
+    <ul>
+        <%block name="toolbar">
+            <li>selection 1</li>
+            <li>selection 2</li>
+            <li>selection 3</li>
+        </%block>
+    </ul>
+    <div class="mainlayout">
+        ${next.body()}
+    </div>
+
+And finally change ``index.html`` to inherit from
+``layout.html`` instead:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="layout.html"/>
+
+    ## .. rest of template
+
+In this setup, each call to ``next.body()`` will render the body
+of the next template in the inheritance chain (which can be
+written as ``base.html -> layout.html -> index.html``). Control
+is still first passed to the bottommost template ``base.html``,
+and ``self`` still references the topmost definition of any
+particular def.
+
+The output we get would be:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+            <div class="header">
+                this is some header content
+            </div>
+
+            <ul>
+                <li>selection 1</li>
+                <li>selection 2</li>
+                <li>selection 3</li>
+            </ul>
+
+            <div class="mainlayout">
+            this is the body content.
+            </div>
+
+            <div class="footer">
+                this is the footer
+            </div>
+        </body>
+    </html>
+
+So above, we have the ``<html>``, ``<body>`` and
+``header``/``footer`` layout of ``base.html``, we have the
+``<ul>`` and ``mainlayout`` section of ``layout.html``, and the
+main body of ``index.html`` as well as its overridden ``header``
+def. The ``layout.html`` template is inserted into the middle of
+the chain without ``base.html`` having to change anything.
+Without the ``next`` namespace, only the main body of
+``index.html`` could be used; there would be no way to call
+``layout.html``'s body content.
+
+.. _parent_namespace:
+
+Using the ``parent`` Namespace to Augment Defs
+==============================================
+
+Lets now look at the other inheritance-specific namespace, the
+opposite of ``next`` called ``parent``. ``parent`` is the
+namespace of the template **immediately preceding** the current
+template. What's useful about this namespace is that
+defs or blocks can call upon their overridden versions.
+This is not as hard as it sounds and
+is very much like using the ``super`` keyword in Python. Lets
+modify ``index.html`` to augment the list of selections provided
+by the ``toolbar`` function in ``layout.html``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%inherit file="layout.html"/>
+
+    <%block name="header">
+        this is some header content
+    </%block>
+
+    <%block name="toolbar">
+        ## call the parent's toolbar first
+        ${parent.toolbar()}
+        <li>selection 4</li>
+        <li>selection 5</li>
+    </%block>
+
+    this is the body content.
+
+Above, we implemented a ``toolbar()`` function, which is meant
+to override the definition of ``toolbar`` within the inherited
+template ``layout.html``. However, since we want the content
+from that of ``layout.html`` as well, we call it via the
+``parent`` namespace whenever we want it's content, in this case
+before we add our own selections. So the output for the whole
+thing is now:
+
+.. sourcecode:: html
+
+    <html>
+        <body>
+            <div class="header">
+                this is some header content
+            </div>
+
+            <ul>
+                <li>selection 1</li>
+                <li>selection 2</li>
+                <li>selection 3</li>
+                <li>selection 4</li>
+                <li>selection 5</li>
+            </ul>
+
+            <div class="mainlayout">
+            this is the body content.
+            </div>
+
+            <div class="footer">
+                this is the footer
+            </div>
+        </body>
+    </html>
+
+and you're now a template inheritance ninja!
+
+Using ``<%include>`` with Template Inheritance
+==============================================
+
+A common source of confusion is the behavior of the ``<%include>`` tag,
+often in conjunction with its interaction within template inheritance.
+Key to understanding the ``<%include>`` tag is that it is a *dynamic*, e.g.
+runtime, include, and not a static include.   The ``<%include>`` is only processed
+as the template renders, and not at inheritance setup time.   When encountered,
+the referenced template is run fully as an entirely separate template with no
+linkage to any current inheritance structure.
+
+If the tag were on the other hand a *static* include, this would allow source
+within the included template to interact within the same inheritance context
+as the calling template, but currently Mako has no static include facility.
+
+In practice, this means that ``<%block>`` elements defined in an ``<%include>``
+file will not interact with corresponding ``<%block>`` elements in the calling
+template.
+
+A common mistake is along these lines:
+
+.. sourcecode:: mako
+
+    ## partials.mako
+    <%block name="header">
+        Global Header
+    </%block>
+
+    ## parent.mako
+    <%include file="partials.mako">
+
+    ## child.mako
+    <%inherit file="parent.mako">
+    <%block name="header">
+        Custom Header
+    </%block>
+
+Above, one might expect that the ``"header"`` block declared in ``child.mako``
+might be invoked, as a result of it overriding the same block present in
+``parent.mako`` via the include for ``partials.mako``.  But this is not the case.
+Instead, ``parent.mako`` will invoke ``partials.mako``, which then invokes
+``"header"`` in ``partials.mako``, and then is finished rendering.  Nothing
+from ``child.mako`` will render; there is no interaction between the ``"header"``
+block in ``child.mako`` and the ``"header"`` block in ``partials.mako``.
+
+Instead, ``parent.mako`` must explicitly state the inheritance structure.
+In order to call upon specific elements of ``partials.mako``, we will call upon
+it as a namespace:
+
+.. sourcecode:: mako
+
+    ## partials.mako
+    <%block name="header">
+        Global Header
+    </%block>
+
+    ## parent.mako
+    <%namespace name="partials" file="partials.mako"/>
+    <%block name="header">
+        ${partials.header()}
+    </%block>
+
+    ## child.mako
+    <%inherit file="parent.mako">
+    <%block name="header">
+        Custom Header
+    </%block>
+
+Where above, ``parent.mako`` states the inheritance structure that ``child.mako``
+is to participate within.  ``partials.mako`` only defines defs/blocks that can be
+used on a per-name basis.
+
+Another scenario is below, which results in both ``"SectionA"`` blocks being rendered for the ``child.mako`` document:
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ${self.body()}
+    <%block name="SectionA">
+        base.mako
+    </%block>
+
+    ## parent.mako
+    <%inherit file="base.mako">
+    <%include file="child.mako">
+
+    ## child.mako
+    <%block name="SectionA">
+        child.mako
+    </%block>
+
+The resolution is similar; instead of using ``<%include>``, we call upon the blocks
+of ``child.mako`` using a namespace:
+
+.. sourcecode:: mako
+
+    ## parent.mako
+    <%inherit file="base.mako">
+    <%namespace name="child" file="child.mako">
+
+    <%block name="SectionA">
+        ${child.SectionA()}
+    </%block>
+
+
+.. _inheritance_attr:
+
+Inheritable Attributes
+======================
+
+The :attr:`attr <.Namespace.attr>` accessor of the :class:`.Namespace` object
+allows access to module level variables declared in a template. By accessing
+``self.attr``, you can access regular attributes from the
+inheritance chain as declared in ``<%! %>`` sections. Such as:
+
+.. sourcecode:: mako
+
+    <%!
+        class_ = "grey"
+    %>
+
+    <div class="${self.attr.class_}">
+        ${self.body()}
+    </div>
+
+If an inheriting template overrides ``class_`` to be
+``"white"``, as in:
+
+.. sourcecode:: mako
+
+    <%!
+        class_ = "white"
+    %>
+    <%inherit file="parent.html"/>
+
+    This is the body
+
+you'll get output like:
+
+.. sourcecode:: html
+
+    <div class="white">
+        This is the body
+    </div>
+
+.. seealso::
+
+    :ref:`namespace_attr_for_includes` - a more sophisticated example using
+    :attr:`.Namespace.attr`.
diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst
new file mode 100644 (file)
index 0000000..1453b80
--- /dev/null
@@ -0,0 +1,475 @@
+.. _namespaces_toplevel:
+
+==========
+Namespaces
+==========
+
+Namespaces are used to organize groups of defs into
+categories, and also to "import" defs from other files.
+
+If the file ``components.html`` defines these two defs:
+
+.. sourcecode:: mako
+
+    ## components.html
+    <%def name="comp1()">
+        this is comp1
+    </%def>
+
+    <%def name="comp2(x)">
+        this is comp2, x is ${x}
+    </%def>
+
+you can make another file, for example ``index.html``, that
+pulls those two defs into a namespace called ``comp``:
+
+.. sourcecode:: mako
+
+    ## index.html
+    <%namespace name="comp" file="components.html"/>
+
+    Here's comp1:  ${comp.comp1()}
+    Here's comp2:  ${comp.comp2(x=5)}
+
+The ``comp`` variable above is an instance of
+:class:`.Namespace`, a **proxy object** which delivers
+method calls to the underlying template callable using the
+current context.
+
+``<%namespace>`` also provides an ``import`` attribute which can
+be used to pull the names into the local namespace, removing the
+need to call it via the "``.``" operator. When ``import`` is used, the
+``name`` attribute is optional.
+
+.. sourcecode:: mako
+
+    <%namespace file="components.html" import="comp1, comp2"/>
+
+    Heres comp1:  ${comp1()}
+    Heres comp2:  ${comp2(x=5)}
+
+``import`` also supports the "``*``" operator:
+
+.. sourcecode:: mako
+
+    <%namespace file="components.html" import="*"/>
+
+    Heres comp1:  ${comp1()}
+    Heres comp2:  ${comp2(x=5)}
+
+The names imported by the ``import`` attribute take precedence
+over any names that exist within the current context.
+
+.. note:: In current versions of Mako, usage of ``import='*'`` is
+   known to decrease performance of the template. This will be
+   fixed in a future release.
+
+The ``file`` argument allows expressions -- if looking for
+context variables, the ``context`` must be named explicitly:
+
+.. sourcecode:: mako
+
+    <%namespace name="dyn" file="${context['namespace_name']}"/>
+
+Ways to Call Namespaces
+=======================
+
+There are essentially four ways to call a function from a
+namespace.
+
+The "expression" format, as described previously. Namespaces are
+just Python objects with functions on them, and can be used in
+expressions like any other function:
+
+.. sourcecode:: mako
+
+    ${mynamespace.somefunction('some arg1', 'some arg2', arg3='some arg3', arg4='some arg4')}
+
+Synonymous with the "expression" format is the "custom tag"
+format, when a "closed" tag is used. This format, introduced in
+Mako 0.2.3, allows the usage of a "custom" Mako tag, with the
+function arguments passed in using named attributes:
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="some arg1" arg2="some arg2" arg3="some arg3" arg4="some arg4"/>
+
+When using tags, the values of the arguments are taken as
+literal strings by default. To embed Python expressions as
+arguments, use the embedded expression format:
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="${someobject.format()}" arg2="${somedef(5, 12)}"/>
+
+The "custom tag" format is intended mainly for namespace
+functions which recognize body content, which in Mako is known
+as a "def with embedded content":
+
+.. sourcecode:: mako
+
+    <%mynamespace:somefunction arg1="some argument" args="x, y">
+        Some record: ${x}, ${y}
+    </%mynamespace:somefunction>
+
+The "classic" way to call defs with embedded content is the ``<%call>`` tag:
+
+.. sourcecode:: mako
+
+    <%call expr="mynamespace.somefunction(arg1='some argument')" args="x, y">
+        Some record: ${x}, ${y}
+    </%call>
+
+For information on how to construct defs that embed content from
+the caller, see :ref:`defs_with_content`.
+
+.. _namespaces_python_modules:
+
+Namespaces from Regular Python Modules
+======================================
+
+Namespaces can also import regular Python functions from
+modules. These callables need to take at least one argument,
+``context``, an instance of :class:`.Context`. A module file
+``some/module.py`` might contain the callable:
+
+.. sourcecode:: python
+
+    def my_tag(context):
+        context.write("hello world")
+        return ''
+
+A template can use this module via:
+
+.. sourcecode:: mako
+
+    <%namespace name="hw" module="some.module"/>
+
+    ${hw.my_tag()}
+
+Note that the ``context`` argument is not needed in the call;
+the :class:`.Namespace` tag creates a locally-scoped callable which
+takes care of it. The ``return ''`` is so that the def does not
+dump a ``None`` into the output stream -- the return value of any
+def is rendered after the def completes, in addition to whatever
+was passed to :meth:`.Context.write` within its body.
+
+If your def is to be called in an "embedded content" context,
+that is as described in :ref:`defs_with_content`, you should use
+the :func:`.supports_caller` decorator, which will ensure that Mako
+will ensure the correct "caller" variable is available when your
+def is called, supporting embedded content:
+
+.. sourcecode:: python
+
+    from mako.runtime import supports_caller
+
+    @supports_caller
+    def my_tag(context):
+        context.write("<div>")
+        context['caller'].body()
+        context.write("</div>")
+        return ''
+
+Capturing of output is available as well, using the
+outside-of-templates version of the :func:`.capture` function,
+which accepts the "context" as its first argument:
+
+.. sourcecode:: python
+
+    from mako.runtime import supports_caller, capture
+
+    @supports_caller
+    def my_tag(context):
+        return "<div>%s</div>" % \
+                capture(context, context['caller'].body, x="foo", y="bar")
+
+Declaring Defs in Namespaces
+============================
+
+The ``<%namespace>`` tag supports the definition of ``<%def>``\ s
+directly inside the tag. These defs become part of the namespace
+like any other function, and will override the definitions
+pulled in from a remote template or module:
+
+.. sourcecode:: mako
+
+    ## define a namespace
+    <%namespace name="stuff">
+        <%def name="comp1()">
+            comp1
+        </%def>
+    </%namespace>
+
+    ## then call it
+    ${stuff.comp1()}
+
+.. _namespaces_body:
+
+The ``body()`` Method
+=====================
+
+Every namespace that is generated from a template contains a
+method called ``body()``. This method corresponds to the main
+body of the template, and plays its most important roles when
+using inheritance relationships as well as
+def-calls-with-content.
+
+Since the ``body()`` method is available from a namespace just
+like all the other defs defined in a template, what happens if
+you send arguments to it? By default, the ``body()`` method
+accepts no positional arguments, and for usefulness in
+inheritance scenarios will by default dump all keyword arguments
+into a dictionary called ``pageargs``. But if you actually want
+to get at the keyword arguments, Mako recommends you define your
+own argument signature explicitly. You do this via using the
+``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%page args="x, y, someval=8, scope='foo', **kwargs"/>
+
+A template which defines the above signature requires that the
+variables ``x`` and ``y`` are defined, defines default values
+for ``someval`` and ``scope``, and sets up ``**kwargs`` to
+receive all other keyword arguments. If ``**kwargs`` or similar
+is not present, the argument ``**pageargs`` gets tacked on by
+Mako. When the template is called as a top-level template (i.e.
+via :meth:`~.Template.render`) or via the ``<%include>`` tag, the
+values for these arguments will be pulled from the ``Context``.
+In all other cases, i.e. via calling the ``body()`` method, the
+arguments are taken as ordinary arguments from the method call.
+So above, the body might be called as:
+
+.. sourcecode:: mako
+
+    ${self.body(5, y=10, someval=15, delta=7)}
+
+The :class:`.Context` object also supplies a :attr:`~.Context.kwargs`
+accessor, for cases when you'd like to pass along the top level context
+arguments to a ``body()`` callable:
+
+.. sourcecode:: mako
+
+    ${next.body(**context.kwargs)}
+
+The usefulness of calls like the above become more apparent when
+one works with inheriting templates. For more information on
+this, as well as the meanings of the names ``self`` and
+``next``, see :ref:`inheritance_toplevel`.
+
+.. _namespaces_builtin:
+
+Built-in Namespaces
+===================
+
+The namespace is so great that Mako gives your template one (or
+two) for free. The names of these namespaces are ``local`` and
+``self``. Other built-in namespaces include ``parent`` and
+``next``, which are optional and are described in
+:ref:`inheritance_toplevel`.
+
+.. _namespace_local:
+
+``local``
+---------
+
+The ``local`` namespace is basically the namespace for the
+currently executing template. This means that all of the top
+level defs defined in your template, as well as your template's
+``body()`` function, are also available off of the ``local``
+namespace.
+
+The ``local`` namespace is also where properties like ``uri``,
+``filename``, and ``module`` and the ``get_namespace`` method
+can be particularly useful.
+
+.. _namespace_self:
+
+``self``
+--------
+
+The ``self`` namespace, in the case of a template that does not
+use inheritance, is synonymous with ``local``. If inheritance is
+used, then ``self`` references the topmost template in the
+inheritance chain, where it is most useful for providing the
+ultimate form of various "method" calls which may have been
+overridden at various points in an inheritance chain. See
+:ref:`inheritance_toplevel`.
+
+Inheritable Namespaces
+======================
+
+The ``<%namespace>`` tag includes an optional attribute
+``inheritable="True"``, which will cause the namespace to be
+attached to the ``self`` namespace. Since ``self`` is globally
+available throughout an inheritance chain (described in the next
+section), all the templates in an inheritance chain can get at
+the namespace imported in a super-template via ``self``.
+
+.. sourcecode:: mako
+
+    ## base.html
+    <%namespace name="foo" file="foo.html" inheritable="True"/>
+
+    ${next.body()}
+
+    ## somefile.html
+    <%inherit file="base.html"/>
+
+    ${self.foo.bar()}
+
+This allows a super-template to load a whole bunch of namespaces
+that its inheriting templates can get to, without them having to
+explicitly load those namespaces themselves.
+
+The ``import="*"`` part of the ``<%namespace>`` tag doesn't yet
+interact with the ``inheritable`` flag, so currently you have to
+use the explicit namespace name off of ``self``, followed by the
+desired function name. But more on this in a future release.
+
+Namespace API Usage Example - Static Dependencies
+==================================================
+
+The ``<%namespace>`` tag at runtime produces an instance of
+:class:`.Namespace`.   Programmatic access of :class:`.Namespace` can be used
+to build various kinds of scaffolding in templates and between templates.
+
+A common request is the ability for a particular template to declare
+"static includes" - meaning, the usage of a particular set of defs requires
+that certain Javascript/CSS files are present.   Using :class:`.Namespace` as the
+object that holds together the various templates present, we can build a variety
+of such schemes.   In particular, the :class:`.Context` has a ``namespaces``
+attribute, which is a dictionary of all :class:`.Namespace` objects declared.
+Iterating the values of this dictionary will provide a :class:`.Namespace`
+object for each time the ``<%namespace>`` tag was used, anywhere within the
+inheritance chain.
+
+
+.. _namespace_attr_for_includes:
+
+Version One - Use :attr:`.Namespace.attr`
+-----------------------------------------
+
+The :attr:`.Namespace.attr` attribute allows us to locate any variables declared
+in the ``<%! %>`` of a template.
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ## base-most template, renders layout etc.
+    <html>
+    <head>
+    ## traverse through all namespaces present,
+    ## look for an attribute named 'includes'
+    % for ns in context.namespaces.values():
+        % for incl in getattr(ns.attr, 'includes', []):
+            ${incl}
+        % endfor
+    % endfor
+    </head>
+    <body>
+    ${next.body()}
+    </body
+    </html>
+
+    ## library.mako
+    ## library functions.
+    <%!
+        includes = [
+            '<link rel="stylesheet" type="text/css" href="mystyle.css"/>',
+            '<script type="text/javascript" src="functions.js"></script>'
+        ]
+    %>
+
+    <%def name="mytag()">
+        <form>
+            ${caller.body()}
+        </form>
+    </%def>
+
+    ## index.mako
+    ## calling template.
+    <%inherit file="base.mako"/>
+    <%namespace name="foo" file="library.mako"/>
+
+    <%foo:mytag>
+        a form
+    </%foo:mytag>
+
+
+Above, the file ``library.mako`` declares an attribute ``includes`` inside its global ``<%! %>`` section.
+``index.mako`` includes this template using the ``<%namespace>`` tag.  The base template ``base.mako``, which is the inherited parent of ``index.mako`` and is reponsible for layout, then locates this attribute and iterates through its contents to produce the includes that are specific to ``library.mako``.
+
+Version Two - Use a specific named def
+-----------------------------------------
+
+In this version, we put the includes into a ``<%def>`` that
+follows a naming convention.
+
+.. sourcecode:: mako
+
+    ## base.mako
+    ## base-most template, renders layout etc.
+    <html>
+    <head>
+    ## traverse through all namespaces present,
+    ## look for a %def named 'includes'
+    % for ns in context.namespaces.values():
+        % if hasattr(ns, 'includes'):
+            ${ns.includes()}
+        % endif
+    % endfor
+    </head>
+    <body>
+    ${next.body()}
+    </body
+    </html>
+
+    ## library.mako
+    ## library functions.
+
+    <%def name="includes()">
+        <link rel="stylesheet" type="text/css" href="mystyle.css"/>
+        <script type="text/javascript" src="functions.js"></script>
+    </%def>
+
+    <%def name="mytag()">
+        <form>
+            ${caller.body()}
+        </form>
+    </%def>
+
+
+    ## index.mako
+    ## calling template.
+    <%inherit file="base.mako"/>
+    <%namespace name="foo" file="library.mako"/>
+
+    <%foo:mytag>
+        a form
+    </%foo:mytag>
+
+In this version, ``library.mako`` declares a ``<%def>`` named ``includes``.   The example works
+identically to the previous one, except that ``base.mako`` looks for defs named ``include``
+on each namespace it examines.
+
+API Reference
+=============
+
+.. autoclass:: mako.runtime.Namespace
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.TemplateNamespace
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.ModuleNamespace
+    :show-inheritance:
+    :members:
+
+.. autofunction:: mako.runtime.supports_caller
+
+.. autofunction:: mako.runtime.capture
+
diff --git a/doc/build/requirements.txt b/doc/build/requirements.txt
new file mode 100644 (file)
index 0000000..cc5dfbd
--- /dev/null
@@ -0,0 +1,2 @@
+changelog>=0.3.4
+sphinx-paramlinks>=0.2.0
diff --git a/doc/build/runtime.rst b/doc/build/runtime.rst
new file mode 100644 (file)
index 0000000..17c9b99
--- /dev/null
@@ -0,0 +1,448 @@
+.. _runtime_toplevel:
+
+============================
+The Mako Runtime Environment
+============================
+
+This section describes a little bit about the objects and
+built-in functions that are available in templates.
+
+.. _context:
+
+Context
+=======
+
+The :class:`.Context` is the central object that is created when
+a template is first executed, and is responsible for handling
+all communication with the outside world.  Within the template
+environment, it is available via the :ref:`reserved name <reserved_names>`
+``context``.  The :class:`.Context` includes two
+major components, one of which is the output buffer, which is a
+file-like object such as Python's ``StringIO`` or similar, and
+the other a dictionary of variables that can be freely
+referenced within a template; this dictionary is a combination
+of the arguments sent to the :meth:`~.Template.render` function and
+some built-in variables provided by Mako's runtime environment.
+
+The Buffer
+----------
+
+The buffer is stored within the :class:`.Context`, and writing
+to it is achieved by calling the :meth:`~.Context.write` method
+-- in a template this looks like ``context.write('some string')``.
+You usually don't need to care about this, as all text within a template, as
+well as all expressions provided by ``${}``, automatically send
+everything to this method. The cases you might want to be aware
+of its existence are if you are dealing with various
+filtering/buffering scenarios, which are described in
+:ref:`filtering_toplevel`, or if you want to programmatically
+send content to the output stream, such as within a ``<% %>``
+block.
+
+.. sourcecode:: mako
+
+    <%
+        context.write("some programmatic text")
+    %>
+
+The actual buffer may or may not be the original buffer sent to
+the :class:`.Context` object, as various filtering/caching
+scenarios may "push" a new buffer onto the context's underlying
+buffer stack. For this reason, just stick with
+``context.write()`` and content will always go to the topmost
+buffer.
+
+.. _context_vars:
+
+Context Variables
+-----------------
+
+When your template is compiled into a Python module, the body
+content is enclosed within a Python function called
+``render_body``. Other top-level defs defined in the template are
+defined within their own function bodies which are named after
+the def's name with the prefix ``render_`` (i.e. ``render_mydef``).
+One of the first things that happens within these functions is
+that all variable names that are referenced within the function
+which are not defined in some other way (i.e. such as via
+assignment, module level imports, etc.) are pulled from the
+:class:`.Context` object's dictionary of variables. This is how you're
+able to freely reference variable names in a template which
+automatically correspond to what was passed into the current
+:class:`.Context`.
+
+* **What happens if I reference a variable name that is not in
+  the current context?** - The value you get back is a special
+  value called ``UNDEFINED``, or if the ``strict_undefined=True`` flag
+  is used a ``NameError`` is raised. ``UNDEFINED`` is just a simple global
+  variable with the class :class:`mako.runtime.Undefined`. The
+  ``UNDEFINED`` object throws an error when you call ``str()`` on
+  it, which is what happens if you try to use it in an
+  expression.
+* **UNDEFINED makes it hard for me to find what name is missing** - An alternative
+  is to specify the option ``strict_undefined=True``
+  to the :class:`.Template` or :class:`.TemplateLookup`.  This will cause
+  any non-present variables to raise an immediate ``NameError``
+  which includes the name of the variable in its message
+  when :meth:`~.Template.render` is called -- ``UNDEFINED`` is not used.
+
+  .. versionadded:: 0.3.6
+
+* **Why not just return None?** Using ``UNDEFINED``, or
+  raising a ``NameError`` is more
+  explicit and allows differentiation between a value of ``None``
+  that was explicitly passed to the :class:`.Context` and a value that
+  wasn't present at all.
+* **Why raise an exception when you call str() on it ? Why not
+  just return a blank string?** - Mako tries to stick to the
+  Python philosophy of "explicit is better than implicit". In
+  this case, it's decided that the template author should be made
+  to specifically handle a missing value rather than
+  experiencing what may be a silent failure. Since ``UNDEFINED``
+  is a singleton object just like Python's ``True`` or ``False``,
+  you can use the ``is`` operator to check for it:
+
+  .. sourcecode:: mako
+
+        % if someval is UNDEFINED:
+            someval is: no value
+        % else:
+            someval is: ${someval}
+        % endif
+
+Another facet of the :class:`.Context` is that its dictionary of
+variables is **immutable**. Whatever is set when
+:meth:`~.Template.render` is called is what stays. Of course, since
+its Python, you can hack around this and change values in the
+context's internal dictionary, but this will probably will not
+work as well as you'd think. The reason for this is that Mako in
+many cases creates copies of the :class:`.Context` object, which
+get sent to various elements of the template and inheriting
+templates used in an execution. So changing the value in your
+local :class:`.Context` will not necessarily make that value
+available in other parts of the template's execution. Examples
+of where Mako creates copies of the :class:`.Context` include
+within top-level def calls from the main body of the template
+(the context is used to propagate locally assigned variables
+into the scope of defs; since in the template's body they appear
+as inlined functions, Mako tries to make them act that way), and
+within an inheritance chain (each template in an inheritance
+chain has a different notion of ``parent`` and ``next``, which
+are all stored in unique :class:`.Context` instances).
+
+* **So what if I want to set values that are global to everyone
+  within a template request?** - All you have to do is provide a
+  dictionary to your :class:`.Context` when the template first
+  runs, and everyone can just get/set variables from that. Lets
+  say its called ``attributes``.
+
+  Running the template looks like:
+
+  .. sourcecode:: python
+
+      output = template.render(attributes={})
+
+  Within a template, just reference the dictionary:
+
+  .. sourcecode:: mako
+
+      <%
+          attributes['foo'] = 'bar'
+      %>
+      'foo' attribute is: ${attributes['foo']}
+
+* **Why can't "attributes" be a built-in feature of the
+  Context?** - This is an area where Mako is trying to make as
+  few decisions about your application as it possibly can.
+  Perhaps you don't want your templates to use this technique of
+  assigning and sharing data, or perhaps you have a different
+  notion of the names and kinds of data structures that should
+  be passed around. Once again Mako would rather ask the user to
+  be explicit.
+
+Context Methods and Accessors
+-----------------------------
+
+Significant members of :class:`.Context` include:
+
+* ``context[key]`` / ``context.get(key, default=None)`` -
+  dictionary-like accessors for the context. Normally, any
+  variable you use in your template is automatically pulled from
+  the context if it isn't defined somewhere already. Use the
+  dictionary accessor and/or ``get`` method when you want a
+  variable that *is* already defined somewhere else, such as in
+  the local arguments sent to a ``%def`` call. If a key is not
+  present, like a dictionary it raises ``KeyError``.
+* ``keys()`` - all the names defined within this context.
+* ``kwargs`` - this returns a **copy** of the context's
+  dictionary of variables. This is useful when you want to
+  propagate the variables in the current context to a function
+  as keyword arguments, i.e.:
+
+  .. sourcecode:: mako
+
+        ${next.body(**context.kwargs)}
+
+* ``write(text)`` - write some text to the current output
+  stream.
+* ``lookup`` - returns the :class:`.TemplateLookup` instance that is
+  used for all file-lookups within the current execution (even
+  though individual :class:`.Template` instances can conceivably have
+  different instances of a :class:`.TemplateLookup`, only the
+  :class:`.TemplateLookup` of the originally-called :class:`.Template` gets
+  used in a particular execution).
+
+.. _loop_context:
+
+The Loop Context
+================
+
+Within ``% for`` blocks, the :ref:`reserved name<reserved_names>` ``loop``
+is available.  ``loop`` tracks the progress of
+the ``for`` loop and makes it easy to use the iteration state to control
+template behavior:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for a in ("one", "two", "three"):
+        <li>Item ${loop.index}: ${a}</li>
+    % endfor
+    </ul>
+
+.. versionadded:: 0.7
+
+Iterations
+----------
+
+Regardless of the type of iterable you're looping over, ``loop`` always tracks
+the 0-indexed iteration count (available at ``loop.index``), its parity
+(through the ``loop.even`` and ``loop.odd`` bools), and ``loop.first``, a bool
+indicating whether the loop is on its first iteration.  If your iterable
+provides a ``__len__`` method, ``loop`` also provides access to
+a count of iterations remaining at ``loop.reverse_index`` and ``loop.last``,
+a bool indicating whether the loop is on its last iteration; accessing these
+without ``__len__`` will raise a ``TypeError``.
+
+Cycling
+-------
+
+Cycling is available regardless of whether the iterable you're using provides
+a ``__len__`` method.  Prior to Mako 0.7, you might have generated a simple
+zebra striped list using ``enumerate``:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for i, item in enumerate(('spam', 'ham', 'eggs')):
+      <li class="${'odd' if i % 2 else 'even'}">${item}</li>
+    % endfor
+    </ul>
+
+With ``loop.cycle``, you get the same results with cleaner code and less prep work:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for item in ('spam', 'ham', 'eggs'):
+      <li class="${loop.cycle('even', 'odd')}">${item}</li>
+    % endfor
+    </ul>
+
+Both approaches produce output like the following:
+
+.. sourcecode:: html
+
+    <ul>
+      <li class="even">spam</li>
+      <li class="odd">ham</li>
+      <li class="even">eggs</li>
+    </ul>
+
+Parent Loops
+------------
+
+Loop contexts can also be transparently nested, and the Mako runtime will do
+the right thing and manage the scope for you.  You can access the parent loop
+context through ``loop.parent``.
+
+This allows you to reach all the way back up through the loop stack by
+chaining ``parent`` attribute accesses, i.e. ``loop.parent.parent....`` as
+long as the stack depth isn't exceeded.  For example, you can use the parent
+loop to make a checkered table:
+
+.. sourcecode:: mako
+
+    <table>
+    % for consonant in 'pbj':
+      <tr>
+      % for vowel in 'iou':
+        <td class="${'black' if (loop.parent.even == loop.even) else 'red'}">
+          ${consonant + vowel}t
+        </td>
+      % endfor
+      </tr>
+    % endfor
+    </table>
+
+.. sourcecode:: html
+
+    <table>
+      <tr>
+        <td class="black">
+          pit
+        </td>
+        <td class="red">
+          pot
+        </td>
+        <td class="black">
+          put
+        </td>
+      </tr>
+      <tr>
+        <td class="red">
+          bit
+        </td>
+        <td class="black">
+          bot
+        </td>
+        <td class="red">
+          but
+        </td>
+      </tr>
+      <tr>
+        <td class="black">
+          jit
+        </td>
+        <td class="red">
+          jot
+        </td>
+        <td class="black">
+          jut
+        </td>
+      </tr>
+    </table>
+
+.. _migrating_loop:
+
+Migrating Legacy Templates that Use the Word "loop"
+---------------------------------------------------
+
+.. versionchanged:: 0.7
+   The ``loop`` name is now :ref:`reserved <reserved_names>` in Mako,
+   which means a template that refers to a variable named ``loop``
+   won't function correctly when used in Mako 0.7.
+
+To ease the transition for such systems, the feature can be disabled across the board for
+all templates, then re-enabled on a per-template basis for those templates which wish
+to make use of the new system.
+
+First, the ``enable_loop=False`` flag is passed to either the :class:`.TemplateLookup`
+or :class:`.Template` object in use:
+
+.. sourcecode:: python
+
+    lookup = TemplateLookup(directories=['/docs'], enable_loop=False)
+
+or:
+
+.. sourcecode:: python
+
+    template = Template("some template", enable_loop=False)
+
+An individual template can make usage of the feature when ``enable_loop`` is set to
+``False`` by switching it back on within the ``<%page>`` tag:
+
+.. sourcecode:: mako
+
+    <%page enable_loop="True"/>
+
+    % for i in collection:
+        ${i} ${loop.index}
+    % endfor
+
+Using the above scheme, it's safe to pass the name ``loop`` to the :meth:`.Template.render`
+method as well as to freely make usage of a variable named ``loop`` within a template, provided
+the ``<%page>`` tag doesn't override it.  New templates that want to use the ``loop`` context
+can then set up ``<%page enable_loop="True"/>`` to use the new feature without affecting
+old templates.
+
+All the Built-in Names
+======================
+
+A one-stop shop for all the names Mako defines. Most of these
+names are instances of :class:`.Namespace`, which are described
+in the next section, :ref:`namespaces_toplevel`. Also, most of
+these names other than ``context``, ``UNDEFINED``, and ``loop`` are
+also present *within* the :class:`.Context` itself.   The names
+``context``, ``loop`` and ``UNDEFINED`` themselves can't be passed
+to the context and can't be substituted -- see the section :ref:`reserved_names`.
+
+* ``context`` - this is the :class:`.Context` object, introduced
+  at :ref:`context`.
+* ``local`` - the namespace of the current template, described
+  in :ref:`namespaces_builtin`.
+* ``self`` - the namespace of the topmost template in an
+  inheritance chain (if any, otherwise the same as ``local``),
+  mostly described in :ref:`inheritance_toplevel`.
+* ``parent`` - the namespace of the parent template in an
+  inheritance chain (otherwise undefined); see
+  :ref:`inheritance_toplevel`.
+* ``next`` - the namespace of the next template in an
+  inheritance chain (otherwise undefined); see
+  :ref:`inheritance_toplevel`.
+* ``caller`` - a "mini" namespace created when using the
+  ``<%call>`` tag to define a "def call with content"; described
+  in :ref:`defs_with_content`.
+* ``loop`` - this provides access to :class:`.LoopContext` objects when
+  they are requested within ``% for`` loops, introduced at :ref:`loop_context`.
+* ``capture`` - a function that calls a given def and captures
+  its resulting content into a string, which is returned. Usage
+  is described in :ref:`filtering_toplevel`.
+* ``UNDEFINED`` - a global singleton that is applied to all
+  otherwise uninitialized template variables that were not
+  located within the :class:`.Context` when rendering began,
+  unless the :class:`.Template` flag ``strict_undefined``
+  is set to ``True``. ``UNDEFINED`` is
+  an instance of :class:`.Undefined`, and raises an
+  exception when its ``__str__()`` method is called.
+* ``pageargs`` - this is a dictionary which is present in a
+  template which does not define any ``**kwargs`` section in its
+  ``<%page>`` tag. All keyword arguments sent to the ``body()``
+  function of a template (when used via namespaces) go here by
+  default unless otherwise defined as a page argument. If this
+  makes no sense, it shouldn't; read the section
+  :ref:`namespaces_body`.
+
+.. _reserved_names:
+
+Reserved Names
+--------------
+
+Mako has a few names that are considered to be "reserved" and can't be used
+as variable names.
+
+.. versionchanged:: 0.7
+   Mako raises an error if these words are found passed to the template
+   as context arguments, whereas in previous versions they'd be silently
+   ignored or lead to other error messages.
+
+* ``context`` - see :ref:`context`.
+* ``UNDEFINED`` - see :ref:`context_vars`.
+* ``loop`` - see :ref:`loop_context`.  Note this can be disabled for legacy templates
+  via the ``enable_loop=False`` argument; see :ref:`migrating_loop`.
+
+API Reference
+=============
+
+.. autoclass:: mako.runtime.Context
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.LoopContext
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.runtime.Undefined
+    :show-inheritance:
+
diff --git a/doc/build/static/docs.css b/doc/build/static/docs.css
new file mode 100644 (file)
index 0000000..3d9e1c5
--- /dev/null
@@ -0,0 +1,438 @@
+/* global */
+
+body {
+  background-color: #FDFBFC;
+  margin:38px;
+  color:#333333;
+}
+
+a {
+    font-weight:normal; 
+    text-decoration:none;
+}
+
+form {
+    display:inline;
+}
+
+/* hyperlinks */
+
+a:link, a:visited, a:active {
+    color:#0000FF;
+}
+a:hover {
+    color:#700000;
+    text-decoration:underline;
+}
+
+/* paragraph links after sections.
+   These aren't visible until hovering
+   over the <h> tag, then have a 
+   "reverse video" effect over the actual
+   link
+ */
+
+a.headerlink {
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover {
+    background-color: #990000;
+    color: white;
+}
+
+
+/* Container setup */
+
+#docs-container {
+  max-width:1000px;
+}
+
+
+/* header/footer elements */
+
+#docs-header h1 {
+    font-size:20px;
+    color: #222222;
+    margin: 0;
+    padding: 0;
+}
+
+#docs-header {
+  font-family:Tahoma, Geneva,sans-serif;
+
+  font-size:.9em;
+
+}
+
+#docs-top-navigation,
+#docs-bottom-navigation {
+  font-family: Tahoma, Geneva, sans-serif;
+  background-color: #EEE;
+  border: solid 1px #CCC;
+  padding:10px;
+  font-size:.9em;
+}
+
+#docs-top-navigation {
+  margin:10px 0px 10px 0px;
+  line-height:1.2em;
+}
+
+.docs-navigation-links {
+  font-family:Tahoma, Geneva,sans-serif;
+}
+
+#docs-bottom-navigation {
+    float:right;
+    margin: 1em 0 1em 5px;
+}
+
+#docs-copyright {
+    font-size:.85em;
+    padding:5px 0px;
+}
+
+#docs-header h1,
+#docs-top-navigation h1,
+#docs-top-navigation h2 {
+  font-family:Tahoma,Geneva,sans-serif;
+  font-weight:normal;
+}
+
+#docs-top-navigation h2 {
+    margin:16px 4px 7px 5px;
+    font-size:2em;
+}
+
+#docs-search {
+    float:right;
+}
+
+#docs-top-page-control {
+  float:right;
+  width:350px;
+}
+
+#docs-top-page-control ul {
+  padding:0;
+  margin:0;
+}
+
+#docs-top-page-control li {
+    list-style-type:none;
+    padding:1px 8px;
+}
+
+
+#docs-container .version-num {
+    font-weight: bold;
+}
+
+
+/* content container, sidebar */
+
+#docs-body-container {
+  background-color:#EFEFEF;
+  border: solid 1px #CCC;
+
+}
+
+#docs-body,
+#docs-sidebar
+ {
+  /*font-family: helvetica, arial, sans-serif;
+  font-size:.9em;*/
+
+  font-family: Tahoma, Geneva, sans-serif;
+  /*font-size:.85em;*/
+  line-height:1.5em;
+
+}
+
+#docs-sidebar > ul {
+  font-size:.9em;
+}
+
+#docs-sidebar {
+  float:left;
+  width:212px;
+  padding: 10px 0 0 15px;
+  /*font-size:.85em;*/
+}
+
+#docs-sidebar h3, #docs-sidebar h4 {
+    background-color: #DDDDDD;
+    color: #222222;
+    font-family: Tahoma, Geneva,sans-serif;
+    font-size: 1.1em;
+    font-weight: normal;
+    margin: 10px 0 0 -15px;
+    padding: 5px 10px 5px 10px;
+    text-shadow: 1px 1px 0 white;
+    width:210px;
+}
+
+#docs-sidebar h3 a, #docs-sidebar h4 a {
+  color: #222222;
+}
+#docs-sidebar ul {
+  margin: 10px 10px 10px 0px;
+  padding: 0;
+  list-style: none outside none;
+}
+
+
+#docs-sidebar ul ul {
+    margin-bottom: 0;
+    margin-top: 0;
+    list-style: square outside none;
+    margin-left: 20px;
+}
+
+#docs-body {
+  background-color:#FFFFFF;
+  padding:1px 10px 10px 10px;
+}
+
+#docs-body.withsidebar {
+  margin: 0 0 0 230px;
+  border-left:3px solid #DFDFDF;
+}
+
+#docs-body h1,
+#docs-body h2,
+#docs-body h3,
+#docs-body h4 {
+  font-family:Tahoma, Geneva, sans-serif;
+}
+
+#docs-body h1 {
+  /* hide the <h1> for each content section. */
+  display:none;
+  font-size:1.8em;
+}
+
+#docs-body h2 {
+  font-size:1.6em;
+}
+
+#docs-body h3 {
+  font-size:1.4em;
+}
+
+/* SQL popup, code styles */
+
+.highlight {
+  background:none;
+}
+
+#docs-container pre {
+  font-size:1.2em;
+}
+
+#docs-container .pre {
+  font-size:1.1em;
+}
+
+#docs-container pre {
+  background-color: #f0f0f0;  
+  border: solid 1px #ccc;
+  box-shadow: 2px 2px 3px #DFDFDF;
+  padding:10px;
+  margin: 5px 0px 5px 0px;
+  overflow:auto;
+  line-height:1.3em;
+}
+
+.popup_sql, .show_sql
+{
+    background-color: #FBFBEE;
+    padding:5px 10px;
+    margin:10px -5px;
+    border:1px dashed;
+}
+
+/* the [SQL] links used to display SQL */
+#docs-container .sql_link
+{
+  font-weight:normal;
+  font-family: arial, sans-serif;
+  font-size:.9em;
+  text-transform: uppercase;
+  color:#990000;
+  border:1px solid;
+  padding:1px 2px 1px 2px;
+  margin:0px 10px 0px 15px;
+  float:right;
+  line-height:1.2em;
+}
+
+#docs-container a.sql_link, 
+#docs-container .sql_link
+{
+    text-decoration: none;
+    padding:1px 2px;
+}
+
+#docs-container a.sql_link:hover {
+    text-decoration: none;
+    color:#fff;
+    border:1px solid #900;
+    background-color: #900;
+}
+
+/* docutils-specific elements */
+
+th.field-name {
+    text-align:right;
+}
+
+div.note, div.warning, p.deprecated, div.topic  {
+    background-color:#EEFFEF;
+}
+
+
+div.admonition, div.topic, p.deprecated, p.versionadded, p.versionchanged {
+    border:1px solid #CCCCCC;
+    padding:5px 10px;
+    font-size:.9em;
+    box-shadow: 2px 2px 3px #DFDFDF;
+}
+
+div.warning .admonition-title {
+    color:#FF0000;
+}
+
+div.admonition .admonition-title, div.topic .topic-title {
+    font-weight:bold;
+}
+
+.viewcode-back, .viewcode-link {
+    float:right;
+}
+
+dl.function > dt,
+dl.attribute > dt,
+dl.classmethod > dt,
+dl.method > dt,
+dl.class > dt,
+dl.exception > dt
+{
+    background-color:#F0F0F0;
+    margin:25px -10px 10px 10px;
+    padding: 0px 10px;
+}
+
+p.versionadded span.versionmodified,
+p.versionchanged span.versionmodified,
+p.deprecated span.versionmodified {
+    background-color: #F0F0F0;
+    font-style: italic;
+}
+
+dt:target, span.highlight {
+    background-color:#FBE54E;
+}
+
+a.headerlink {
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover {
+    background-color: #00f;
+    color: white;
+}
+
+.clearboth {
+    clear:both;
+}
+
+tt.descname {
+    background-color:transparent;
+    font-size:1.2em;
+    font-weight:bold;
+}
+
+tt.descclassname {
+    background-color:transparent;
+}
+
+tt {
+    background-color:#ECF0F3;
+    padding:0 1px;
+}
+
+/* syntax highlighting overrides */
+.k, .kn {color:#0908CE;}
+.o {color:#BF0005;}
+.go {color:#804049;}
+
+
+/* special "index page" sections 
+   with specific formatting
+*/
+
+div#sqlalchemy-documentation {
+  font-size:.95em;
+}
+div#sqlalchemy-documentation em {
+  font-style:normal;
+}
+div#sqlalchemy-documentation .rubric{
+  font-size:14px;
+  background-color:#EEFFEF;
+  padding:5px;
+  border:1px solid #BFBFBF;
+}
+div#sqlalchemy-documentation a, div#sqlalchemy-documentation li {
+  padding:5px 0px;
+}
+
+div#getting-started {
+  border-bottom:1px solid;
+}
+
+div#sqlalchemy-documentation div#sqlalchemy-orm {
+  float:left;
+  width:48%;
+}
+
+div#sqlalchemy-documentation div#sqlalchemy-core {
+  float:left;
+  width:48%;
+  margin:0;
+  padding-left:10px;
+  border-left:1px solid;
+}
+
+div#dialect-documentation {
+  border-top:1px solid;
+  /*clear:left;*/
+}
diff --git a/doc/build/static/makoLogo.png b/doc/build/static/makoLogo.png
new file mode 100644 (file)
index 0000000..c43c087
Binary files /dev/null and b/doc/build/static/makoLogo.png differ
diff --git a/doc/build/static/site.css b/doc/build/static/site.css
new file mode 100644 (file)
index 0000000..5b12b22
--- /dev/null
@@ -0,0 +1,86 @@
+body {
+    font-family: Tahoma, Geneva, sans-serif;
+    line-height:1.4em;
+    margin:15px;
+    background-color:#FFFFFF;
+}
+img {border:none;}
+a { text-decoration: none;}
+a:visited  { color: #2929ff;}
+a:hover { color: #0000ff;}
+
+#wrap {
+    margin:0 auto;
+    max-width:1024px;
+    min-width:480px;
+    position:relative;
+
+}
+h1 {
+    font-size:1.6em;
+    font-weight:bold;
+}
+
+h2 {
+    font-size:1.1em;
+    font-weight:bold;
+    margin:10px 0px 10px 0px;
+}
+
+.clearfix{
+    clear:both;
+}
+
+.red {
+       font-weight:bold;
+       color:#FF0000;
+}
+.rightbar {
+    float:right;
+}
+.slogan {
+    margin-top:10px;
+}
+#gittip_nav {
+    float:right;
+    margin:10px 0px 0px 0px;
+}
+
+.toolbar {
+    margin-top:20px;
+}
+.copyright {
+    font-size:.8em;
+    text-align:center;
+    color:909090;
+}
+.pylogo {
+       text-align:right;
+       float:right;
+}
+.code {
+    font-family:monospace;
+}
+
+li {
+    margin:1px 0px 1px 0px;
+}
+
+.speedchart td {
+    font-size:small;
+}
+
+pre.codesample {
+    margin: 1.5em;
+    padding: .5em;
+    font-size: .95em;
+    line-height:1em;
+    background-color: #eee;
+    border: 1px solid #ccc;
+    width:450px;
+    overflow:auto;
+}
+
+#speedchart {
+    margin:5px 10px 5px 10px;
+}
diff --git a/doc/build/syntax.rst b/doc/build/syntax.rst
new file mode 100644 (file)
index 0000000..e3dd7db
--- /dev/null
@@ -0,0 +1,486 @@
+.. _syntax_toplevel:
+
+======
+Syntax
+======
+
+A Mako template is parsed from a text stream containing any kind
+of content, XML, HTML, email text, etc. The template can further
+contain Mako-specific directives which represent variable and/or
+expression substitutions, control structures (i.e. conditionals
+and loops), server-side comments, full blocks of Python code, as
+well as various tags that offer additional functionality. All of
+these constructs compile into real Python code. This means that
+you can leverage the full power of Python in almost every aspect
+of a Mako template.
+
+Expression Substitution
+=======================
+
+The simplest expression is just a variable substitution. The
+syntax for this is the ``${}`` construct, which is inspired by
+Perl, Genshi, JSP EL, and others:
+
+.. sourcecode:: mako
+
+    this is x: ${x}
+
+Above, the string representation of ``x`` is applied to the
+template's output stream. If you're wondering where ``x`` comes
+from, it's usually from the :class:`.Context` supplied to the
+template's rendering function. If ``x`` was not supplied to the
+template and was not otherwise assigned locally, it evaluates to
+a special value ``UNDEFINED``. More on that later.
+
+The contents within the ``${}`` tag are evaluated by Python
+directly, so full expressions are OK:
+
+.. sourcecode:: mako
+
+    pythagorean theorem:  ${pow(x,2) + pow(y,2)}
+
+The results of the expression are evaluated into a string result
+in all cases before being rendered to the output stream, such as
+the above example where the expression produces a numeric
+result.
+
+Expression Escaping
+===================
+
+Mako includes a number of built-in escaping mechanisms,
+including HTML, URI and XML escaping, as well as a "trim"
+function. These escapes can be added to an expression
+substitution using the ``|`` operator:
+
+.. sourcecode:: mako
+
+    ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``. The ``u`` name indicates URL
+escaping, whereas ``h`` represents HTML escaping, ``x``
+represents XML escaping, and ``trim`` applies a trim function.
+
+Read more about built-in filtering functions, including how to
+make your own filter functions, in :ref:`filtering_toplevel`.
+
+Control Structures
+==================
+
+A control structure refers to all those things that control the
+flow of a program -- conditionals (i.e. ``if``/``else``), loops (like
+``while`` and ``for``), as well as things like ``try``/``except``. In Mako,
+control structures are written using the ``%`` marker followed
+by a regular Python control expression, and are "closed" by
+using another ``%`` marker with the tag "``end<name>``", where
+"``<name>``" is the keyword of the expression:
+
+.. sourcecode:: mako
+
+    % if x==5:
+        this is some output
+    % endif
+
+The ``%`` can appear anywhere on the line as long as no text
+precedes it; indentation is not significant. The full range of
+Python "colon" expressions are allowed here, including
+``if``/``elif``/``else``, ``while``, ``for``, and even ``def``, although
+Mako has a built-in tag for defs which is more full-featured.
+
+.. sourcecode:: mako
+
+    % for a in ['one', 'two', 'three', 'four', 'five']:
+        % if a[0] == 't':
+        its two or three
+        % elif a[0] == 'f':
+        four/five
+        % else:
+        one
+        % endif
+    % endfor
+
+The ``%`` sign can also be "escaped", if you actually want to
+emit a percent sign as the first non whitespace character on a
+line, by escaping it as in ``%%``:
+
+.. sourcecode:: mako
+
+    %% some text
+
+        %% some more text
+
+The Loop Context
+----------------
+
+The **loop context** provides additional information about a loop
+while inside of a ``% for`` structure:
+
+.. sourcecode:: mako
+
+    <ul>
+    % for a in ("one", "two", "three"):
+        <li>Item ${loop.index}: ${a}</li>
+    % endfor
+    </ul>
+
+See :ref:`loop_context` for more information on this feature.
+
+.. versionadded:: 0.7
+
+Comments
+========
+
+Comments come in two varieties. The single line comment uses
+``##`` as the first non-space characters on a line:
+
+.. sourcecode:: mako
+
+    ## this is a comment.
+    ...text ...
+
+A multiline version exists using ``<%doc> ...text... </%doc>``:
+
+.. sourcecode:: mako
+
+    <%doc>
+        these are comments
+        more comments
+    </%doc>
+
+Newline Filters
+===============
+
+The backslash ("``\``") character, placed at the end of any
+line, will consume the newline character before continuing to
+the next line:
+
+.. sourcecode:: mako
+
+    here is a line that goes onto \
+    another line.
+
+The above text evaluates to:
+
+.. sourcecode:: text
+
+    here is a line that goes onto another line.
+
+Python Blocks
+=============
+
+Any arbitrary block of python can be dropped in using the ``<%
+%>`` tags:
+
+.. sourcecode:: mako
+
+    this is a template
+    <%
+        x = db.get_resource('foo')
+        y = [z.element for z in x if x.frobnizzle==5]
+    %>
+    % for elem in y:
+        element: ${elem}
+    % endfor
+
+Within ``<% %>``, you're writing a regular block of Python code.
+While the code can appear with an arbitrary level of preceding
+whitespace, it has to be consistently formatted with itself.
+Mako's compiler will adjust the block of Python to be consistent
+with the surrounding generated Python code.
+
+Module-level Blocks
+===================
+
+A variant on ``<% %>`` is the module-level code block, denoted
+by ``<%! %>``. Code within these tags is executed at the module
+level of the template, and not within the rendering function of
+the template. Therefore, this code does not have access to the
+template's context and is only executed when the template is
+loaded into memory (which can be only once per application, or
+more, depending on the runtime environment). Use the ``<%! %>``
+tags to declare your template's imports, as well as any
+pure-Python functions you might want to declare:
+
+.. sourcecode:: mako
+
+    <%!
+        import mylib
+        import re
+
+        def filter(text):
+            return re.sub(r'^@', '', text)
+    %>
+
+Any number of ``<%! %>`` blocks can be declared anywhere in a
+template; they will be rendered in the resulting module
+in a single contiguous block above all render callables,
+in the order in which they appear in the source template.
+
+Tags
+====
+
+The rest of what Mako offers takes place in the form of tags.
+All tags use the same syntax, which is similar to an XML tag
+except that the first character of the tag name is a ``%``
+character. The tag is closed either by a contained slash
+character, or an explicit closing tag:
+
+.. sourcecode:: mako
+
+    <%include file="foo.txt"/>
+
+    <%def name="foo" buffered="True">
+        this is a def
+    </%def>
+
+All tags have a set of attributes which are defined for each
+tag. Some of these attributes are required. Also, many
+attributes support **evaluation**, meaning you can embed an
+expression (using ``${}``) inside the attribute text:
+
+.. sourcecode:: mako
+
+    <%include file="/foo/bar/${myfile}.txt"/>
+
+Whether or not an attribute accepts runtime evaluation depends
+on the type of tag and how that tag is compiled into the
+template. The best way to find out if you can stick an
+expression in is to try it! The lexer will tell you if it's not
+valid.
+
+Heres a quick summary of all the tags:
+
+``<%page>``
+-----------
+
+This tag defines general characteristics of the template,
+including caching arguments, and optional lists of arguments
+which the template expects when invoked.
+
+.. sourcecode:: mako
+
+    <%page args="x, y, z='default'"/>
+
+Or a page tag that defines caching characteristics:
+
+.. sourcecode:: mako
+
+    <%page cached="True" cache_type="memory"/>
+
+Currently, only one ``<%page>`` tag gets used per template, the
+rest get ignored. While this will be improved in a future
+release, for now make sure you have only one ``<%page>`` tag
+defined in your template, else you may not get the results you
+want. The details of what ``<%page>`` is used for are described
+further in :ref:`namespaces_body` as well as :ref:`caching_toplevel`.
+
+``<%include>``
+--------------
+
+A tag that is familiar from other template languages, ``%include``
+is a regular joe that just accepts a file argument and calls in
+the rendered result of that file:
+
+.. sourcecode:: mako
+
+    <%include file="header.html"/>
+
+        hello world
+
+    <%include file="footer.html"/>
+
+Include also accepts arguments which are available as ``<%page>`` arguments in the receiving template:
+
+.. sourcecode:: mako
+
+    <%include file="toolbar.html" args="current_section='members', username='ed'"/>
+
+``<%def>``
+----------
+
+The ``%def`` tag defines a Python function which contains a set
+of content, that can be called at some other point in the
+template. The basic idea is simple:
+
+.. sourcecode:: mako
+
+    <%def name="myfunc(x)">
+        this is myfunc, x is ${x}
+    </%def>
+
+    ${myfunc(7)}
+
+The ``%def`` tag is a lot more powerful than a plain Python ``def``, as
+the Mako compiler provides many extra services with ``%def`` that
+you wouldn't normally have, such as the ability to export defs
+as template "methods", automatic propagation of the current
+:class:`.Context`, buffering/filtering/caching flags, and def calls
+with content, which enable packages of defs to be sent as
+arguments to other def calls (not as hard as it sounds). Get the
+full deal on what ``%def`` can do in :ref:`defs_toplevel`.
+
+``<%block>``
+------------
+
+``%block`` is a tag that is close to a ``%def``,
+except executes itself immediately in its base-most scope,
+and can also be anonymous (i.e. with no name):
+
+.. sourcecode:: mako
+
+    <%block filter="h">
+        some <html> stuff.
+    </%block>
+
+Inspired by Jinja2 blocks, named blocks offer a syntactically pleasing way
+to do inheritance:
+
+.. sourcecode:: mako
+
+    <html>
+        <body>
+        <%block name="header">
+            <h2><%block name="title"/></h2>
+        </%block>
+        ${self.body()}
+        </body>
+    </html>
+
+Blocks are introduced in :ref:`blocks` and further described in :ref:`inheritance_toplevel`.
+
+.. versionadded:: 0.4.1
+
+``<%namespace>``
+----------------
+
+``%namespace`` is Mako's equivalent of Python's ``import``
+statement. It allows access to all the rendering functions and
+metadata of other template files, plain Python modules, as well
+as locally defined "packages" of functions.
+
+.. sourcecode:: mako
+
+    <%namespace file="functions.html" import="*"/>
+
+The underlying object generated by ``%namespace``, an instance of
+:class:`.mako.runtime.Namespace`, is a central construct used in
+templates to reference template-specific information such as the
+current URI, inheritance structures, and other things that are
+not as hard as they sound right here. Namespaces are described
+in :ref:`namespaces_toplevel`.
+
+``<%inherit>``
+--------------
+
+Inherit allows templates to arrange themselves in **inheritance
+chains**. This is a concept familiar in many other template
+languages.
+
+.. sourcecode:: mako
+
+    <%inherit file="base.html"/>
+
+When using the ``%inherit`` tag, control is passed to the topmost
+inherited template first, which then decides how to handle
+calling areas of content from its inheriting templates. Mako
+offers a lot of flexibility in this area, including dynamic
+inheritance, content wrapping, and polymorphic method calls.
+Check it out in :ref:`inheritance_toplevel`.
+
+``<%``\ nsname\ ``:``\ defname\ ``>``
+-------------------------------------
+
+Any user-defined "tag" can be created against
+a namespace by using a tag with a name of the form
+``<%<namespacename>:<defname>>``. The closed and open formats of such a
+tag are equivalent to an inline expression and the ``<%call>``
+tag, respectively.
+
+.. sourcecode:: mako
+
+    <%mynamespace:somedef param="some value">
+        this is the body
+    </%mynamespace:somedef>
+
+To create custom tags which accept a body, see
+:ref:`defs_with_content`.
+
+.. versionadded:: 0.2.3
+
+``<%call>``
+-----------
+
+The call tag is the "classic" form of a user-defined tag, and is
+roughly equivalent to the ``<%namespacename:defname>`` syntax
+described above. This tag is also described in :ref:`defs_with_content`.
+
+``<%doc>``
+----------
+
+The ``%doc`` tag handles multiline comments:
+
+.. sourcecode:: mako
+
+    <%doc>
+        these are comments
+        more comments
+    </%doc>
+
+Also the ``##`` symbol as the first non-space characters on a line can be used for single line comments.
+
+``<%text>``
+-----------
+
+This tag suspends the Mako lexer's normal parsing of Mako
+template directives, and returns its entire body contents as
+plain text. It is used pretty much to write documentation about
+Mako:
+
+.. sourcecode:: mako
+
+    <%text filter="h">
+        heres some fake mako ${syntax}
+        <%def name="x()">${x}</%def>
+    </%text>
+
+.. _syntax_exiting_early:
+
+Exiting Early from a Template
+=============================
+
+Sometimes you want to stop processing a template or ``<%def>``
+method in the middle and just use the text you've accumulated so
+far.  This is accomplished by using ``return`` statement inside
+a Python block.   It's a good idea for the ``return`` statement
+to return an empty string, which prevents the Python default return
+value of ``None`` from being rendered by the template.  This
+return value is for semantic purposes provided in templates via
+the ``STOP_RENDERING`` symbol:
+
+.. sourcecode:: mako
+
+    % if not len(records):
+        No records found.
+        <% return STOP_RENDERING %>
+    % endif
+
+Or perhaps:
+
+.. sourcecode:: mako
+
+    <%
+        if not len(records):
+            return STOP_RENDERING
+    %>
+
+In older versions of Mako, an empty string can be substituted for
+the ``STOP_RENDERING`` symbol:
+
+.. sourcecode:: mako
+
+    <% return '' %>
+
+.. versionadded:: 1.0.2 - added the ``STOP_RENDERING`` symbol which serves
+   as a semantic identifier for the empty string ``""`` used by a
+   Python ``return`` statement.
+
diff --git a/doc/build/templates/base.mako b/doc/build/templates/base.mako
new file mode 100644 (file)
index 0000000..b23be0f
--- /dev/null
@@ -0,0 +1,56 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title><%block name="head_title">Mako Templates for Python</%block></title>
+
+<!-- begin iterate through sphinx environment css_files -->
+% for cssfile in self.attr.default_css_files + css_files:
+    <link rel="stylesheet" href="${pathto(cssfile, 1)}" type="text/css" />
+% endfor
+<!-- end iterate through sphinx environment css_files -->
+
+<%block name="headers">
+</%block>
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+    % if toolbar:
+    <div class="toolbar">
+    <a href="${site_base}/">Home</a>
+    &nbsp; | &nbsp;
+    <a href="${site_base}/community.html">Community</a>
+    &nbsp; | &nbsp;
+    <a href="${pathto('index')}">Documentation</a>
+    &nbsp; | &nbsp;
+    <a href="${site_base}/download.html">Download</a>
+    </div>
+    % endif
+
+    </div>
+
+    <a href="${site_base}/"><img src="${pathto('_static/makoLogo.png', 1)}" /></a>
+
+    <hr/>
+
+    ${next.body()}
+<div class="clearfix">
+<%block name="footer">
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+</%block>
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/build/templates/genindex.mako b/doc/build/templates/genindex.mako
new file mode 100644 (file)
index 0000000..2f45f79
--- /dev/null
@@ -0,0 +1,77 @@
+<%inherit file="${context['layout']}"/>
+
+<%block name="show_title" filter="util.striptags">
+    ${_('Index')}
+</%block>
+
+   <h1 id="index">${_('Index')}</h1>
+
+   % for i, (key, dummy) in enumerate(genindexentries):
+    ${i != 0 and '| ' or ''}<a href="#${key}"><strong>${key}</strong></a>
+   % endfor
+
+   <hr />
+
+   % for i, (key, entries) in enumerate(genindexentries):
+<h2 id="${key}">${key}</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    <%
+        breakat = genindexcounts[i] // 2
+        numcols = 1
+        numitems = 0
+    %>
+% for entryname, (links, subitems, dummy) in entries:
+
+<dt>
+    % if links:
+        <a href="${links[0][1]}">${entryname|h}</a>
+        % for unknown, link in links[1:]:
+            , <a href="${link}">[${i}]</a>
+        % endfor
+    % else:
+        ${entryname|h}
+    % endif
+</dt>
+
+    % if subitems:
+    <dd><dl>
+      % for subentryname, subentrylinks in subitems:
+      <dt><a href="${subentrylinks[0][1]}">${subentryname|h}</a>
+              % for j, (unknown, link) in enumerate(subentrylinks[1:]):
+                  <a href="${link}">[${j}]</a>
+              % endfor
+      </dt>
+      % endfor
+    </dl></dd>
+    % endif
+
+  <%
+    numitems = numitems + 1 + len(subitems)
+  %>
+  % if numcols <2 and numitems > breakat:
+     <%
+        numcols = numcols + 1
+     %>
+        </dl></td><td width="33%" valign="top"><dl>
+  % endif
+
+% endfor
+<dt></dt></dl>
+</td></tr></table>
+% endfor
+
+<%def name="sidebarrel()">
+% if split_index:
+   <h4>${_('Index')}</h4>
+   <p>
+   % for i, (key, dummy) in enumerate(genindexentries):
+       ${i > 0 and '| ' or ''}
+       <a href="${pathto('genindex-' + key)}"><strong>${key}</strong></a>
+   % endfor
+   </p>
+
+   <p><a href="${pathto('genindex-all')}"><strong>${_('Full index on one page')}</strong></a></p>
+% endif
+   ${parent.sidebarrel()}
+</%def>
diff --git a/doc/build/templates/layout.mako b/doc/build/templates/layout.mako
new file mode 100644 (file)
index 0000000..486367c
--- /dev/null
@@ -0,0 +1,205 @@
+## coding: utf-8
+<%!
+    local_script_files = []
+
+    default_css_files = [
+        '_static/pygments.css',
+        '_static/docs.css',
+        '_static/site.css'
+    ]
+%>
+
+<%doc>
+    Structural elements are all prefixed with "docs-"
+    to prevent conflicts when the structure is integrated into the
+    main site.
+
+    docs-container ->
+        docs-header ->
+            docs-search
+            docs-version-header
+        docs-top-navigation
+            docs-top-page-control
+            docs-navigation-banner
+        docs-body-container ->
+            docs-sidebar
+            docs-body
+        docs-bottom-navigation
+            docs-copyright
+</%doc>
+
+<%inherit file="base.mako"/>
+
+<%
+withsidebar = bool(toc) and current_page_name != 'index'
+%>
+
+<%block name="head_title">
+    % if current_page_name != 'index':
+    ${capture(self.show_title) | util.striptags} &mdash;
+    % endif
+    ${docstitle|h}
+</%block>
+
+
+<div id="docs-container">
+
+<%block name="headers">
+    ${parent.headers()}
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    '${pathto("", 1)}',
+          VERSION:     '${release|h}',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '${file_suffix}'
+      };
+    </script>
+    % for scriptfile in script_files + self.attr.local_script_files:
+        <script type="text/javascript" src="${pathto(scriptfile, 1)}"></script>
+    % endfor
+    % if hasdoc('about'):
+        <link rel="author" title="${_('About these documents')}" href="${pathto('about')}" />
+    % endif
+    <link rel="index" title="${_('Index')}" href="${pathto('genindex')}" />
+    <link rel="search" title="${_('Search')}" href="${pathto('search')}" />
+    % if hasdoc('copyright'):
+        <link rel="copyright" title="${_('Copyright')}" href="${pathto('copyright')}" />
+    % endif
+    <link rel="top" title="${docstitle|h}" href="${pathto('index')}" />
+    % if parents:
+        <link rel="up" title="${parents[-1]['title']|util.striptags}" href="${parents[-1]['link']|h}" />
+    % endif
+    % if nexttopic:
+        <link rel="next" title="${nexttopic['title']|util.striptags}" href="${nexttopic['link']|h}" />
+    % endif
+    % if prevtopic:
+        <link rel="prev" title="${prevtopic['title']|util.striptags}" href="${prevtopic['link']|h}" />
+    % endif
+</%block>
+
+<div id="docs-header">
+    <h1>${docstitle|h}</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="${pathto('search')}" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="${_('Search')}" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">${release}</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+        % if prevtopic:
+            <li>Prev:
+            <a href="${prevtopic['link']|h}" title="${_('previous chapter')}">${prevtopic['title']}</a>
+            </li>
+        % endif
+        % if nexttopic:
+            <li>Next:
+            <a href="${nexttopic['link']|h}" title="${_('next chapter')}">${nexttopic['title']}</a>
+            </li>
+        % endif
+
+        <li>
+            <a href="${pathto('index')}">Table of Contents</a> |
+            <a href="${pathto('genindex')}">Index</a>
+            % if sourcename:
+            | <a href="${pathto('_sources/' + sourcename, True)|h}">${_('view source')}
+            % endif
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="${pathto('index')}">${docstitle|h}</a>
+        % if parents:
+            % for parent in parents:
+                » <a href="${parent['link']|h}" title="${parent['title']}">${parent['title']}</a>
+            % endfor
+        % endif
+        % if current_page_name != 'index':
+        » ${self.show_title()}
+        % endif
+
+        <h2>
+            <%block name="show_title">
+                ${title}
+            </%block>
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+% if withsidebar:
+    <div id="docs-sidebar">
+    <h3><a href="${pathto('index')}">Table of Contents</a></h3>
+    ${toc}
+
+    % if prevtopic:
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="${prevtopic['link']|h}" title="${_('previous chapter')}">${prevtopic['title']}</a>
+    </p>
+    % endif
+    % if nexttopic:
+    <h4>Next Topic</h4>
+    <p>
+    <a href="${nexttopic['link']|h}" title="${_('next chapter')}">${nexttopic['title']}</a>
+    </p>
+    % endif
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="${pathto('search')}" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="${_('Search')}" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+% endif
+
+    <div id="docs-body" class="${'withsidebar' if withsidebar else ''}" >
+        ${next.body()}
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+    % if prevtopic:
+        Previous:
+        <a href="${prevtopic['link']|h}" title="${_('previous chapter')}">${prevtopic['title']}</a>
+    % endif
+    % if nexttopic:
+        Next:
+        <a href="${nexttopic['link']|h}" title="${_('next chapter')}">${nexttopic['title']}</a>
+    % endif
+
+    <div id="docs-copyright">
+    % if hasdoc('copyright'):
+        &copy; <a href="${pathto('copyright')}">Copyright</a> ${copyright|h}.
+    % else:
+        &copy; Copyright ${copyright|h}.
+    % endif
+    % if show_sphinx:
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> ${sphinx_version|h}
+        with Mako templates.
+    % endif
+    </div>
+</div>
+
+</div>
diff --git a/doc/build/templates/page.mako b/doc/build/templates/page.mako
new file mode 100644 (file)
index 0000000..61cf9a0
--- /dev/null
@@ -0,0 +1,2 @@
+<%inherit file="${context['layout']}"/>
+${body| util.strip_toplevel_anchors}
\ No newline at end of file
diff --git a/doc/build/templates/rtd_layout.mako b/doc/build/templates/rtd_layout.mako
new file mode 100644 (file)
index 0000000..3fafd53
--- /dev/null
@@ -0,0 +1,37 @@
+<!-- readthedocs add-in template -->
+
+<%inherit file="/layout.mako"/>
+
+
+<%block name="headers">
+
+<link href='http://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700' rel='stylesheet' type='text/css'>
+
+<!-- RTD <head> via mako adapter -->
+<script type="text/javascript">
+    var doc_version = "${current_version}";
+    var doc_slug = "${slug}";
+    var static_root = "${pathto('_static', 1)}"
+
+    // copied from:
+    // https://github.com/rtfd/readthedocs.org/commit/edbbb4c753454cf20c128d4eb2fef60d740debaa#diff-2f70e8d9361202bfe3f378d2ff2c510bR8
+    var READTHEDOCS_DATA = {
+        project: "${slug}",
+        version: "${current_version}",
+        page: "${pagename}",
+        theme: "${html_theme or ''}"
+      };
+
+</script>
+<!-- end RTD <head> via mako adapter -->
+
+    ${parent.headers()}
+
+</%block>
+
+
+${next.body()}
+
+<%block name="footer">
+    ${parent.footer()}
+</%block>
diff --git a/doc/build/templates/search.mako b/doc/build/templates/search.mako
new file mode 100644 (file)
index 0000000..0eaa8f9
--- /dev/null
@@ -0,0 +1,25 @@
+<%inherit file="${context['layout']}"/>
+
+<%!
+    local_script_files = ['_static/searchtools.js']
+%>
+
+<%block name="show_title" filter="util.striptags">
+    ${_('Search')}
+</%block>
+
+<div id="searchform">
+<h3>Enter Search Terms:</h3>
+<form class="search" action="${pathto('search')}" method="get">
+  <input type="text" name="q" size="18" /> <input type="submit" value="${_('Search')}" />
+  <input type="hidden" name="check_keywords" value="yes" />
+  <input type="hidden" name="area" value="default" />
+</form>
+</div>
+
+<div id="search-results"></div>
+
+<%block name="footer">
+    ${parent.footer()}
+    <script type="text/javascript" src="searchindex.js"></script>
+</%block>
diff --git a/doc/build/unicode.rst b/doc/build/unicode.rst
new file mode 100644 (file)
index 0000000..1ba364e
--- /dev/null
@@ -0,0 +1,345 @@
+.. _unicode_toplevel:
+
+===================
+The Unicode Chapter
+===================
+
+The Python language supports two ways of representing what we
+know as "strings", i.e. series of characters. In Python 2, the
+two types are ``string`` and ``unicode``, and in Python 3 they are
+``bytes`` and ``string``. A key aspect of the Python 2 ``string`` and
+Python 3 ``bytes`` types are that they contain no information
+regarding what **encoding** the data is stored in. For this
+reason they were commonly referred to as **byte strings** on
+Python 2, and Python 3 makes this name more explicit. The
+origins of this come from Python's background of being developed
+before the Unicode standard was even available, back when
+strings were C-style strings and were just that, a series of
+bytes. Strings that had only values below 128 just happened to
+be **ASCII** strings and were printable on the console, whereas
+strings with values above 128 would produce all kinds of
+graphical characters and bells.
+
+Contrast the "byte-string" type with the "unicode/string" type.
+Objects of this latter type are created whenever you say something like
+``u"hello world"`` (or in Python 3, just ``"hello world"``). In this
+case, Python represents each character in the string internally
+using multiple bytes per character (something similar to
+UTF-16). What's important is that when using the
+``unicode``/``string`` type to store strings, Python knows the
+data's encoding; it's in its own internal format. Whereas when
+using the ``string``/``bytes`` type, it does not.
+
+When Python 2 attempts to treat a byte-string as a string, which
+means it's attempting to compare/parse its characters, to coerce
+it into another encoding, or to decode it to a unicode object,
+it has to guess what the encoding is. In this case, it will
+pretty much always guess the encoding as ``ascii``... and if the
+byte-string contains bytes above value 128, you'll get an error.
+Python 3 eliminates much of this confusion by just raising an
+error unconditionally if a byte-string is used in a
+character-aware context.
+
+There is one operation that Python *can* do with a non-ASCII
+byte-string, and it's a great source of confusion: it can dump the
+byte-string straight out to a stream or a file, with nary a care
+what the encoding is. To Python, this is pretty much like
+dumping any other kind of binary data (like an image) to a
+stream somewhere. In Python 2, it is common to see programs that
+embed all kinds of international characters and encodings into
+plain byte-strings (i.e. using ``"hello world"`` style literals)
+can fly right through their run, sending reams of strings out to
+wherever they are going, and the programmer, seeing the same
+output as was expressed in the input, is now under the illusion
+that his or her program is Unicode-compliant. In fact, their
+program has no unicode awareness whatsoever, and similarly has
+no ability to interact with libraries that *are* unicode aware.
+Python 3 makes this much less likely by defaulting to unicode as
+the storage format for strings.
+
+The "pass through encoded data" scheme is what template
+languages like Cheetah and earlier versions of Myghty do by
+default. Mako as of version 0.2 also supports this mode of
+operation when using Python 2, using the ``disable_unicode=True``
+flag. However, when using Mako in its default mode of
+unicode-aware, it requires explicitness when dealing with
+non-ASCII encodings. Additionally, if you ever need to handle
+unicode strings and other kinds of encoding conversions more
+intelligently, the usage of raw byte-strings quickly becomes a
+nightmare, since you are sending the Python interpreter
+collections of bytes for which it can make no intelligent
+decisions with regards to encoding. In Python 3 Mako only allows
+usage of native, unicode strings.
+
+In normal Mako operation, all parsed template constructs and
+output streams are handled internally as Python ``unicode``
+objects. It's only at the point of :meth:`~.Template.render` that this unicode
+stream may be rendered into whatever the desired output encoding
+is. The implication here is that the template developer must
+:ensure that :ref:`the encoding of all non-ASCII templates is explicit
+<set_template_file_encoding>` (still required in Python 3),
+that :ref:`all non-ASCII-encoded expressions are in one way or another
+converted to unicode <handling_non_ascii_expressions>`
+(not much of a burden in Python 3), and that :ref:`the output stream of the
+template is handled as a unicode stream being encoded to some
+encoding <defining_output_encoding>` (still required in Python 3).
+
+.. _set_template_file_encoding:
+
+Specifying the Encoding of a Template File
+==========================================
+
+This is the most basic encoding-related setting, and it is
+equivalent to Python's "magic encoding comment", as described in
+`pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_. Any
+template that contains non-ASCII characters requires that this
+comment be present so that Mako can decode to unicode (and also
+make usage of Python's AST parsing services). Mako's lexer will
+use this encoding in order to convert the template source into a
+``unicode`` object before continuing its parsing:
+
+.. sourcecode:: mako
+
+    ## -*- coding: utf-8 -*-
+
+    Alors vous imaginez ma surprise, au lever du jour, quand 
+    une drôle de petite voix m’a réveillé. Elle disait:
+     « S’il vous plaît… dessine-moi un mouton! »
+
+For the picky, the regular expression used is derived from that
+of the above mentioned pep:
+
+.. sourcecode:: python
+
+    #.*coding[:=]\s*([-\w.]+).*\n
+
+The lexer will convert to unicode in all cases, so that if any
+characters exist in the template that are outside of the
+specified encoding (or the default of ``ascii``), the error will
+be immediate.
+
+As an alternative, the template encoding can be specified
+programmatically to either :class:`.Template` or :class:`.TemplateLookup` via
+the ``input_encoding`` parameter:
+
+.. sourcecode:: python
+
+    t = TemplateLookup(directories=['./'], input_encoding='utf-8')
+
+The above will assume all located templates specify ``utf-8``
+encoding, unless the template itself contains its own magic
+encoding comment, which takes precedence.
+
+.. _handling_non_ascii_expressions:
+
+Handling Expressions
+====================
+
+The next area that encoding comes into play is in expression
+constructs. By default, Mako's treatment of an expression like
+this:
+
+.. sourcecode:: mako
+
+    ${"hello world"}
+
+looks something like this:
+
+.. sourcecode:: python
+
+    context.write(unicode("hello world"))
+
+In Python 3, it's just:
+
+.. sourcecode:: python
+
+    context.write(str("hello world"))
+
+That is, **the output of all expressions is run through the
+``unicode`` built-in**. This is the default setting, and can be
+modified to expect various encodings. The ``unicode`` step serves
+both the purpose of rendering non-string expressions into
+strings (such as integers or objects which contain ``__str()__``
+methods), and to ensure that the final output stream is
+constructed as a unicode object. The main implication of this is
+that **any raw byte-strings that contain an encoding other than
+ASCII must first be decoded to a Python unicode object**. It
+means you can't say this in Python 2:
+
+.. sourcecode:: mako
+
+    ${"voix m’a réveillé."}  ## error in Python 2!
+
+You must instead say this:
+
+.. sourcecode:: mako
+
+    ${u"voix m’a réveillé."}  ## OK !
+
+Similarly, if you are reading data from a file that is streaming
+bytes, or returning data from some object that is returning a
+Python byte-string containing a non-ASCII encoding, you have to
+explicitly decode to unicode first, such as:
+
+.. sourcecode:: mako
+
+    ${call_my_object().decode('utf-8')}
+
+Note that filehandles acquired by ``open()`` in Python 3 default
+to returning "text", that is the decoding is done for you. See
+Python 3's documentation for the ``open()`` built-in for details on
+this.
+
+If you want a certain encoding applied to *all* expressions,
+override the ``unicode`` builtin with the ``decode`` built-in at the
+:class:`.Template` or :class:`.TemplateLookup` level:
+
+.. sourcecode:: python
+
+    t = Template(templatetext, default_filters=['decode.utf8'])
+
+Note that the built-in ``decode`` object is slower than the
+``unicode`` function, since unlike ``unicode`` it's not a Python
+built-in, and it also checks the type of the incoming data to
+determine if string conversion is needed first.
+
+The ``default_filters`` argument can be used to entirely customize
+the filtering process of expressions. This argument is described
+in :ref:`filtering_default_filters`.
+
+.. _defining_output_encoding:
+
+Defining Output Encoding
+========================
+
+Now that we have a template which produces a pure unicode output
+stream, all the hard work is done. We can take the output and do
+anything with it.
+
+As stated in the :doc:`"Usage" chapter <usage>`, both :class:`.Template` and
+:class:`.TemplateLookup` accept ``output_encoding`` and ``encoding_errors``
+parameters which can be used to encode the output in any Python
+supported codec:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
+
+    mytemplate = mylookup.get_template("foo.txt")
+    print(mytemplate.render())
+
+:meth:`~.Template.render` will return a ``bytes`` object in Python 3 if an output
+encoding is specified. By default it performs no encoding and
+returns a native string.
+
+:meth:`~.Template.render_unicode` will return the template output as a Python
+``unicode`` object (or ``string`` in Python 3):
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode())
+
+The above method disgards the output encoding keyword argument;
+you can encode yourself by saying:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode().encode('utf-8', 'replace'))
+
+Buffer Selection
+----------------
+
+Mako does play some games with the style of buffering used
+internally, to maximize performance. Since the buffer is by far
+the most heavily used object in a render operation, it's
+important!
+
+When calling :meth:`~.Template.render` on a template that does not specify any
+output encoding (i.e. it's ``ascii``), Python's ``cStringIO`` module,
+which cannot handle encoding of non-ASCII ``unicode`` objects
+(even though it can send raw byte-strings through), is used for
+buffering. Otherwise, a custom Mako class called
+``FastEncodingBuffer`` is used, which essentially is a super
+dumbed-down version of ``StringIO`` that gathers all strings into
+a list and uses ``u''.join(elements)`` to produce the final output
+-- it's markedly faster than ``StringIO``.
+
+.. _unicode_disabled:
+
+Saying to Heck with It: Disabling the Usage of Unicode Entirely
+===============================================================
+
+Some segments of Mako's userbase choose to make no usage of
+Unicode whatsoever, and instead would prefer the "pass through"
+approach; all string expressions in their templates return
+encoded byte-strings, and they would like these strings to pass
+right through. The only advantage to this approach is that
+templates need not use ``u""`` for literal strings; there's an
+arguable speed improvement as well since raw byte-strings
+generally perform slightly faster than unicode objects in
+Python. For these users, assuming they're sticking with Python
+2, they can hit the ``disable_unicode=True`` flag as so:
+
+.. sourcecode:: python
+
+    # -*- coding:utf-8 -*-
+    from mako.template import Template
+
+    t = Template("drôle de petite voix m’a réveillé.", disable_unicode=True, input_encoding='utf-8')
+    print(t.code)
+
+The ``disable_unicode`` mode is strictly a Python 2 thing. It is
+not supported at all in Python 3.
+
+The generated module source code will contain elements like
+these:
+
+.. sourcecode:: python
+
+    # -*- coding:utf-8 -*-
+    #  ...more generated code ...
+
+    def render_body(context,**pageargs):
+        context.caller_stack.push_frame()
+        try:
+            __M_locals = dict(pageargs=pageargs)
+            # SOURCE LINE 1
+            context.write('dr\xc3\xb4le de petite voix m\xe2\x80\x99a r\xc3\xa9veill\xc3\xa9.')
+            return ''
+        finally:
+            context.caller_stack.pop_frame()
+
+Where above that the string literal used within :meth:`.Context.write`
+is a regular byte-string.
+
+When ``disable_unicode=True`` is turned on, the ``default_filters``
+argument which normally defaults to ``["unicode"]`` now defaults
+to ``["str"]`` instead. Setting ``default_filters`` to the empty list
+``[]`` can remove the overhead of the ``str`` call. Also, in this
+mode you **cannot** safely call :meth:`~.Template.render_unicode` -- you'll get
+unicode/decode errors.
+
+The ``h`` filter (HTML escape) uses a less performant pure Python
+escape function in non-unicode mode. This because
+MarkupSafe only supports Python unicode objects for non-ASCII
+strings.
+
+.. versionchanged:: 0.3.4
+   In prior versions, it used ``cgi.escape()``, which has been replaced
+   with a function that also escapes single quotes.
+
+Rules for using ``disable_unicode=True``
+----------------------------------------
+
+* Don't use this mode unless you really, really want to and you
+  absolutely understand what you're doing.
+* Don't use this option just because you don't want to learn to
+  use Unicode properly; we aren't supporting user issues in this
+  mode of operation. We will however offer generous help for the
+  vast majority of users who stick to the Unicode program.
+* Python 3 is unicode by default, and the flag is not available
+  when running on Python 3.
+
diff --git a/doc/build/usage.rst b/doc/build/usage.rst
new file mode 100644 (file)
index 0000000..ceb8d41
--- /dev/null
@@ -0,0 +1,520 @@
+.. _usage_toplevel:
+
+=====
+Usage
+=====
+
+Basic Usage
+===========
+
+This section describes the Python API for Mako templates. If you
+are using Mako within a web framework such as Pylons, the work
+of integrating Mako's API is already done for you, in which case
+you can skip to the next section, :ref:`syntax_toplevel`.
+
+The most basic way to create a template and render it is through
+the :class:`.Template` class:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template("hello world!")
+    print(mytemplate.render())
+
+Above, the text argument to :class:`.Template` is **compiled** into a
+Python module representation. This module contains a function
+called ``render_body()``, which produces the output of the
+template. When ``mytemplate.render()`` is called, Mako sets up a
+runtime environment for the template and calls the
+``render_body()`` function, capturing the output into a buffer and
+returning its string contents.
+
+
+The code inside the ``render_body()`` function has access to a
+namespace of variables. You can specify these variables by
+sending them as additional keyword arguments to the :meth:`~.Template.render`
+method:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template("hello, ${name}!")
+    print(mytemplate.render(name="jack"))
+
+The :meth:`~.Template.render` method calls upon Mako to create a
+:class:`.Context` object, which stores all the variable names accessible
+to the template and also stores a buffer used to capture output.
+You can create this :class:`.Context` yourself and have the template
+render with it, using the :meth:`~.Template.render_context` method:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.runtime import Context
+    from StringIO import StringIO
+
+    mytemplate = Template("hello, ${name}!")
+    buf = StringIO()
+    ctx = Context(buf, name="jack")
+    mytemplate.render_context(ctx)
+    print(buf.getvalue())
+
+Using File-Based Templates
+==========================
+
+A :class:`.Template` can also load its template source code from a file,
+using the ``filename`` keyword argument:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template(filename='/docs/mytmpl.txt')
+    print(mytemplate.render())
+
+For improved performance, a :class:`.Template` which is loaded from a
+file can also cache the source code to its generated module on
+the filesystem as a regular Python module file (i.e. a ``.py``
+file). To do this, just add the ``module_directory`` argument to
+the template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+
+    mytemplate = Template(filename='/docs/mytmpl.txt', module_directory='/tmp/mako_modules')
+    print(mytemplate.render())
+
+When the above code is rendered, a file
+``/tmp/mako_modules/docs/mytmpl.txt.py`` is created containing the
+source code for the module. The next time a :class:`.Template` with the
+same arguments is created, this module file will be
+automatically re-used.
+
+.. _usage_templatelookup:
+
+Using ``TemplateLookup``
+========================
+
+All of the examples thus far have dealt with the usage of a
+single :class:`.Template` object. If the code within those templates
+tries to locate another template resource, it will need some way
+to find them, using simple URI strings. For this need, the
+resolution of other templates from within a template is
+accomplished by the :class:`.TemplateLookup` class. This class is
+constructed given a list of directories in which to search for
+templates, as well as keyword arguments that will be passed to
+the :class:`.Template` objects it creates:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'])
+    mytemplate = Template("""<%include file="header.txt"/> hello world!""", lookup=mylookup)
+
+Above, we created a textual template which includes the file
+``"header.txt"``. In order for it to have somewhere to look for
+``"header.txt"``, we passed a :class:`.TemplateLookup` object to it, which
+will search in the directory ``/docs`` for the file ``"header.txt"``.
+
+Usually, an application will store most or all of its templates
+as text files on the filesystem. So far, all of our examples
+have been a little bit contrived in order to illustrate the
+basic concepts. But a real application would get most or all of
+its templates directly from the :class:`.TemplateLookup`, using the
+aptly named :meth:`~.TemplateLookup.get_template` method, which accepts the URI of the
+desired template:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], module_directory='/tmp/mako_modules')
+
+    def serve_template(templatename, **kwargs):
+        mytemplate = mylookup.get_template(templatename)
+        print(mytemplate.render(**kwargs))
+
+In the example above, we create a :class:`.TemplateLookup` which will
+look for templates in the ``/docs`` directory, and will store
+generated module files in the ``/tmp/mako_modules`` directory. The
+lookup locates templates by appending the given URI to each of
+its search directories; so if you gave it a URI of
+``/etc/beans/info.txt``, it would search for the file
+``/docs/etc/beans/info.txt``, else raise a :class:`.TopLevelNotFound`
+exception, which is a custom Mako exception.
+
+When the lookup locates templates, it will also assign a ``uri``
+property to the :class:`.Template` which is the URI passed to the
+:meth:`~.TemplateLookup.get_template()` call. :class:`.Template` uses this URI to calculate the
+name of its module file. So in the above example, a
+``templatename`` argument of ``/etc/beans/info.txt`` will create a
+module file ``/tmp/mako_modules/etc/beans/info.txt.py``.
+
+Setting the Collection Size
+---------------------------
+
+The :class:`.TemplateLookup` also serves the important need of caching a
+fixed set of templates in memory at a given time, so that
+successive URI lookups do not result in full template
+compilations and/or module reloads on each request. By default,
+the :class:`.TemplateLookup` size is unbounded. You can specify a fixed
+size using the ``collection_size`` argument:
+
+.. sourcecode:: python
+
+    mylookup = TemplateLookup(directories=['/docs'],
+                    module_directory='/tmp/mako_modules', collection_size=500)
+
+The above lookup will continue to load templates into memory
+until it reaches a count of around 500. At that point, it will
+clean out a certain percentage of templates using a least
+recently used scheme.
+
+Setting Filesystem Checks
+-------------------------
+
+Another important flag on :class:`.TemplateLookup` is
+``filesystem_checks``. This defaults to ``True``, and says that each
+time a template is returned by the :meth:`~.TemplateLookup.get_template()` method, the
+revision time of the original template file is checked against
+the last time the template was loaded, and if the file is newer
+will reload its contents and recompile the template. On a
+production system, setting ``filesystem_checks`` to ``False`` can
+afford a small to moderate performance increase (depending on
+the type of filesystem used).
+
+.. _usage_unicode:
+
+Using Unicode and Encoding
+==========================
+
+Both :class:`.Template` and :class:`.TemplateLookup` accept ``output_encoding``
+and ``encoding_errors`` parameters which can be used to encode the
+output in any Python supported codec:
+
+.. sourcecode:: python
+
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+
+    mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
+
+    mytemplate = mylookup.get_template("foo.txt")
+    print(mytemplate.render())
+
+When using Python 3, the :meth:`~.Template.render` method will return a ``bytes``
+object, **if** ``output_encoding`` is set. Otherwise it returns a
+``string``.
+
+Additionally, the :meth:`~.Template.render_unicode()` method exists which will
+return the template output as a Python ``unicode`` object, or in
+Python 3 a ``string``:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode())
+
+The above method disregards the output encoding keyword
+argument; you can encode yourself by saying:
+
+.. sourcecode:: python
+
+    print(mytemplate.render_unicode().encode('utf-8', 'replace'))
+
+Note that Mako's ability to return data in any encoding and/or
+``unicode`` implies that the underlying output stream of the
+template is a Python unicode object. This behavior is described
+fully in :ref:`unicode_toplevel`.
+
+.. _handling_exceptions:
+
+Handling Exceptions
+===================
+
+Template exceptions can occur in two distinct places. One is
+when you **lookup, parse and compile** the template, the other
+is when you **run** the template. Within the running of a
+template, exceptions are thrown normally from whatever Python
+code originated the issue. Mako has its own set of exception
+classes which mostly apply to the lookup and lexer/compiler
+stages of template construction. Mako provides some library
+routines that can be used to help provide Mako-specific
+information about any exception's stack trace, as well as
+formatting the exception within textual or HTML format. In all
+cases, the main value of these handlers is that of converting
+Python filenames, line numbers, and code samples into Mako
+template filenames, line numbers, and code samples. All lines
+within a stack trace which correspond to a Mako template module
+will be converted to be against the originating template file.
+
+To format exception traces, the :func:`.text_error_template` and
+:func:`.html_error_template` functions are provided. They make usage of
+``sys.exc_info()`` to get at the most recently thrown exception.
+Usage of these handlers usually looks like:
+
+.. sourcecode:: python
+
+    from mako import exceptions
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        print(exceptions.text_error_template().render())
+
+Or for the HTML render function:
+
+.. sourcecode:: python
+
+    from mako import exceptions
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        print(exceptions.html_error_template().render())
+
+The :func:`.html_error_template` template accepts two options:
+specifying ``full=False`` causes only a section of an HTML
+document to be rendered. Specifying ``css=False`` will disable the
+default stylesheet from being rendered.
+
+E.g.:
+
+.. sourcecode:: python
+
+    print(exceptions.html_error_template().render(full=False))
+
+The HTML render function is also available built-in to
+:class:`.Template` using the ``format_exceptions`` flag. In this case, any
+exceptions raised within the **render** stage of the template
+will result in the output being substituted with the output of
+:func:`.html_error_template`:
+
+.. sourcecode:: python
+
+    template = Template(filename="/foo/bar", format_exceptions=True)
+    print(template.render())
+
+Note that the compile stage of the above template occurs when
+you construct the :class:`.Template` itself, and no output stream is
+defined. Therefore exceptions which occur within the
+lookup/parse/compile stage will not be handled and will
+propagate normally. While the pre-render traceback usually will
+not include any Mako-specific lines anyway, it will mean that
+exceptions which occur previous to rendering and those which
+occur within rendering will be handled differently... so the
+``try``/``except`` patterns described previously are probably of more
+general use.
+
+The underlying object used by the error template functions is
+the :class:`.RichTraceback` object. This object can also be used
+directly to provide custom error views. Here's an example usage
+which describes its general API:
+
+.. sourcecode:: python
+
+    from mako.exceptions import RichTraceback
+
+    try:
+        template = lookup.get_template(uri)
+        print(template.render())
+    except:
+        traceback = RichTraceback()
+        for (filename, lineno, function, line) in traceback.traceback:
+            print("File %s, line %s, in %s" % (filename, lineno, function))
+            print(line, "\n")
+        print("%s: %s" % (str(traceback.error.__class__.__name__), traceback.error))
+
+Common Framework Integrations
+=============================
+
+The Mako distribution includes a little bit of helper code for
+the purpose of using Mako in some popular web framework
+scenarios. This is a brief description of what's included.
+
+WSGI
+----
+
+A sample WSGI application is included in the distribution in the
+file ``examples/wsgi/run_wsgi.py``. This runner is set up to pull
+files from a `templates` as well as an `htdocs` directory and
+includes a rudimental two-file layout. The WSGI runner acts as a
+fully functional standalone web server, using ``wsgiutils`` to run
+itself, and propagates GET and POST arguments from the request
+into the :class:`.Context`, can serve images, CSS files and other kinds
+of files, and also displays errors using Mako's included
+exception-handling utilities.
+
+Pygments
+--------
+
+A `Pygments <http://pygments.pocoo.org>`_-compatible syntax
+highlighting module is included under :mod:`mako.ext.pygmentplugin`.
+This module is used in the generation of Mako documentation and
+also contains various `setuptools` entry points under the heading
+``pygments.lexers``, including ``mako``, ``html+mako``, ``xml+mako``
+(see the ``setup.py`` file for all the entry points).
+
+Babel
+-----
+
+Mako provides support for extracting `gettext` messages from
+templates via a `Babel`_ extractor
+entry point under ``mako.ext.babelplugin``.
+
+`Gettext` messages are extracted from all Python code sections,
+including those of control lines and expressions embedded
+in tags.
+
+`Translator
+comments <http://babel.edgewall.org/wiki/Documentation/messages.html#comments-tags-and-translator-comments-explanation>`_
+may also be extracted from Mako templates when a comment tag is
+specified to `Babel`_ (such as with
+the ``-c`` option).
+
+For example, a project ``"myproj"`` contains the following Mako
+template at ``myproj/myproj/templates/name.html``:
+
+.. sourcecode:: mako
+
+    <div id="name">
+      Name:
+      ## TRANSLATORS: This is a proper name. See the gettext
+      ## manual, section Names.
+      ${_('Francois Pinard')}
+    </div>
+
+To extract gettext messages from this template the project needs
+a Mako section in its `Babel Extraction Method Mapping
+file <http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration>`_
+(typically located at ``myproj/babel.cfg``):
+
+.. sourcecode:: cfg
+
+    # Extraction from Python source files
+
+    [python: myproj/**.py]
+
+    # Extraction from Mako templates
+
+    [mako: myproj/templates/**.html]
+    input_encoding = utf-8
+
+The Mako extractor supports an optional ``input_encoding``
+parameter specifying the encoding of the templates (identical to
+:class:`.Template`/:class:`.TemplateLookup`'s ``input_encoding`` parameter).
+
+Invoking `Babel`_'s extractor at the
+command line in the project's root directory:
+
+.. sourcecode:: sh
+
+    myproj$ pybabel extract -F babel.cfg -c "TRANSLATORS:" .
+
+will output a `gettext` catalog to `stdout` including the following:
+
+.. sourcecode:: pot
+
+    #. TRANSLATORS: This is a proper name. See the gettext
+    #. manual, section Names.
+    #: myproj/templates/name.html:5
+    msgid "Francois Pinard"
+    msgstr ""
+
+This is only a basic example:
+`Babel`_ can be invoked from ``setup.py``
+and its command line options specified in the accompanying
+``setup.cfg`` via `Babel Distutils/Setuptools
+Integration <http://babel.edgewall.org/wiki/Documentation/setup.html>`_.
+
+Comments must immediately precede a `gettext` message to be
+extracted. In the following case the ``TRANSLATORS:`` comment would
+not have been extracted:
+
+.. sourcecode:: mako
+
+    <div id="name">
+      ## TRANSLATORS: This is a proper name. See the gettext
+      ## manual, section Names.
+      Name: ${_('Francois Pinard')}
+    </div>
+
+See the `Babel User
+Guide <http://babel.edgewall.org/wiki/Documentation/index.html>`_
+for more information.
+
+.. _babel: http://babel.edgewall.org/
+
+
+API Reference
+=============
+
+.. autoclass:: mako.template.Template
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.template.DefTemplate
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.lookup.TemplateCollection
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.lookup.TemplateLookup
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mako.exceptions.RichTraceback
+    :show-inheritance:
+
+    .. py:attribute:: error
+
+       the exception instance.
+
+    .. py:attribute:: message
+
+       the exception error message as unicode.
+
+    .. py:attribute:: source
+
+       source code of the file where the error occurred.
+       If the error occurred within a compiled template,
+       this is the template source.
+
+    .. py:attribute:: lineno
+
+       line number where the error occurred.  If the error
+       occurred within a compiled template, the line number
+       is adjusted to that of the template source.
+
+    .. py:attribute:: records
+
+       a list of 8-tuples containing the original
+       python traceback elements, plus the
+       filename, line number, source line, and full template source
+       for the traceline mapped back to its originating source
+       template, if any for that traceline (else the fields are ``None``).
+
+    .. py:attribute:: reverse_records
+
+       the list of records in reverse
+       traceback -- a list of 4-tuples, in the same format as a regular
+       python traceback, with template-corresponding
+       traceback records replacing the originals.
+
+    .. py:attribute:: reverse_traceback
+
+       the traceback list in reverse.
+
+.. autofunction:: mako.exceptions.html_error_template
+
+.. autofunction:: mako.exceptions.text_error_template
+
diff --git a/doc/caching.html b/doc/caching.html
new file mode 100644 (file)
index 0000000..7e6e9a7
--- /dev/null
@@ -0,0 +1,790 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Caching
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Changelog" href="changelog.html" />
+        <link rel="prev" title="The Unicode Chapter" href="unicode.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="unicode.html" title="previous chapter">The Unicode Chapter</a>
+            </li>
+            <li>Next:
+            <a href="changelog.html" title="next chapter">Changelog</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/caching.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Caching
+            
+
+        <h2>
+            
+                Caching
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Caching</a><ul>
+<li><a class="reference internal" href="#cache-arguments">Cache Arguments</a><ul>
+<li><a class="reference internal" href="#backend-specific-cache-arguments">Backend-Specific Cache Arguments</a></li>
+<li><a class="reference internal" href="#using-the-beaker-cache-backend">Using the Beaker Cache Backend</a></li>
+<li><a class="reference internal" href="#using-the-dogpile-cache-backend">Using the dogpile.cache Backend</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#programmatic-cache-access">Programmatic Cache Access</a></li>
+<li><a class="reference internal" href="#cache-plugins">Cache Plugins</a><ul>
+<li><a class="reference internal" href="#guidelines-for-writing-cache-plugins">Guidelines for Writing Cache Plugins</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#api-reference">API Reference</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="unicode.html" title="previous chapter">The Unicode Chapter</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="changelog.html" title="next chapter">Changelog</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="caching">
+<span id="caching-toplevel"></span><h1>Caching<a class="headerlink" href="#caching" title="Permalink to this headline">¶</a></h1>
+<p>Any template or component can be cached using the <code class="docutils literal"><span class="pre">cache</span></code>
+argument to the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> or <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> directives:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">template text</span>
+</pre></div>
+</div>
+<p>The above template, after being executed the first time, will
+store its content within a cache that by default is scoped
+within memory. Subsequent calls to the template&#8217;s <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a>
+method will return content directly from the cache. When the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object itself falls out of scope, its corresponding
+cache is garbage collected along with the template.</p>
+<p>The caching system requires that a cache backend be installed; this
+includes either the <a class="reference external" href="http://beaker.readthedocs.org/">Beaker</a> package
+or the <a class="reference external" href="http://dogpilecache.readthedocs.org">dogpile.cache</a>, as well as
+any other third-party caching libraries that feature Mako integration.</p>
+<p>By default, caching will attempt to make use of Beaker.
+To use dogpile.cache, the
+<code class="docutils literal"><span class="pre">cache_impl</span></code> argument must be set; see this argument in the
+section <a class="reference internal" href="#cache-arguments"><span class="std std-ref">Cache Arguments</span></a>.</p>
+<p>In addition to being available on the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag, the caching flag and all
+its options can be used with the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tag as well:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;mycomp&quot;</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_timeout=</span><span class="s">&quot;60&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    other text</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>... and equivalently with the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> tag, anonymous or named:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_timeout=</span><span class="s">&quot;60&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    other text</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<div class="section" id="cache-arguments">
+<span id="id1"></span><h2>Cache Arguments<a class="headerlink" href="#cache-arguments" title="Permalink to this headline">¶</a></h2>
+<p>Mako has two cache arguments available on tags that are
+available in all cases.   The rest of the arguments
+available are specific to a backend.</p>
+<p>The two generic tags arguments are:</p>
+<ul>
+<li><p class="first"><code class="docutils literal"><span class="pre">cached=&quot;True&quot;</span></code> - enable caching for this <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>,
+<code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>, or <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code>.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">cache_key</span></code> - the &#8220;key&#8221; used to uniquely identify this content
+in the cache.   Usually, this key is chosen automatically
+based on the name of the rendering callable (i.e. <code class="docutils literal"><span class="pre">body</span></code>
+when used in <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>, the name of the def when using <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>,
+the explicit or internally-generated name when using <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code>).
+Using the <code class="docutils literal"><span class="pre">cache_key</span></code> parameter, the key can be overridden
+using a fixed or programmatically generated value.</p>
+<p>For example, here&#8217;s a page
+that caches any page which inherits from it, based on the
+filename of the calling template:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_key=</span><span class="s">&quot;${self.filename}&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span>
+
+<span class="cp">## rest of template</span><span class="x"></span>
+</pre></div>
+</div>
+</li>
+</ul>
+<p>On a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, the
+caching can be configured using these arguments:</p>
+<ul>
+<li><p class="first"><code class="docutils literal"><span class="pre">cache_enabled</span></code> - Setting this
+to <code class="docutils literal"><span class="pre">False</span></code> will disable all caching functionality
+when the template renders.  Defaults to <code class="docutils literal"><span class="pre">True</span></code>.
+e.g.:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">lookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span>
+                <span class="n">directories</span><span class="o">=</span><span class="s1">&#39;/path/to/templates&#39;</span><span class="p">,</span>
+                <span class="n">cache_enabled</span> <span class="o">=</span> <span class="bp">False</span>
+                <span class="p">)</span>
+</pre></div>
+</div>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">cache_impl</span></code> - The string name of the cache backend
+to use.   This defaults to <code class="docutils literal"><span class="pre">'beaker'</span></code>, indicating
+that the &#8216;beaker&#8217; backend will be used.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">cache_args</span></code> - A dictionary of cache parameters that
+will be consumed by the cache backend.   See
+<a class="reference internal" href="#beaker-backend"><span class="std std-ref">Using the Beaker Cache Backend</span></a> and <a class="reference internal" href="#dogpile-cache-backend"><span class="std std-ref">Using the dogpile.cache Backend</span></a> for examples.</p>
+</li>
+</ul>
+<div class="section" id="backend-specific-cache-arguments">
+<h3>Backend-Specific Cache Arguments<a class="headerlink" href="#backend-specific-cache-arguments" title="Permalink to this headline">¶</a></h3>
+<p>The <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>, and <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> tags
+accept any named argument that starts with the prefix <code class="docutils literal"><span class="pre">&quot;cache_&quot;</span></code>.
+Those arguments are then packaged up and passed along to the
+underlying caching implementation, minus the <code class="docutils literal"><span class="pre">&quot;cache_&quot;</span></code> prefix.</p>
+<p>The actual arguments understood are determined by the backend.</p>
+<ul class="simple">
+<li><a class="reference internal" href="#beaker-backend"><span class="std std-ref">Using the Beaker Cache Backend</span></a> - Includes arguments understood by
+Beaker.</li>
+<li><a class="reference internal" href="#dogpile-cache-backend"><span class="std std-ref">Using the dogpile.cache Backend</span></a> - Includes arguments understood by
+dogpile.cache.</li>
+</ul>
+</div>
+<div class="section" id="using-the-beaker-cache-backend">
+<span id="beaker-backend"></span><h3>Using the Beaker Cache Backend<a class="headerlink" href="#using-the-beaker-cache-backend" title="Permalink to this headline">¶</a></h3>
+<p>When using Beaker, new implementations will want to make usage
+of <strong>cache regions</strong> so that cache configurations can be maintained
+externally to templates.  These configurations live under
+named &#8220;regions&#8221; that can be referred to within templates themselves.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.6.0: </span>Support for Beaker cache regions.</p>
+</div>
+<p>For example, suppose we would like two regions.  One is a &#8220;short term&#8221;
+region that will store content in a memory-based dictionary,
+expiring after 60 seconds.   The other is a Memcached region,
+where values should expire in five minutes.   To configure
+our <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, first we get a handle to a
+<code class="xref py py-class docutils literal"><span class="pre">beaker.cache.CacheManager</span></code>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">beaker.cache</span> <span class="kn">import</span> <span class="n">CacheManager</span>
+
+<span class="n">manager</span> <span class="o">=</span> <span class="n">CacheManager</span><span class="p">(</span><span class="n">cache_regions</span><span class="o">=</span><span class="p">{</span>
+    <span class="s1">&#39;short_term&#39;</span><span class="p">:{</span>
+        <span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;memory&#39;</span><span class="p">,</span>
+        <span class="s1">&#39;expire&#39;</span><span class="p">:</span> <span class="mi">60</span>
+    <span class="p">},</span>
+    <span class="s1">&#39;long_term&#39;</span><span class="p">:{</span>
+        <span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="s1">&#39;ext:memcached&#39;</span><span class="p">,</span>
+        <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="s1">&#39;127.0.0.1:11211&#39;</span><span class="p">,</span>
+        <span class="s1">&#39;expire&#39;</span><span class="p">:</span> <span class="mi">300</span>
+    <span class="p">}</span>
+<span class="p">})</span>
+
+<span class="n">lookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span>
+                <span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/path/to/templates&#39;</span><span class="p">],</span>
+                <span class="n">module_directory</span><span class="o">=</span><span class="s1">&#39;/path/to/modules&#39;</span><span class="p">,</span>
+                <span class="n">cache_impl</span><span class="o">=</span><span class="s1">&#39;beaker&#39;</span><span class="p">,</span>
+                <span class="n">cache_args</span><span class="o">=</span><span class="p">{</span>
+                    <span class="s1">&#39;manager&#39;</span><span class="p">:</span><span class="n">manager</span>
+                <span class="p">}</span>
+        <span class="p">)</span>
+</pre></div>
+</div>
+<p>Our templates can then opt to cache data in one of either region,
+using the <code class="docutils literal"><span class="pre">cache_region</span></code> argument.   Such as using <code class="docutils literal"><span class="pre">short_term</span></code>
+at the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> level:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_region=</span><span class="s">&quot;short_term&quot;</span><span class="cp">&gt;</span>
+
+<span class="cp">## ...</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Or, <code class="docutils literal"><span class="pre">long_term</span></code> at the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> level:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_region=</span><span class="s">&quot;long_term&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    other text</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The Beaker backend also works without regions.   There are a
+variety of arguments that can be passed to the <code class="docutils literal"><span class="pre">cache_args</span></code>
+dictionary, which are also allowable in templates via the
+<code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code>,
+and <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tags specific to those sections.   The values
+given override those specified at the  <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>
+or <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> level.</p>
+<p>With the possible exception
+of <code class="docutils literal"><span class="pre">cache_timeout</span></code>, these arguments are probably better off
+staying at the template configuration level.  Each argument
+specified as <code class="docutils literal"><span class="pre">cache_XYZ</span></code> in a template tag is specified
+without the <code class="docutils literal"><span class="pre">cache_</span></code> prefix in the <code class="docutils literal"><span class="pre">cache_args</span></code> dictionary:</p>
+<ul class="simple">
+<li><code class="docutils literal"><span class="pre">cache_timeout</span></code> - number of seconds in which to invalidate the
+cached data.  After this timeout, the content is re-generated
+on the next call.  Available as <code class="docutils literal"><span class="pre">timeout</span></code> in the <code class="docutils literal"><span class="pre">cache_args</span></code>
+dictionary.</li>
+<li><code class="docutils literal"><span class="pre">cache_type</span></code> - type of caching. <code class="docutils literal"><span class="pre">'memory'</span></code>, <code class="docutils literal"><span class="pre">'file'</span></code>, <code class="docutils literal"><span class="pre">'dbm'</span></code>, or
+<code class="docutils literal"><span class="pre">'ext:memcached'</span></code> (note that  the string <code class="docutils literal"><span class="pre">memcached</span></code> is
+also accepted by the dogpile.cache Mako plugin, though not by Beaker itself).
+Available as <code class="docutils literal"><span class="pre">type</span></code> in the <code class="docutils literal"><span class="pre">cache_args</span></code> dictionary.</li>
+<li><code class="docutils literal"><span class="pre">cache_url</span></code> - (only used for <code class="docutils literal"><span class="pre">memcached</span></code> but required) a single
+IP address or a semi-colon separated list of IP address of
+memcache servers to use.  Available as <code class="docutils literal"><span class="pre">url</span></code> in the <code class="docutils literal"><span class="pre">cache_args</span></code>
+dictionary.</li>
+<li><code class="docutils literal"><span class="pre">cache_dir</span></code> - in the case of the <code class="docutils literal"><span class="pre">'file'</span></code> and <code class="docutils literal"><span class="pre">'dbm'</span></code> cache types,
+this is the filesystem directory with which to store data
+files. If this option is not present, the value of
+<code class="docutils literal"><span class="pre">module_directory</span></code> is used (i.e. the directory where compiled
+template modules are stored). If neither option is available
+an exception is thrown.  Available as <code class="docutils literal"><span class="pre">dir</span></code> in the
+<code class="docutils literal"><span class="pre">cache_args</span></code> dictionary.</li>
+</ul>
+</div>
+<div class="section" id="using-the-dogpile-cache-backend">
+<span id="dogpile-cache-backend"></span><h3>Using the dogpile.cache Backend<a class="headerlink" href="#using-the-dogpile-cache-backend" title="Permalink to this headline">¶</a></h3>
+<p><a class="reference external" href="http://dogpilecache.readthedocs.org">dogpile.cache</a> is a new replacement for Beaker.   It provides
+a modernized, slimmed down interface and is generally easier to use
+than Beaker.   As of this writing it has not yet been released.  dogpile.cache
+includes its own Mako cache plugin &#8211; see <a class="reference external" href="http://dogpilecache.readthedocs.io/en/latest/api.html#module-dogpile.cache.plugins.mako_cache" title="(in dogpile.cache v0.6.2)"><code class="xref py py-mod docutils literal"><span class="pre">dogpile.cache.plugins.mako_cache</span></code></a> in the
+dogpile.cache documentation.</p>
+</div>
+</div>
+<div class="section" id="programmatic-cache-access">
+<h2>Programmatic Cache Access<a class="headerlink" href="#programmatic-cache-access" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>, as well as any template-derived <a class="reference internal" href="namespaces.html#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, has
+an accessor called <code class="docutils literal"><span class="pre">cache</span></code> which returns the <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> object
+for that template. This object is a facade on top of the underlying
+<a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> object, and provides some very rudimental
+capabilities, such as the ability to get and put arbitrary
+values:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="n">local</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;somekey&quot;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s2">&quot;memory&quot;</span><span class="p">,</span> <span class="s2">&quot;somevalue&quot;</span><span class="p">)</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Above, the cache associated with the <code class="docutils literal"><span class="pre">local</span></code> namespace is
+accessed and a key is placed within a memory cache.</p>
+<p>More commonly, the <code class="docutils literal"><span class="pre">cache</span></code> object is used to invalidate cached
+sections programmatically:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">template</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s1">&#39;/sometemplate.html&#39;</span><span class="p">)</span>
+
+<span class="c1"># invalidate the &quot;body&quot; of the template</span>
+<span class="n">template</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">invalidate_body</span><span class="p">()</span>
+
+<span class="c1"># invalidate an individual def</span>
+<span class="n">template</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">invalidate_def</span><span class="p">(</span><span class="s1">&#39;somedef&#39;</span><span class="p">)</span>
+
+<span class="c1"># invalidate an arbitrary key</span>
+<span class="n">template</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">invalidate</span><span class="p">(</span><span class="s1">&#39;somekey&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>You can access any special method or attribute of the <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a>
+itself using the <a class="reference internal" href="#mako.cache.Cache.impl" title="mako.cache.Cache.impl"><code class="xref py py-attr docutils literal"><span class="pre">impl</span></code></a> attribute:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">template</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">impl</span><span class="o">.</span><span class="n">do_something_special</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>Note that using implementation-specific methods will mean you can&#8217;t
+swap in a different kind of <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> implementation at a
+later time.</p>
+</div>
+<div class="section" id="cache-plugins">
+<span id="id2"></span><h2>Cache Plugins<a class="headerlink" href="#cache-plugins" title="Permalink to this headline">¶</a></h2>
+<p>The mechanism used by caching can be plugged in
+using a <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> subclass.    This class implements
+the rudimental methods Mako needs to implement the caching
+API.   Mako includes the <a class="reference internal" href="#mako.ext.beaker_cache.BeakerCacheImpl" title="mako.ext.beaker_cache.BeakerCacheImpl"><code class="xref py py-class docutils literal"><span class="pre">BeakerCacheImpl</span></code></a> class to
+provide the default implementation.  A <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> class
+is acquired by Mako using a <code class="docutils literal"><span class="pre">pkg_resources</span></code> entrypoint, using
+the name given as the <code class="docutils literal"><span class="pre">cache_impl</span></code> argument to <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>
+or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>.    This entry point can be
+installed via the standard <cite>setuptools</cite>/<code class="docutils literal"><span class="pre">setup()</span></code> procedure, underneath
+the <cite>EntryPoint</cite> group named <code class="docutils literal"><span class="pre">&quot;mako.cache&quot;</span></code>.  It can also be
+installed at runtime via a convenience installer <a class="reference internal" href="#mako.cache.register_plugin" title="mako.cache.register_plugin"><code class="xref py py-func docutils literal"><span class="pre">register_plugin()</span></code></a>
+which accomplishes essentially the same task.</p>
+<p>An example plugin that implements a local dictionary cache:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.cache</span> <span class="kn">import</span> <span class="n">Cacheimpl</span><span class="p">,</span> <span class="n">register_plugin</span>
+
+<span class="k">class</span> <span class="nc">SimpleCacheImpl</span><span class="p">(</span><span class="n">CacheImpl</span><span class="p">):</span>
+    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cache</span><span class="p">):</span>
+        <span class="nb">super</span><span class="p">(</span><span class="n">SimpleCacheImpl</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">cache</span><span class="p">)</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span> <span class="o">=</span> <span class="p">{}</span>
+
+    <span class="k">def</span> <span class="nf">get_or_create</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">creation_function</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+        <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">:</span>
+            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="o">=</span> <span class="n">creation_function</span><span class="p">()</span>
+            <span class="k">return</span> <span class="n">value</span>
+
+    <span class="k">def</span> <span class="nf">set</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
+
+    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
+        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
+
+    <span class="k">def</span> <span class="nf">invalidate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
+
+<span class="c1"># optional - register the class locally</span>
+<span class="n">register_plugin</span><span class="p">(</span><span class="s2">&quot;simple&quot;</span><span class="p">,</span> <span class="n">__name__</span><span class="p">,</span> <span class="s2">&quot;SimpleCacheImpl&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Enabling the above plugin in a template would look like:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;mytemplate&quot;</span><span class="p">,</span>
+             <span class="nb">file</span><span class="o">=</span><span class="s2">&quot;mytemplate.html&quot;</span><span class="p">,</span>
+             <span class="n">cache_impl</span><span class="o">=</span><span class="s1">&#39;simple&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<div class="section" id="guidelines-for-writing-cache-plugins">
+<h3>Guidelines for Writing Cache Plugins<a class="headerlink" href="#guidelines-for-writing-cache-plugins" title="Permalink to this headline">¶</a></h3>
+<ul class="simple">
+<li>The <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> is created on a per-<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> basis.  The
+class should ensure that only data for the parent <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> is
+persisted or returned by the cache methods.    The actual <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>
+is available via the <code class="docutils literal"><span class="pre">self.cache.template</span></code> attribute.   The <code class="docutils literal"><span class="pre">self.cache.id</span></code>
+attribute, which is essentially the unique modulename of the template, is
+a good value to use in order to represent a unique namespace of keys specific
+to the template.</li>
+<li>Templates only use the <a class="reference internal" href="#mako.cache.CacheImpl.get_or_create" title="mako.cache.CacheImpl.get_or_create"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.get_or_create()</span></code></a> method
+in an implicit fashion.  The <a class="reference internal" href="#mako.cache.CacheImpl.set" title="mako.cache.CacheImpl.set"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.set()</span></code></a>,
+<a class="reference internal" href="#mako.cache.CacheImpl.get" title="mako.cache.CacheImpl.get"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.get()</span></code></a>, and <a class="reference internal" href="#mako.cache.CacheImpl.invalidate" title="mako.cache.CacheImpl.invalidate"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.invalidate()</span></code></a> methods are
+only used in response to direct programmatic access to the corresponding
+methods on the <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> object.</li>
+<li><a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> will be accessed in a multithreaded fashion if the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> itself is used multithreaded.  Care should be taken
+to ensure caching implementations are threadsafe.</li>
+<li>A library like <a class="reference external" href="http://pypi.python.org/pypi/dogpile.core">Dogpile</a>, which
+is a minimal locking system derived from Beaker, can be used to help
+implement the <a class="reference internal" href="#mako.cache.CacheImpl.get_or_create" title="mako.cache.CacheImpl.get_or_create"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.get_or_create()</span></code></a> method in a threadsafe
+way that can maximize effectiveness across multiple threads as well
+as processes. <a class="reference internal" href="#mako.cache.CacheImpl.get_or_create" title="mako.cache.CacheImpl.get_or_create"><code class="xref py py-meth docutils literal"><span class="pre">CacheImpl.get_or_create()</span></code></a> is the
+key method used by templates.</li>
+<li>All arguments passed to <code class="docutils literal"><span class="pre">**kw</span></code> come directly from the parameters
+inside the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code>, or <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tags directly,
+minus the <code class="docutils literal"><span class="pre">&quot;cache_&quot;</span></code> prefix, as strings, with the exception of
+the argument <code class="docutils literal"><span class="pre">cache_timeout</span></code>, which is passed to the plugin
+as the name <code class="docutils literal"><span class="pre">timeout</span></code> with the value converted to an integer.
+Arguments present in <code class="docutils literal"><span class="pre">cache_args</span></code> on <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or
+<a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> are passed directly, but are superseded
+by those present in the most specific template tag.</li>
+<li>The directory where <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> places module files can
+be acquired using the accessor <code class="docutils literal"><span class="pre">self.cache.template.module_directory</span></code>.
+This directory can be a good place to throw cache-related work
+files, underneath a prefix like <code class="docutils literal"><span class="pre">_my_cache_work</span></code> so that name
+conflicts with generated modules don&#8217;t occur.</li>
+</ul>
+</div>
+</div>
+<div class="section" id="api-reference">
+<h2>API Reference<a class="headerlink" href="#api-reference" title="Permalink to this headline">¶</a></h2>
+<dl class="class">
+<dt id="mako.cache.Cache">
+<em class="property">class </em><code class="descclassname">mako.cache.</code><code class="descname">Cache</code><span class="sig-paren">(</span><em>template</em>, <em>*args</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Represents a data content cache made available to the module
+space of a specific <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.6: </span><a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> by itself is mostly a
+container for a <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> object, which implements
+a fixed API to provide caching services; specific subclasses exist to
+implement different
+caching strategies.   Mako includes a backend that works with
+the Beaker caching system.   Beaker itself then supports
+a number of backends (i.e. file, memory, memcached, etc.)</p>
+</div>
+<p>The construction of a <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> is part of the mechanics
+of a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>, and programmatic access to this
+cache is typically via the <code class="xref py py-attr docutils literal"><span class="pre">Template.cache</span></code> attribute.</p>
+<dl class="method">
+<dt id="mako.cache.Cache.get">
+<code class="descname">get</code><span class="sig-paren">(</span><em>key</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.get" title="Permalink to this definition">¶</a></dt>
+<dd><p>Retrieve a value from the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.Cache.get.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.get.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.Cache.get.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.get.params.**kw">¶</a> &#8211; cache configuration arguments.  The
+backend is configured using these arguments upon first request.
+Subsequent requests that use the same series of configuration
+values will use that same backend.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.get_or_create">
+<code class="descname">get_or_create</code><span class="sig-paren">(</span><em>key</em>, <em>creation_function</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.get_or_create" title="Permalink to this definition">¶</a></dt>
+<dd><p>Retrieve a value from the cache, using the given creation function
+to generate a new value.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.cache.Cache.id">
+<code class="descname">id</code><em class="property"> = None</em><a class="headerlink" href="#mako.cache.Cache.id" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the &#8216;id&#8217; that identifies this cache.</p>
+<p>This is a value that should be globally unique to the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> associated with this cache, and can
+be used by a caching system to name a local container
+for data specific to this template.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.cache.Cache.impl">
+<code class="descname">impl</code><em class="property"> = None</em><a class="headerlink" href="#mako.cache.Cache.impl" title="Permalink to this definition">¶</a></dt>
+<dd><p>Provide the <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> in use by this <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a>.</p>
+<p>This accessor allows a <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> with additional
+methods beyond that of <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> to be used programmatically.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.invalidate">
+<code class="descname">invalidate</code><span class="sig-paren">(</span><em>key</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.invalidate" title="Permalink to this definition">¶</a></dt>
+<dd><p>Invalidate a value in the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.Cache.invalidate.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.invalidate.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.Cache.invalidate.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.invalidate.params.**kw">¶</a> &#8211; cache configuration arguments.  The
+backend is configured using these arguments upon first request.
+Subsequent requests that use the same series of configuration
+values will use that same backend.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.invalidate_body">
+<code class="descname">invalidate_body</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.invalidate_body" title="Permalink to this definition">¶</a></dt>
+<dd><p>Invalidate the cached content of the &#8220;body&#8221; method for this
+template.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.invalidate_closure">
+<code class="descname">invalidate_closure</code><span class="sig-paren">(</span><em>name</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.invalidate_closure" title="Permalink to this definition">¶</a></dt>
+<dd><p>Invalidate a nested <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> within this template.</p>
+<p>Caching of nested defs is a blunt tool as there is no
+management of scope &#8211; nested defs that use cache tags
+need to have names unique of all other nested defs in the
+template, else their content will be overwritten by
+each other.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.invalidate_def">
+<code class="descname">invalidate_def</code><span class="sig-paren">(</span><em>name</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.invalidate_def" title="Permalink to this definition">¶</a></dt>
+<dd><p>Invalidate the cached content of a particular <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> within this
+template.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.put">
+<code class="descname">put</code><span class="sig-paren">(</span><em>key</em>, <em>value</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.put" title="Permalink to this definition">¶</a></dt>
+<dd><p>A synonym for <a class="reference internal" href="#mako.cache.Cache.set" title="mako.cache.Cache.set"><code class="xref py py-meth docutils literal"><span class="pre">Cache.set()</span></code></a>.</p>
+<p>This is here for backwards compatibility.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.Cache.set">
+<code class="descname">set</code><span class="sig-paren">(</span><em>key</em>, <em>value</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.Cache.set" title="Permalink to this definition">¶</a></dt>
+<dd><p>Place a value in the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.Cache.set.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.set.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.Cache.set.params.value"></span><strong>value</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.set.params.value">¶</a> &#8211; the value.</li>
+<li><span class="target" id="mako.cache.Cache.set.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.Cache.set.params.**kw">¶</a> &#8211; cache configuration arguments.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.cache.Cache.starttime">
+<code class="descname">starttime</code><em class="property"> = None</em><a class="headerlink" href="#mako.cache.Cache.starttime" title="Permalink to this definition">¶</a></dt>
+<dd><p>Epochal time value for when the owning <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> was
+first compiled.</p>
+<p>A cache implementation may wish to invalidate data earlier than
+this timestamp; this has the effect of the cache for a specific
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> starting clean any time the <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>
+is recompiled, such as when the original template file changed on
+the filesystem.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.cache.CacheImpl">
+<em class="property">class </em><code class="descclassname">mako.cache.</code><code class="descname">CacheImpl</code><span class="sig-paren">(</span><em>cache</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.CacheImpl" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Provide a cache implementation for use by <a class="reference internal" href="#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a>.</p>
+<dl class="method">
+<dt id="mako.cache.CacheImpl.get">
+<code class="descname">get</code><span class="sig-paren">(</span><em>key</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.CacheImpl.get" title="Permalink to this definition">¶</a></dt>
+<dd><p>Retrieve a value from the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.CacheImpl.get.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.get.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.CacheImpl.get.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.get.params.**kw">¶</a> &#8211; cache configuration arguments.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.CacheImpl.get_or_create">
+<code class="descname">get_or_create</code><span class="sig-paren">(</span><em>key</em>, <em>creation_function</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.CacheImpl.get_or_create" title="Permalink to this definition">¶</a></dt>
+<dd><p>Retrieve a value from the cache, using the given creation function
+to generate a new value.</p>
+<p>This function <em>must</em> return a value, either from
+the cache, or via the given creation function.
+If the creation function is called, the newly
+created value should be populated into the cache
+under the given key before being returned.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.CacheImpl.get_or_create.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.get_or_create.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.CacheImpl.get_or_create.params.creation_function"></span><strong>creation_function</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.get_or_create.params.creation_function">¶</a> &#8211; function that when called generates
+a new value.</li>
+<li><span class="target" id="mako.cache.CacheImpl.get_or_create.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.get_or_create.params.**kw">¶</a> &#8211; cache configuration arguments.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.CacheImpl.invalidate">
+<code class="descname">invalidate</code><span class="sig-paren">(</span><em>key</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.CacheImpl.invalidate" title="Permalink to this definition">¶</a></dt>
+<dd><p>Invalidate a value in the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.CacheImpl.invalidate.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.invalidate.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.CacheImpl.invalidate.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.invalidate.params.**kw">¶</a> &#8211; cache configuration arguments.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.cache.CacheImpl.pass_context">
+<code class="descname">pass_context</code><em class="property"> = False</em><a class="headerlink" href="#mako.cache.CacheImpl.pass_context" title="Permalink to this definition">¶</a></dt>
+<dd><p>If <code class="docutils literal"><span class="pre">True</span></code>, the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> will be passed to
+<a class="reference internal" href="#mako.cache.CacheImpl.get_or_create" title="mako.cache.CacheImpl.get_or_create"><code class="xref py py-meth docutils literal"><span class="pre">get_or_create</span></code></a> as the name <code class="docutils literal"><span class="pre">'context'</span></code>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.cache.CacheImpl.set">
+<code class="descname">set</code><span class="sig-paren">(</span><em>key</em>, <em>value</em>, <em>**kw</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.CacheImpl.set" title="Permalink to this definition">¶</a></dt>
+<dd><p>Place a value in the cache.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.cache.CacheImpl.set.params.key"></span><strong>key</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.set.params.key">¶</a> &#8211; the value&#8217;s key.</li>
+<li><span class="target" id="mako.cache.CacheImpl.set.params.value"></span><strong>value</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.set.params.value">¶</a> &#8211; the value.</li>
+<li><span class="target" id="mako.cache.CacheImpl.set.params.**kw"></span><strong>**kw</strong><a class="paramlink headerlink reference internal" href="#mako.cache.CacheImpl.set.params.**kw">¶</a> &#8211; cache configuration arguments.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="function">
+<dt id="mako.cache.register_plugin">
+<code class="descclassname">mako.cache.</code><code class="descname">register_plugin</code><span class="sig-paren">(</span><em>self</em>, <em>name</em>, <em>modulepath</em>, <em>objname</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.cache.register_plugin" title="Permalink to this definition">¶</a></dt>
+<dd></dd></dl>
+
+<dl class="class">
+<dt id="mako.ext.beaker_cache.BeakerCacheImpl">
+<em class="property">class </em><code class="descclassname">mako.ext.beaker_cache.</code><code class="descname">BeakerCacheImpl</code><span class="sig-paren">(</span><em>cache</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.ext.beaker_cache.BeakerCacheImpl" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">mako.cache.CacheImpl</span></code></a></p>
+<p>A <a class="reference internal" href="#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> provided for the Beaker caching system.</p>
+<p>This plugin is used by default, based on the default
+value of <code class="docutils literal"><span class="pre">'beaker'</span></code> for the <code class="docutils literal"><span class="pre">cache_impl</span></code> parameter of the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> classes.</p>
+</dd></dl>
+
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="unicode.html" title="previous chapter">The Unicode Chapter</a>
+        Next:
+        <a href="changelog.html" title="next chapter">Changelog</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/changelog.html b/doc/changelog.html
new file mode 100644 (file)
index 0000000..88e9505
--- /dev/null
@@ -0,0 +1,1734 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Changelog
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="prev" title="Caching" href="caching.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="caching.html" title="previous chapter">Caching</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/changelog.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Changelog
+            
+
+        <h2>
+            
+                Changelog
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Changelog</a><ul>
+<li><a class="reference internal" href="#id1">1.0</a><ul>
+<li><a class="reference internal" href="#change-1.0.6">1.0.6</a></li>
+<li><a class="reference internal" href="#change-1.0.5">1.0.5</a></li>
+<li><a class="reference internal" href="#change-1.0.4">1.0.4</a></li>
+<li><a class="reference internal" href="#change-1.0.3">1.0.3</a></li>
+<li><a class="reference internal" href="#change-1.0.2">1.0.2</a></li>
+<li><a class="reference internal" href="#change-1.0.1">1.0.1</a></li>
+<li><a class="reference internal" href="#change-1.0.0">1.0.0</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id2">0.9</a><ul>
+<li><a class="reference internal" href="#change-0.9.1">0.9.1</a></li>
+<li><a class="reference internal" href="#change-0.9.0">0.9.0</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id3">0.8</a><ul>
+<li><a class="reference internal" href="#change-0.8.1">0.8.1</a></li>
+<li><a class="reference internal" href="#change-0.8.0">0.8.0</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id4">0.7</a><ul>
+<li><a class="reference internal" href="#change-0.7.3">0.7.3</a></li>
+<li><a class="reference internal" href="#change-0.7.2">0.7.2</a></li>
+<li><a class="reference internal" href="#change-0.7.1">0.7.1</a></li>
+<li><a class="reference internal" href="#change-0.7.0">0.7.0</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#older-versions">Older Versions</a><ul>
+<li><a class="reference internal" href="#change-0.6.2">0.6.2</a></li>
+<li><a class="reference internal" href="#change-0.6.1">0.6.1</a></li>
+<li><a class="reference internal" href="#change-0.6.0">0.6.0</a></li>
+<li><a class="reference internal" href="#change-0.5.0">0.5.0</a></li>
+<li><a class="reference internal" href="#change-0.4.2">0.4.2</a></li>
+<li><a class="reference internal" href="#change-0.4.1">0.4.1</a></li>
+<li><a class="reference internal" href="#change-0.4.0">0.4.0</a></li>
+<li><a class="reference internal" href="#change-0.3.6">0.3.6</a></li>
+<li><a class="reference internal" href="#change-0.3.5">0.3.5</a></li>
+<li><a class="reference internal" href="#change-0.3.4">0.3.4</a></li>
+<li><a class="reference internal" href="#change-0.3.3">0.3.3</a></li>
+<li><a class="reference internal" href="#change-0.3.2">0.3.2</a></li>
+<li><a class="reference internal" href="#change-0.3.1">0.3.1</a></li>
+<li><a class="reference internal" href="#change-0.3.0">0.3.0</a></li>
+<li><a class="reference internal" href="#change-0.2.6">0.2.6</a></li>
+<li><a class="reference internal" href="#change-0.2.5">0.2.5</a></li>
+<li><a class="reference internal" href="#change-0.2.4">0.2.4</a></li>
+<li><a class="reference internal" href="#change-0.2.3">0.2.3</a></li>
+<li><a class="reference internal" href="#change-0.2.2">0.2.2</a></li>
+<li><a class="reference internal" href="#change-0.2.1">0.2.1</a></li>
+<li><a class="reference internal" href="#change-0.2.0">0.2.0</a></li>
+<li><a class="reference internal" href="#change-0.1.10">0.1.10</a></li>
+<li><a class="reference internal" href="#change-0.1.9">0.1.9</a></li>
+<li><a class="reference internal" href="#change-0.1.8">0.1.8</a></li>
+<li><a class="reference internal" href="#change-0.1.7">0.1.7</a></li>
+<li><a class="reference internal" href="#change-0.1.6">0.1.6</a></li>
+<li><a class="reference internal" href="#change-0.1.5">0.1.5</a></li>
+<li><a class="reference internal" href="#change-0.1.4">0.1.4</a></li>
+<li><a class="reference internal" href="#change-0.1.3">0.1.3</a></li>
+<li><a class="reference internal" href="#change-0.1.2">0.1.2</a></li>
+<li><a class="reference internal" href="#change-0.1.1">0.1.1</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="caching.html" title="previous chapter">Caching</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="changelog">
+<h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="id1">
+<h2>1.0<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="change-1.0.6">
+<h3>1.0.6<a class="headerlink" href="#change-1.0.6" title="Permalink to this headline">¶</a></h3>
+Released: Wed Nov 9 2016<ul class="simple">
+<li><p id="change-1.0.6-0"><span class="target" id="change-1ab45bb9f44f0ac0c491437d7cd278d1"><strong>[feature] </strong></span>Added new parameter <a class="reference internal" href="usage.html#mako.template.Template.params.include_error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.include_error_handler</span></code></a> .
+This works like <a class="reference internal" href="usage.html#mako.template.Template.params.error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.error_handler</span></code></a> but indicates the
+handler should take place when this template is included within another
+template via the <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag.  Pull request courtesy
+Huayi Zhang.<a class="changeset-link headerlink reference internal" href="#change-1ab45bb9f44f0ac0c491437d7cd278d1">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.5">
+<h3>1.0.5<a class="headerlink" href="#change-1.0.5" title="Permalink to this headline">¶</a></h3>
+Released: Wed Nov 2 2016<ul class="simple">
+<li><p id="change-1.0.5-0"><span class="target" id="change-a888b5e8bb3335eb6b79287ee7e3e65e"><strong>[bug] </strong></span>Updated the Sphinx documentation builder to work with recent
+versions of Sphinx.<a class="changeset-link headerlink reference internal" href="#change-a888b5e8bb3335eb6b79287ee7e3e65e">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.4">
+<h3>1.0.4<a class="headerlink" href="#change-1.0.4" title="Permalink to this headline">¶</a></h3>
+Released: Thu Mar 10 2016<ul class="simple">
+<li><p id="change-1.0.4-0"><span class="target" id="change-a0f9819d8082887201784fd7fe175897"><strong>[test] [feature] </strong></span>The default test runner is now py.test.  Running &#8220;python setup.py test&#8221;
+will make use of py.test instead of nose.  nose still works as a test
+runner as well, however.<a class="changeset-link headerlink reference internal" href="#change-a0f9819d8082887201784fd7fe175897">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-1.0.4-1"><span class="target" id="change-5a254376fcfe88072601688a7fd34bb2"><strong>[lexer] [bug] </strong></span>Major improvements to lexing of intricate Python sections which may
+contain complex backslash sequences, as well as support for the bitwise
+operator (e.g. pipe symbol) inside of expression sections distinct
+from the Mako &#8220;filter&#8221; operator, provided the operator is enclosed
+within parentheses or brackets.  Pull request courtesy Daniel Martin.<a class="changeset-link headerlink reference internal" href="#change-5a254376fcfe88072601688a7fd34bb2">¶</a><p>References: <a class="reference external" href="https://github.com/zzzeek/mako/pull/19">pull request github:19</a></p>
+</p>
+</li>
+<li><p id="change-1.0.4-2"><span class="target" id="change-159bcf8ab71d37b6e32321c2d62b7fa5"><strong>[feature] </strong></span>Added new method <a class="reference internal" href="usage.html#mako.template.Template.list_defs" title="mako.template.Template.list_defs"><code class="xref py py-meth docutils literal"><span class="pre">Template.list_defs()</span></code></a>.   Pull request courtesy
+Jonathan Vanasco.<a class="changeset-link headerlink reference internal" href="#change-159bcf8ab71d37b6e32321c2d62b7fa5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/16">pull request bitbucket:16</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.3">
+<h3>1.0.3<a class="headerlink" href="#change-1.0.3" title="Permalink to this headline">¶</a></h3>
+Released: Tue Oct 27 2015<ul class="simple">
+<li><p id="change-1.0.3-0"><span class="target" id="change-a8691815262bf7a1a4857ab58b59972d"><strong>[babel] [bug] </strong></span>Fixed an issue where the Babel plugin would not handle a translation
+symbol that contained non-ascii characters.  Pull request courtesy
+Roman Imankulov.<a class="changeset-link headerlink reference internal" href="#change-a8691815262bf7a1a4857ab58b59972d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/21">pull request bitbucket:21</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.2">
+<h3>1.0.2<a class="headerlink" href="#change-1.0.2" title="Permalink to this headline">¶</a></h3>
+Released: Wed Aug 26 2015<ul class="simple">
+<li><p id="change-1.0.2-0"><span class="target" id="change-7a886c9ddff2888de5388a76c07f5fb1"><strong>[installation] [bug] </strong></span>The &#8220;universal wheel&#8221; marker is removed from setup.cfg, because
+our setup.py currently makes use of conditional dependencies.
+In <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/249/">#249</a>, the discussion is ongoing on how to correct our
+setup.cfg / setup.py fully so that we can handle the per-version
+dependency changes while still maintaining optimal wheel settings,
+so this issue is not yet fully resolved.<a class="changeset-link headerlink reference internal" href="#change-7a886c9ddff2888de5388a76c07f5fb1">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/249/">#249</a></p>
+</p>
+</li>
+<li><p id="change-1.0.2-1"><span class="target" id="change-d512dee8244e65df20387799e2bf1c3e"><strong>[bug] [py3k] </strong></span>Repair some calls within the ast module that no longer work on Python3.5;
+additionally replace the use of <code class="docutils literal"><span class="pre">inspect.getargspec()</span></code> under
+Python 3 (seems to be called from the TG plugin) to avoid deprecation
+warnings.<a class="changeset-link headerlink reference internal" href="#change-d512dee8244e65df20387799e2bf1c3e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/250/">#250</a></p>
+</p>
+</li>
+<li><p id="change-1.0.2-2"><span class="target" id="change-821f277b7de91a50393a39180bedba19"><strong>[bug] </strong></span>Update the Lingua translation extraction plugin to correctly
+handle templates mixing Python control statements (such as if,
+for and while) with template fragments. Pull request courtesy
+Laurent Daverio.<a class="changeset-link headerlink reference internal" href="#change-821f277b7de91a50393a39180bedba19">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/18">pull request bitbucket:18</a></p>
+</p>
+</li>
+<li><p id="change-1.0.2-3"><span class="target" id="change-5198757b33888a7f8f96e2cee5db8f62"><strong>[feature] </strong></span>Added <code class="docutils literal"><span class="pre">STOP_RENDERING</span></code> keyword for returning/exiting from a
+template early, which is a synonym for an empty string <code class="docutils literal"><span class="pre">&quot;&quot;</span></code>.
+Previously, the docs suggested a bare
+<code class="docutils literal"><span class="pre">return</span></code>, but this could cause <code class="docutils literal"><span class="pre">None</span></code> to appear in the
+rendered template result.<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<p class="last"><a class="reference internal" href="syntax.html#syntax-exiting-early"><span class="std std-ref">Exiting Early from a Template</span></a></p>
+</div>
+<a class="changeset-link headerlink reference internal" href="#change-5198757b33888a7f8f96e2cee5db8f62">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/236/">#236</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.1">
+<h3>1.0.1<a class="headerlink" href="#change-1.0.1" title="Permalink to this headline">¶</a></h3>
+Released: Thu Jan 22 2015<ul class="simple">
+<li><p id="change-1.0.1-0"><span class="target" id="change-1975c829883f2b542d5cde07b22d03ed"><strong>[feature] </strong></span>Added support for Lingua, a translation extraction system as an
+alternative to Babel.  Pull request courtesy Wichert Akkerman.<a class="changeset-link headerlink reference internal" href="#change-1975c829883f2b542d5cde07b22d03ed">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/9">pull request bitbucket:9</a></p>
+</p>
+</li>
+<li><p id="change-1.0.1-1"><span class="target" id="change-32bb4d6d81d803d8fcce430daf6fe6c6"><strong>[bug] [py3k] </strong></span>Modernized the examples/wsgi/run_wsgi.py file for Py3k.
+Pull requset courtesy Cody Taylor.<a class="changeset-link headerlink reference internal" href="#change-32bb4d6d81d803d8fcce430daf6fe6c6">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/11">pull request bitbucket:11</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-1.0.0">
+<h3>1.0.0<a class="headerlink" href="#change-1.0.0" title="Permalink to this headline">¶</a></h3>
+Released: Sun Jun 8 2014<ul class="simple">
+<li><p id="change-1.0.0-0"><span class="target" id="change-a1b32dcfac59fb3d94194cc23d05eec4"><strong>[py2k] [bug] </strong></span>Improved the error re-raise operation when a custom
+<a class="reference internal" href="usage.html#mako.template.Template.params.error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.error_handler</span></code></a> is used that does not handle
+the exception; the original stack trace etc. is now preserved.
+Pull request courtesy Manfred Haltner.<a class="changeset-link headerlink reference internal" href="#change-a1b32dcfac59fb3d94194cc23d05eec4">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/8">pull request bitbucket:8</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-1"><span class="target" id="change-7f76f6ca5487a165840d3f1634e26b5f"><strong>[py2k] [bug] [filters] </strong></span>Added an html_escape filter that works in &#8220;non unicode&#8221; mode.
+Previously, when using <code class="docutils literal"><span class="pre">disable_unicode=True</span></code>, the <code class="docutils literal"><span class="pre">u</span></code> filter
+would fail to handle non-ASCII bytes properly.  Pull request
+courtesy George Xie.<a class="changeset-link headerlink reference internal" href="#change-7f76f6ca5487a165840d3f1634e26b5f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/7">pull request bitbucket:7</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-2"><span class="target" id="change-b602a175c0ec26eaa4f42962d23cca96"><strong>[general] </strong></span>Compatibility changes; in order to modernize the codebase, Mako
+is now dropping support for Python 2.4 and Python 2.5 altogether.
+The source base is now targeted at Python 2.6 and forwards.<a class="changeset-link headerlink reference internal" href="#change-b602a175c0ec26eaa4f42962d23cca96">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-1.0.0-3"><span class="target" id="change-ac6c8e7df6c612e92bf81577c4c96276"><strong>[feature] </strong></span>Template modules now generate a JSON &#8220;metadata&#8221; structure at the bottom
+of the source file which includes parseable information about the
+templates&#8217; source file, encoding etc. as well as a mapping of module
+source lines to template lines, thus replacing the &#8220;# SOURCE LINE&#8221;
+markers throughout the source code.  The structure also indicates those
+lines that are explicitly not part of the template&#8217;s source; the goal
+here is to allow better integration with coverage and other tools.<a class="changeset-link headerlink reference internal" href="#change-ac6c8e7df6c612e92bf81577c4c96276">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-1.0.0-4"><span class="target" id="change-48f95a70e6b509811d3c6c208b3bbafc"><strong>[bug] [py3k] </strong></span>Fixed bug in <code class="docutils literal"><span class="pre">decode.&lt;encoding&gt;</span></code> filter where a non-string object
+would not be correctly interpreted in Python 3.<a class="changeset-link headerlink reference internal" href="#change-48f95a70e6b509811d3c6c208b3bbafc">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-1.0.0-5"><span class="target" id="change-7638baccf1cc95230c98f9475713aff4"><strong>[bug] [py3k] </strong></span>Fixed bug in Python parsing logic which would fail on Python 3
+when a &#8220;try/except&#8221; targeted a tuple of exception types, rather
+than a single exception.<a class="changeset-link headerlink reference internal" href="#change-7638baccf1cc95230c98f9475713aff4">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/227/">#227</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-6"><span class="target" id="change-4ed767c704faafcfcaa96c993b6c3ce8"><strong>[feature] </strong></span>mako-render is now implemented as a setuptools entrypoint script;
+a standalone mako.cmd.cmdline() callable is now available, and the
+system also uses argparse now instead of optparse.  Pull request
+courtesy Derek Harland.<a class="changeset-link headerlink reference internal" href="#change-4ed767c704faafcfcaa96c993b6c3ce8">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/5">pull request bitbucket:5</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-7"><span class="target" id="change-b514d619be9c65cb0abb149be8b3a1a2"><strong>[feature] </strong></span>The mako-render script will now catch exceptions and run them
+into the text error handler, and exit with a non-zero exit code.
+Pull request courtesy Derek Harland.<a class="changeset-link headerlink reference internal" href="#change-b514d619be9c65cb0abb149be8b3a1a2">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/4">pull request bitbucket:4</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-8"><span class="target" id="change-a328a21ec5123a69caf9021bbf70b90a"><strong>[bug] </strong></span>A rework of the mako-render script allows the script to run
+correctly when given a file pathname that is outside of the current
+directory, e.g. <code class="docutils literal"><span class="pre">mako-render</span> <span class="pre">../some_template.mako</span></code>.  In this case,
+the &#8220;template root&#8221; defaults to the directory in which the template
+is located, instead of &#8221;.&#8221;.  The script also accepts a new argument
+<code class="docutils literal"><span class="pre">--template-dir</span></code> which can be specified multiple times to establish
+template lookup directories.  Standard input for templates also works
+now too.  Pull request courtesy Derek Harland.<a class="changeset-link headerlink reference internal" href="#change-a328a21ec5123a69caf9021bbf70b90a">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/pull-request/2">pull request bitbucket:2</a></p>
+</p>
+</li>
+<li><p id="change-1.0.0-9"><span class="target" id="change-e39fabd3e579af9dd730204a7692c76f"><strong>[feature] [py3k] </strong></span>Support is added for Python 3 &#8220;keyword only&#8221; arguments, as used in
+defs.  Pull request courtesy Eevee.<a class="changeset-link headerlink reference internal" href="#change-e39fabd3e579af9dd730204a7692c76f">¶</a><p>References: <a class="reference external" href="https://github.com/zzzeek/mako/pull/7">pull request github:7</a></p>
+</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="id2">
+<h2>0.9<a class="headerlink" href="#id2" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="change-0.9.1">
+<h3>0.9.1<a class="headerlink" href="#change-0.9.1" title="Permalink to this headline">¶</a></h3>
+Released: Thu Dec 26 2013<ul class="simple">
+<li><p id="change-0.9.1-0"><span class="target" id="change-8b4011d90ed7ddc770e03ef8ade6e6dc"><strong>[bug] </strong></span>Fixed bug in Babel plugin where translator comments
+would be lost if intervening text nodes were encountered.
+Fix courtesy Ned Batchelder.<a class="changeset-link headerlink reference internal" href="#change-8b4011d90ed7ddc770e03ef8ade6e6dc">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/225/">#225</a></p>
+</p>
+</li>
+<li><p id="change-0.9.1-1"><span class="target" id="change-a7b4b7fb4a7bf5e4c0ca7c2a7b072eca"><strong>[bug] </strong></span>Fixed TGPlugin.render method to support unicode template
+names in Py2K - courtesy Vladimir Magamedov.<a class="changeset-link headerlink reference internal" href="#change-a7b4b7fb4a7bf5e4c0ca7c2a7b072eca">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.9.1-2"><span class="target" id="change-c3dd59728d365b33fe9fcbf8ea96f9ab"><strong>[bug] </strong></span>Fixed an AST issue that was preventing correct operation
+under alpha versions of Python 3.4.  Pullreq courtesy Zer0-.<a class="changeset-link headerlink reference internal" href="#change-c3dd59728d365b33fe9fcbf8ea96f9ab">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.9.1-3"><span class="target" id="change-166e48714e8db96013d1a6038e54aff4"><strong>[bug] </strong></span>Changed the format of the &#8220;source encoding&#8221; header output
+by the code generator to use the format <code class="docutils literal"><span class="pre">#</span> <span class="pre">-*-</span> <span class="pre">coding:%s</span> <span class="pre">-*-</span></code>
+instead of <code class="docutils literal"><span class="pre">#</span> <span class="pre">-*-</span> <span class="pre">encoding:%s</span> <span class="pre">-*-</span></code>; the former is more common
+and compatible with emacs.  Courtesy Martin Geisler.<a class="changeset-link headerlink reference internal" href="#change-166e48714e8db96013d1a6038e54aff4">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.9.1-4"><span class="target" id="change-9a88fa8f596546fb451bfcbfa7ce6274"><strong>[bug] </strong></span>Fixed issue where an old lexer rule prevented a template line
+which looked like &#8220;#*&#8221; from being correctly parsed.<a class="changeset-link headerlink reference internal" href="#change-9a88fa8f596546fb451bfcbfa7ce6274">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/224/">#224</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.9.0">
+<h3>0.9.0<a class="headerlink" href="#change-0.9.0" title="Permalink to this headline">¶</a></h3>
+Released: Tue Aug 27 2013<ul class="simple">
+<li><p id="change-0.9.0-0"><span class="target" id="change-f529d0d5bf50c9e01e436ee12672a7f8"><strong>[bug] </strong></span>The Context.locals_() method becomes a private underscored
+method, as this method has a specific internal use. The purpose
+of Context.kwargs has been clarified, in that it only delivers
+top level keyword arguments originally passed to template.render().<a class="changeset-link headerlink reference internal" href="#change-f529d0d5bf50c9e01e436ee12672a7f8">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/219/">#219</a></p>
+</p>
+</li>
+<li><p id="change-0.9.0-1"><span class="target" id="change-41a0ced688ee0a615dcddf766d267241"><strong>[bug] </strong></span>Fixed the babel plugin to properly interpret ${} sections
+inside of a &#8220;call&#8221; tag, i.e. &lt;%self:some_tag attr=&#8221;${_(&#8216;foo&#8217;)}&#8221;/&gt;.
+Code that&#8217;s subject to babel escapes in here needs to be
+specified as a Python expression, not a literal.  This change
+is backwards incompatible vs. code that is relying upon a _(&#8216;&#8217;)
+translation to be working within a call tag.<a class="changeset-link headerlink reference internal" href="#change-41a0ced688ee0a615dcddf766d267241">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.9.0-2"><span class="target" id="change-ac972a0d002a412c4a92175229d7444f"><strong>[bug] </strong></span>The Babel plugin has been repaired to work on Python 3.<a class="changeset-link headerlink reference internal" href="#change-ac972a0d002a412c4a92175229d7444f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/187/">#187</a></p>
+</p>
+</li>
+<li><p id="change-0.9.0-3"><span class="target" id="change-dbf6f29e5e76133b9dd779baacb24818"><strong>[bug] </strong></span>Using &lt;%namespace import=&#8221;*&#8221; module=&#8221;somemodule&#8221;/&gt; now
+skips over module elements that are not explcitly callable,
+avoiding TypeError when trying to produce partials.<a class="changeset-link headerlink reference internal" href="#change-dbf6f29e5e76133b9dd779baacb24818">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/207/">#207</a></p>
+</p>
+</li>
+<li><p id="change-0.9.0-4"><span class="target" id="change-693045b580eddfdc7e464ba0426b3495"><strong>[bug] </strong></span>Fixed Py3K bug where a &#8220;lambda&#8221; expression was not
+interpreted correctly within a template tag; also
+fixed in Py2.4.<a class="changeset-link headerlink reference internal" href="#change-693045b580eddfdc7e464ba0426b3495">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/190/">#190</a></p>
+</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="id3">
+<h2>0.8<a class="headerlink" href="#id3" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="change-0.8.1">
+<h3>0.8.1<a class="headerlink" href="#change-0.8.1" title="Permalink to this headline">¶</a></h3>
+Released: Fri May 24 2013<ul class="simple">
+<li><p id="change-0.8.1-0"><span class="target" id="change-bd4b9d8ffbf32fc1b15161268eefa4d3"><strong>[bug] </strong></span>Changed setup.py to skip installing markupsafe
+if Python version is &lt; 2.6 or is between 3.0 and
+less than 3.3, as Markupsafe now only supports 2.6-&gt;2.X,
+3.3-&gt;3.X.<a class="changeset-link headerlink reference internal" href="#change-bd4b9d8ffbf32fc1b15161268eefa4d3">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/216/">#216</a></p>
+</p>
+</li>
+<li><p id="change-0.8.1-1"><span class="target" id="change-422ca71aa24f94eb264fc0d653dc726e"><strong>[bug] </strong></span>Fixed regression where &#8220;entity&#8221; filter wasn&#8217;t
+converted for py3k properly (added tests.)<a class="changeset-link headerlink reference internal" href="#change-422ca71aa24f94eb264fc0d653dc726e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/214/">#214</a></p>
+</p>
+</li>
+<li><p id="change-0.8.1-2"><span class="target" id="change-32c8f2eaa85fc02c7f1908ade43391a6"><strong>[bug] </strong></span>Fixed bug where mako-render script wasn&#8217;t
+compatible with Py3k.<a class="changeset-link headerlink reference internal" href="#change-32c8f2eaa85fc02c7f1908ade43391a6">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/212/">#212</a></p>
+</p>
+</li>
+<li><p id="change-0.8.1-3"><span class="target" id="change-3493666706cc97f02aa1454a0bfa8b05"><strong>[bug] </strong></span>Cleaned up all the various deprecation/
+file warnings when running the tests under
+various Pythons with warnings turned on.<a class="changeset-link headerlink reference internal" href="#change-3493666706cc97f02aa1454a0bfa8b05">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/213/">#213</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.8.0">
+<h3>0.8.0<a class="headerlink" href="#change-0.8.0" title="Permalink to this headline">¶</a></h3>
+Released: Wed Apr 10 2013<ul class="simple">
+<li><p id="change-0.8.0-0"><span class="target" id="change-6b0ea675bf69869d3082ead0019268ac"><strong>[feature] </strong></span>Performance improvement to the
+&#8220;legacy&#8221; HTML escape feature, used for XML
+escaping and when markupsafe isn&#8217;t present,
+courtesy George Xie.<a class="changeset-link headerlink reference internal" href="#change-6b0ea675bf69869d3082ead0019268ac">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.8.0-1"><span class="target" id="change-9a75951207d1a79183ecde188ec6dc0f"><strong>[bug] </strong></span>Fixed bug whereby an exception in Python 3
+against a module compiled to the filesystem would
+fail trying to produce a RichTraceback due to the
+content being in bytes.<a class="changeset-link headerlink reference internal" href="#change-9a75951207d1a79183ecde188ec6dc0f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/209/">#209</a></p>
+</p>
+</li>
+<li><p id="change-0.8.0-2"><span class="target" id="change-c3d6a16577c7159388068ce214713af5"><strong>[bug] </strong></span>Change default for compile()-&gt;reserved_names
+from tuple to frozenset, as this is expected to be
+a set by default.<a class="changeset-link headerlink reference internal" href="#change-c3d6a16577c7159388068ce214713af5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/208/">#208</a></p>
+</p>
+</li>
+<li><p id="change-0.8.0-3"><span class="target" id="change-eaf9d70768b7b2e3bf37574dc5776ddb"><strong>[feature] </strong></span>Code has been reworked to support Python 2.4-&gt;
+Python 3.xx in place.  2to3 no longer needed.<a class="changeset-link headerlink reference internal" href="#change-eaf9d70768b7b2e3bf37574dc5776ddb">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.8.0-4"><span class="target" id="change-26eea0f7e4b73fcb7f112ad6fff7181d"><strong>[feature] </strong></span>Added lexer_cls argument to Template,
+TemplateLookup, allows alternate Lexer classes
+to be used.<a class="changeset-link headerlink reference internal" href="#change-26eea0f7e4b73fcb7f112ad6fff7181d">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.8.0-5"><span class="target" id="change-b7ef07a547af42dd2677a0ee710a88d8"><strong>[feature] </strong></span>Added future_imports parameter to Template
+and TemplateLookup, renders the __future__ header
+with desired capabilities at the top of the generated
+template module.  Courtesy Ben Trofatter.<a class="changeset-link headerlink reference internal" href="#change-b7ef07a547af42dd2677a0ee710a88d8">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="id4">
+<h2>0.7<a class="headerlink" href="#id4" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="change-0.7.3">
+<h3>0.7.3<a class="headerlink" href="#change-0.7.3" title="Permalink to this headline">¶</a></h3>
+Released: Wed Nov 7 2012<ul class="simple">
+<li><p id="change-0.7.3-0"><span class="target" id="change-5b7ac5083658b50ef3156f602a6fbc7f"><strong>[bug] </strong></span>legacy_html_escape function, used when
+Markupsafe isn&#8217;t installed, was using an inline-compiled
+regexp which causes major slowdowns on Python 3.3;
+is now precompiled.<a class="changeset-link headerlink reference internal" href="#change-5b7ac5083658b50ef3156f602a6fbc7f">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.7.3-1"><span class="target" id="change-591582542cc9469802a12b959ae762fa"><strong>[bug] </strong></span>AST supporting now supports tuple-packed
+function arguments inside pure-python def
+or lambda expressions.<a class="changeset-link headerlink reference internal" href="#change-591582542cc9469802a12b959ae762fa">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/201/">#201</a></p>
+</p>
+</li>
+<li><p id="change-0.7.3-2"><span class="target" id="change-3b3a50e075d4d15358ec199aa7c10fa0"><strong>[bug] </strong></span>Fixed Py3K bug in the Babel extension.<a class="changeset-link headerlink reference internal" href="#change-3b3a50e075d4d15358ec199aa7c10fa0">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.7.3-3"><span class="target" id="change-535675bd3ae6ed887cfebf09a83d4311"><strong>[bug] </strong></span>Fixed the &#8220;filter&#8221; attribute of the
+&lt;%text&gt; tag so that it pulls locally specified
+identifiers from the context the same
+way as that of &lt;%block&gt; and &lt;%filter&gt;.<a class="changeset-link headerlink reference internal" href="#change-535675bd3ae6ed887cfebf09a83d4311">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.7.3-4"><span class="target" id="change-618340e118c47998e9a6a21d3dfeab3c"><strong>[bug] </strong></span>Fixed bug in plugin loader to correctly
+raise exception when non-existent plugin
+is specified.<a class="changeset-link headerlink reference internal" href="#change-618340e118c47998e9a6a21d3dfeab3c">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.7.2">
+<h3>0.7.2<a class="headerlink" href="#change-0.7.2" title="Permalink to this headline">¶</a></h3>
+Released: Fri Jul 20 2012<ul class="simple">
+<li><p id="change-0.7.2-0"><span class="target" id="change-24885c510552de270fdab999df4d3ee3"><strong>[bug] </strong></span>Fixed regression in 0.7.1 where AST
+parsing for Py2.4 was broken.<a class="changeset-link headerlink reference internal" href="#change-24885c510552de270fdab999df4d3ee3">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/193/">#193</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.7.1">
+<h3>0.7.1<a class="headerlink" href="#change-0.7.1" title="Permalink to this headline">¶</a></h3>
+Released: Sun Jul 8 2012<ul class="simple">
+<li><p id="change-0.7.1-0"><span class="target" id="change-52ee3c2b0c1b4d4444ec4e93c7aafa2b"><strong>[feature] </strong></span>Control lines with no bodies will
+now succeed, as &#8220;pass&#8221; is added for these
+when no statements are otherwise present.
+Courtesy Ben Trofatter<a class="changeset-link headerlink reference internal" href="#change-52ee3c2b0c1b4d4444ec4e93c7aafa2b">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/146/">#146</a></p>
+</p>
+</li>
+<li><p id="change-0.7.1-1"><span class="target" id="change-149cdf4c14f9bacfe6dfa61ce8379d4e"><strong>[bug] </strong></span>Fixed some long-broken scoping behavior
+involving variables declared in defs and such,
+which only became apparent when
+the strict_undefined flag was turned on.<a class="changeset-link headerlink reference internal" href="#change-149cdf4c14f9bacfe6dfa61ce8379d4e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/192/">#192</a></p>
+</p>
+</li>
+<li><p id="change-0.7.1-2"><span class="target" id="change-28b06199f79ad5944ce27c6ca795912e"><strong>[bug] </strong></span>Can now use strict_undefined at the
+same time args passed to def() are used
+by other elements of the &lt;%def&gt; tag.<a class="changeset-link headerlink reference internal" href="#change-28b06199f79ad5944ce27c6ca795912e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/191/">#191</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.7.0">
+<h3>0.7.0<a class="headerlink" href="#change-0.7.0" title="Permalink to this headline">¶</a></h3>
+Released: Fri Mar 30 2012<ul class="simple">
+<li><p id="change-0.7.0-0"><span class="target" id="change-99281e61032772527b9b88fa8420e86a"><strong>[feature] </strong></span>Added new &#8220;loop&#8221; variable to templates,
+is provided within a % for block to provide
+info about the loop such as index, first/last,
+odd/even, etc.  A migration path is also provided
+for legacy templates via the &#8220;enable_loop&#8221; argument
+available on Template, TemplateLookup, and &lt;%page&gt;.
+Thanks to Ben Trofatter for all
+the work on this<a class="changeset-link headerlink reference internal" href="#change-99281e61032772527b9b88fa8420e86a">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/125/">#125</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-1"><span class="target" id="change-7e9210f880731443d88f862a56ff6279"><strong>[feature] </strong></span>Added a real check for &#8220;reserved&#8221;
+names, that is names which are never pulled
+from the context and cannot be passed to
+the template.render() method.  Current names
+are &#8220;context&#8221;, &#8220;loop&#8221;, &#8220;UNDEFINED&#8221;.<a class="changeset-link headerlink reference internal" href="#change-7e9210f880731443d88f862a56ff6279">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.7.0-2"><span class="target" id="change-e3c973cf437f4220015f2d5107b90685"><strong>[feature] </strong></span>The html_error_template() will now
+apply Pygments highlighting to the source
+code displayed in the traceback, if Pygments
+if available.  Courtesy Ben Trofatter<a class="changeset-link headerlink reference internal" href="#change-e3c973cf437f4220015f2d5107b90685">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/95/">#95</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-3"><span class="target" id="change-3fe398b17c8a48c37534222a31cb6e95"><strong>[feature] </strong></span>Added support for context managers,
+i.e. &#8220;% with x as e:/ % endwith&#8221; support.
+Courtesy Ben Trofatter<a class="changeset-link headerlink reference internal" href="#change-3fe398b17c8a48c37534222a31cb6e95">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/147/">#147</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-4"><span class="target" id="change-4071228d8de4b33e68b6655b7e55324b"><strong>[feature] </strong></span>Added class-level flag to CacheImpl
+&#8220;pass_context&#8221;; when True, the keyword argument
+&#8216;context&#8217; will be passed to get_or_create()
+containing the Mako Context object.<a class="changeset-link headerlink reference internal" href="#change-4071228d8de4b33e68b6655b7e55324b">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/185/">#185</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-5"><span class="target" id="change-9992c56ef372da93242c0408fde81739"><strong>[bug] </strong></span>Fixed some Py3K resource warnings due
+to filehandles being implicitly closed.<a class="changeset-link headerlink reference internal" href="#change-9992c56ef372da93242c0408fde81739">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/182/">#182</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-6"><span class="target" id="change-99f0e301249bf150b6a9aa25f7271be5"><strong>[bug] </strong></span>Fixed endless recursion bug when
+nesting multiple def-calls with content.
+Thanks to Jeff Dairiki.<a class="changeset-link headerlink reference internal" href="#change-99f0e301249bf150b6a9aa25f7271be5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/186/">#186</a></p>
+</p>
+</li>
+<li><p id="change-0.7.0-7"><span class="target" id="change-5a11b79be7c693f1faf8601f7f61ddfe"><strong>[feature] </strong></span>Added Jinja2 to the example
+benchmark suite, courtesy Vincent Férotin<a class="changeset-link headerlink reference internal" href="#change-5a11b79be7c693f1faf8601f7f61ddfe">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="older-versions">
+<h2>Older Versions<a class="headerlink" href="#older-versions" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="change-0.6.2">
+<h3>0.6.2<a class="headerlink" href="#change-0.6.2" title="Permalink to this headline">¶</a></h3>
+Released: Thu Feb 2 2012<ul class="simple">
+<li><p id="change-0.6.2-0"><span class="target" id="change-9b201e18db55b80dfdde3ccedde47930"><strong>[bug] </strong></span>The ${{&#8220;foo&#8221;:&#8221;bar&#8221;}} parsing issue is fixed!!
+The legendary Eevee has slain the dragon!.  Also fixes quoting issue
+at.<a class="changeset-link headerlink reference internal" href="#change-9b201e18db55b80dfdde3ccedde47930">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/86/">#86</a>, <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/20/">#20</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.6.1">
+<h3>0.6.1<a class="headerlink" href="#change-0.6.1" title="Permalink to this headline">¶</a></h3>
+Released: Sat Jan 28 2012<ul class="simple">
+<li><p id="change-0.6.1-0"><span class="target" id="change-cfec33b6e59137a9512e1f1395305774"><strong>[bug] </strong></span>Added special compatibility for the 0.5.0
+Cache() constructor, which was preventing file
+version checks and not allowing Mako 0.6 to
+recompile the module files.<a class="changeset-link headerlink reference internal" href="#change-cfec33b6e59137a9512e1f1395305774">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.6.0">
+<h3>0.6.0<a class="headerlink" href="#change-0.6.0" title="Permalink to this headline">¶</a></h3>
+Released: Sat Jan 21 2012<ul class="simple">
+<li><p id="change-0.6.0-0"><span class="target" id="change-2b9d5caf9d33544a386cc21b37a81524"><strong>[feature] </strong></span>Template caching has been converted into a plugin
+system, whereby the usage of Beaker is just the
+default plugin.   Template and TemplateLookup
+now accept a string &#8220;cache_impl&#8221; parameter which
+refers to the name of a cache plugin, defaulting
+to the name &#8216;beaker&#8217;.  New plugins can be
+registered as pkg_resources entrypoints under
+the group &#8220;mako.cache&#8221;, or registered directly
+using mako.cache.register_plugin().  The
+core plugin is the mako.cache.CacheImpl
+class.<a class="changeset-link headerlink reference internal" href="#change-2b9d5caf9d33544a386cc21b37a81524">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.6.0-1"><span class="target" id="change-6296089f9cbb6d381f1307e8c87903b3"><strong>[feature] </strong></span>Added support for Beaker cache regions
+in templates.   Usage of regions should be considered
+as superseding the very obsolete idea of passing in
+backend options, timeouts, etc. within templates.<a class="changeset-link headerlink reference internal" href="#change-6296089f9cbb6d381f1307e8c87903b3">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.6.0-2"><span class="target" id="change-0843fd024a1d50547e36cb04a4e8b78a"><strong>[feature] </strong></span>The &#8216;put&#8217; method on Cache is now
+&#8216;set&#8217;.  &#8216;put&#8217; is there for backwards compatibility.<a class="changeset-link headerlink reference internal" href="#change-0843fd024a1d50547e36cb04a4e8b78a">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.6.0-3"><span class="target" id="change-4f115c692e6156a01ef13450ebbd33dc"><strong>[feature] </strong></span>The &lt;%def&gt;, &lt;%block&gt; and &lt;%page&gt; tags now accept
+any argument named &#8220;cache_*&#8221;, and the key
+minus the &#8220;<a href="#id11"><span class="problematic" id="id12">cache_</span></a>&#8221; prefix will be passed as keyword
+arguments to the CacheImpl methods.<a class="changeset-link headerlink reference internal" href="#change-4f115c692e6156a01ef13450ebbd33dc">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.6.0-4"><span class="target" id="change-7a7b3c617612239ebce8bf870d937090"><strong>[feature] </strong></span>Template and TemplateLookup now accept an argument
+cache_args, which refers to a dictionary containing
+cache parameters.  The cache_dir, cache_url, cache_type,
+cache_timeout arguments are deprecated (will probably
+never be removed, however) and can be passed
+now as cache_args={&#8216;url&#8217;:&lt;some url&gt;, &#8216;type&#8217;:&#8217;memcached&#8217;,
+&#8216;timeout&#8217;:50, &#8216;dir&#8217;:&#8217;/path/to/some/directory&#8217;}<a class="changeset-link headerlink reference internal" href="#change-7a7b3c617612239ebce8bf870d937090">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.6.0-5"><span class="target" id="change-d114a1d74a7437b6c3aabe27990a6ed2"><strong>[feature/bug] </strong></span>Can now refer to context variables
+within extra arguments to &lt;%block&gt;, &lt;%def&gt;, i.e.
+&lt;%block name=&#8221;foo&#8221; cache_key=&#8221;${somekey}&#8221;&gt;.
+Filters can also be used in this way, i.e.
+&lt;%def name=&#8221;foo()&#8221; filter=&#8221;myfilter&#8221;&gt;
+then template.render(myfilter=some_callable)<a class="changeset-link headerlink reference internal" href="#change-d114a1d74a7437b6c3aabe27990a6ed2">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/180/">#180</a></p>
+</p>
+</li>
+<li><p id="change-0.6.0-6"><span class="target" id="change-9f5fae46c69a1c75f7490adf375f8050"><strong>[feature] </strong></span>Added &#8220;&#8211;var name=value&#8221; option to the mako-render
+script, allows passing of kw to the template from
+the command line.<a class="changeset-link headerlink reference internal" href="#change-9f5fae46c69a1c75f7490adf375f8050">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/178/">#178</a></p>
+</p>
+</li>
+<li><p id="change-0.6.0-7"><span class="target" id="change-ee72323bae6ecd6f7f0412b687fea6b1"><strong>[feature] </strong></span>Added module_writer argument to Template,
+TemplateLookup, allows a callable to be passed which
+takes over the writing of the template&#8217;s module source
+file, so that special environment-specific steps
+can be taken.<a class="changeset-link headerlink reference internal" href="#change-ee72323bae6ecd6f7f0412b687fea6b1">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/181/">#181</a></p>
+</p>
+</li>
+<li><p id="change-0.6.0-8"><span class="target" id="change-460448904caed525985e90d2fe23dc6f"><strong>[bug] </strong></span>The exception message in the html_error_template
+is now escaped with the HTML filter.<a class="changeset-link headerlink reference internal" href="#change-460448904caed525985e90d2fe23dc6f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/142/">#142</a></p>
+</p>
+</li>
+<li><p id="change-0.6.0-9"><span class="target" id="change-0f53470e3d2ace00fedfec05980570bf"><strong>[bug] </strong></span>Added &#8220;white-space:pre&#8221; style to html_error_template()
+for code blocks so that indentation is preserved<a class="changeset-link headerlink reference internal" href="#change-0f53470e3d2ace00fedfec05980570bf">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/173/">#173</a></p>
+</p>
+</li>
+<li><p id="change-0.6.0-10"><span class="target" id="change-a268e715c3a48b1d2e6651948d9f6739"><strong>[bug] </strong></span>The &#8220;benchmark&#8221; example is now Python 3 compatible
+(even though several of those old template libs aren&#8217;t
+available on Py3K, so YMMV)<a class="changeset-link headerlink reference internal" href="#change-a268e715c3a48b1d2e6651948d9f6739">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/175/">#175</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.5.0">
+<h3>0.5.0<a class="headerlink" href="#change-0.5.0" title="Permalink to this headline">¶</a></h3>
+Released: Wed Sep 28 2011<ul class="simple">
+<li><p id="change-0.5.0-0"><span class="target" id="change-d25af015b75fa0212ca7997ee8f85ee1"></span>A Template is explicitly disallowed
+from having a url that normalizes to relative outside
+of the root.   That is, if the Lookup is based
+at /home/mytemplates, an include that would place
+the ultimate template at
+/home/mytemplates/../some_other_directory,
+i.e. outside of /home/mytemplates,
+is disallowed.   This usage was never intended
+despite the lack of an explicit check.
+The main issue this causes
+is that module files can be written outside
+of the module root (or raise an error, if file perms aren&#8217;t
+set up), and can also lead to the same template being
+cached in the lookup under multiple, relative roots.
+TemplateLookup instead has always supported multiple
+file roots for this purpose.<a class="changeset-link headerlink reference internal" href="#change-d25af015b75fa0212ca7997ee8f85ee1">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/174/">#174</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.4.2">
+<h3>0.4.2<a class="headerlink" href="#change-0.4.2" title="Permalink to this headline">¶</a></h3>
+Released: Fri Aug 5 2011<ul class="simple">
+<li><p id="change-0.4.2-0"><span class="target" id="change-0d5b25f911cea09b48a3cea73dc8b0ad"></span>Fixed bug regarding &lt;%call&gt;/def calls w/ content
+whereby the identity of the &#8220;caller&#8221; callable
+inside the &lt;%def&gt; would be corrupted by the
+presence of another &lt;%call&gt; in the same block.<a class="changeset-link headerlink reference internal" href="#change-0d5b25f911cea09b48a3cea73dc8b0ad">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/170/">#170</a></p>
+</p>
+</li>
+<li><p id="change-0.4.2-1"><span class="target" id="change-131badc51e07746b68123281fa7380a3"></span>Fixed the babel plugin to accommodate &lt;%block&gt;<a class="changeset-link headerlink reference internal" href="#change-131badc51e07746b68123281fa7380a3">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/169/">#169</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.4.1">
+<h3>0.4.1<a class="headerlink" href="#change-0.4.1" title="Permalink to this headline">¶</a></h3>
+Released: Wed Apr 6 2011<ul class="simple">
+<li><p id="change-0.4.1-0"><span class="target" id="change-464bf94bda97d9dfacb13c327c30f669"></span>New tag: &lt;%block&gt;.  A variant on &lt;%def&gt; that
+evaluates its contents in-place.
+Can be named or anonymous,
+the named version is intended for inheritance
+layouts where any given section can be
+surrounded by the &lt;%block&gt; tag in order for
+it to become overrideable by inheriting
+templates, without the need to specify a
+top-level &lt;%def&gt; plus explicit call.
+Modified scoping and argument rules as well as a
+more strictly enforced usage scheme make it ideal
+for this purpose without at all replacing most
+other things that defs are still good for.
+Lots of new docs.<a class="changeset-link headerlink reference internal" href="#change-464bf94bda97d9dfacb13c327c30f669">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/164/">#164</a></p>
+</p>
+</li>
+<li><p id="change-0.4.1-1"><span class="target" id="change-e5f029ea7d0f9f821c25e308c354006c"></span>a slight adjustment to the &#8220;highlight&#8221; logic
+for generating template bound stacktraces.
+Will stick to known template source lines
+without any extra guessing.<a class="changeset-link headerlink reference internal" href="#change-e5f029ea7d0f9f821c25e308c354006c">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/165/">#165</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.4.0">
+<h3>0.4.0<a class="headerlink" href="#change-0.4.0" title="Permalink to this headline">¶</a></h3>
+Released: Sun Mar 6 2011<ul class="simple">
+<li><p id="change-0.4.0-0"><span class="target" id="change-24faf88ef298503c8544d93f64092984"></span>A 20% speedup for a basic two-page
+inheritance setup rendering
+a table of escaped data
+(see <a class="reference external" href="http://techspot.zzzeek.org/2010/11/19/quick-mako-vs.-jinja-speed-test/">http://techspot.zzzeek.org/2010/11/19/quick-mako-vs.-jinja-speed-test/</a>).
+A few configurational changes which
+affect those in the I-don&#8217;t-do-unicode
+camp should be noted below.<a class="changeset-link headerlink reference internal" href="#change-24faf88ef298503c8544d93f64092984">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.4.0-1"><span class="target" id="change-4e7e70e466a6b372ba2085724f0c0dcc"></span>The FastEncodingBuffer is now used
+by default instead of cStringIO or StringIO,
+regardless of whether output_encoding
+is set to None or not.  FEB is faster than
+both.  Only StringIO allows bytestrings
+of unknown encoding to pass right
+through, however - while it is of course
+not recommended to send bytestrings of unknown
+encoding to the output stream, this
+mode of usage can be re-enabled by
+setting the flag bytestring_passthrough
+to True.<a class="changeset-link headerlink reference internal" href="#change-4e7e70e466a6b372ba2085724f0c0dcc">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.4.0-2"><span class="target" id="change-b23a68d0fccb2b8b34d1a727397669a5"></span>disable_unicode mode requires that
+output_encoding be set to None - it also
+forces the bytestring_passthrough flag
+to True.<a class="changeset-link headerlink reference internal" href="#change-b23a68d0fccb2b8b34d1a727397669a5">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.4.0-3"><span class="target" id="change-0237ae4dc8e41beca5fe6392fbd68f4e"></span>the &lt;%namespace&gt; tag raises an error
+if the &#8216;template&#8217; and &#8216;module&#8217; attributes
+are specified at the same time in
+one tag.  A different class is used
+for each case which allows a reduction in
+runtime conditional logic and function
+call overhead.<a class="changeset-link headerlink reference internal" href="#change-0237ae4dc8e41beca5fe6392fbd68f4e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/156/">#156</a></p>
+</p>
+</li>
+<li><p id="change-0.4.0-4"><span class="target" id="change-a23ec787ca226d13d1115300493de625"></span>the keys() in the Context, as well as
+it&#8217;s internal _data dictionary, now
+include just what was specified to
+render() as well as Mako builtins
+&#8216;caller&#8217;, &#8216;capture&#8217;.  The contents
+of __builtin__ are no longer copied.
+Thanks to Daniel Lopez for pointing
+this out.<a class="changeset-link headerlink reference internal" href="#change-a23ec787ca226d13d1115300493de625">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/159/">#159</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.6">
+<h3>0.3.6<a class="headerlink" href="#change-0.3.6" title="Permalink to this headline">¶</a></h3>
+Released: Sat Nov 13 2010<ul class="simple">
+<li><p id="change-0.3.6-0"><span class="target" id="change-ba90f64b03241356193e4e9fef913f63"></span>Documentation is on Sphinx.<a class="changeset-link headerlink reference internal" href="#change-ba90f64b03241356193e4e9fef913f63">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/126/">#126</a></p>
+</p>
+</li>
+<li><p id="change-0.3.6-1"><span class="target" id="change-6fa26d3bfceaff55a258fb53794e6313"></span>Beaker is now part of &#8220;extras&#8221; in
+setup.py instead of &#8220;install_requires&#8221;.
+This to produce a lighter weight install
+for those who don&#8217;t use the caching
+as well as to conform to Pyramid
+deployment practices.<a class="changeset-link headerlink reference internal" href="#change-6fa26d3bfceaff55a258fb53794e6313">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/154/">#154</a></p>
+</p>
+</li>
+<li><p id="change-0.3.6-2"><span class="target" id="change-add98954fc4473f31b998fd2931c0c2c"></span>The Beaker import (or attempt thereof)
+is delayed until actually needed;
+this to remove the performance penalty
+from startup, particularly for
+&#8220;single execution&#8221; environments
+such as shell scripts.<a class="changeset-link headerlink reference internal" href="#change-add98954fc4473f31b998fd2931c0c2c">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/153/">#153</a></p>
+</p>
+</li>
+<li><p id="change-0.3.6-3"><span class="target" id="change-6f50239252b9579a5a952a529cce3c8f"></span>Patch to lexer to not generate an empty
+&#8216;&#8217; write in the case of backslash-ended
+lines.<a class="changeset-link headerlink reference internal" href="#change-6f50239252b9579a5a952a529cce3c8f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/155/">#155</a></p>
+</p>
+</li>
+<li><p id="change-0.3.6-4"><span class="target" id="change-9007a381dea9bd8a980aaf646712fa95"></span>Fixed missing <a href="#id5"><span class="problematic" id="id6">**</span></a>extra collection in
+setup.py which prevented setup.py
+from running 2to3 on install.<a class="changeset-link headerlink reference internal" href="#change-9007a381dea9bd8a980aaf646712fa95">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/148/">#148</a></p>
+</p>
+</li>
+<li><p id="change-0.3.6-5"><span class="target" id="change-d94085d95e60f190e30871ff1c472781"></span>New flag on Template, TemplateLookup -
+strict_undefined=True, will cause
+variables not found in the context to
+raise a NameError immediately, instead of
+defaulting to the UNDEFINED value.<a class="changeset-link headerlink reference internal" href="#change-d94085d95e60f190e30871ff1c472781">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.6-6"><span class="target" id="change-c7f4bd0543dcd61c301325887e5e868f"></span>The range of Python identifiers that
+are considered &#8220;undefined&#8221;, meaning they
+are pulled from the context, has been
+trimmed back to not include variables
+declared inside of expressions (i.e. from
+list comprehensions), as well as
+in the argument list of lambdas.  This
+to better support the strict_undefined
+feature.  The change should be
+fully backwards-compatible but involved
+a little bit of tinkering in the AST code,
+which hadn&#8217;t really been touched for
+a couple of years, just FYI.<a class="changeset-link headerlink reference internal" href="#change-c7f4bd0543dcd61c301325887e5e868f">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.5">
+<h3>0.3.5<a class="headerlink" href="#change-0.3.5" title="Permalink to this headline">¶</a></h3>
+Released: Sun Oct 24 2010<ul class="simple">
+<li><p id="change-0.3.5-0"><span class="target" id="change-4f131130d9a9c7503c1285d76453772e"></span>The &lt;%namespace&gt; tag allows expressions
+for the <cite>file</cite> argument, i.e. with ${}.
+The <cite>context</cite> variable, if needed,
+must be referenced explicitly.<a class="changeset-link headerlink reference internal" href="#change-4f131130d9a9c7503c1285d76453772e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/141/">#141</a></p>
+</p>
+</li>
+<li><p id="change-0.3.5-1"><span class="target" id="change-9260777204b90b5d2ef50591a9321f7f"></span>${} expressions embedded in tags,
+such as &lt;%foo:bar x=&#8221;${...}&#8221;&gt;, now
+allow multiline Python expressions.<a class="changeset-link headerlink reference internal" href="#change-9260777204b90b5d2ef50591a9321f7f">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.5-2"><span class="target" id="change-b17753b5fc8d7a350d6c9d07d9e8698b"></span>Fixed previously non-covered regular
+expression, such that using a ${} expression
+inside of a tag element that doesn&#8217;t allow
+them raises a CompileException instead of
+silently failing.<a class="changeset-link headerlink reference internal" href="#change-b17753b5fc8d7a350d6c9d07d9e8698b">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.5-3"><span class="target" id="change-26a430536a4ef0aea275166c8ffead73"></span>Added a try/except around &#8220;import markupsafe&#8221;.
+This to support GAE which can&#8217;t run markupsafe. No idea whatsoever if the
+install_requires in setup.py also breaks GAE,
+couldn&#8217;t get an answer on this.<a class="changeset-link headerlink reference internal" href="#change-26a430536a4ef0aea275166c8ffead73">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/151/">#151</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.4">
+<h3>0.3.4<a class="headerlink" href="#change-0.3.4" title="Permalink to this headline">¶</a></h3>
+Released: Tue Jun 22 2010<ul class="simple">
+<li><p id="change-0.3.4-0"><span class="target" id="change-42a2094bdc5fa56af96f16ead2ea7a85"></span>Now using MarkupSafe for HTML escaping,
+i.e. in place of cgi.escape().  Faster
+C-based implementation and also escapes
+single quotes for additional security.
+Supports the __html__ attribute for
+the given expression as well.<p>When using &#8220;disable_unicode&#8221; mode,
+a pure Python HTML escaper function
+is used which also quotes single quotes.</p>
+<p>Note that Pylons by default doesn&#8217;t
+use Mako&#8217;s filter - check your
+environment.py file.</p>
+<a class="changeset-link headerlink reference internal" href="#change-42a2094bdc5fa56af96f16ead2ea7a85">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.4-1"><span class="target" id="change-c6b3b30f351cb6e68140eb7ff8ec9339"></span>Fixed call to &#8220;unicode.strip&#8221; in
+exceptions.text_error_template which
+is not Py3k compatible.<a class="changeset-link headerlink reference internal" href="#change-c6b3b30f351cb6e68140eb7ff8ec9339">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/137/">#137</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.3">
+<h3>0.3.3<a class="headerlink" href="#change-0.3.3" title="Permalink to this headline">¶</a></h3>
+Released: Mon May 31 2010<ul class="simple">
+<li><p id="change-0.3.3-0"><span class="target" id="change-bc6d3046e00861b0a815a3373dc21489"></span>Added conditional to RichTraceback
+such that if no traceback is passed
+and sys.exc_info() has been reset,
+the formatter just returns blank
+for the &#8220;traceback&#8221; portion.<a class="changeset-link headerlink reference internal" href="#change-bc6d3046e00861b0a815a3373dc21489">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/135/">#135</a></p>
+</p>
+</li>
+<li><p id="change-0.3.3-1"><span class="target" id="change-7398285484aa0b44f7cb4314d635343f"></span>Fixed sometimes incorrect usage of
+exc.__class__.__name__
+in html/text error templates when using
+Python 2.4<a class="changeset-link headerlink reference internal" href="#change-7398285484aa0b44f7cb4314d635343f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/131/">#131</a></p>
+</p>
+</li>
+<li><p id="change-0.3.3-2"><span class="target" id="change-fc38c54c185a03815b882ae0235dd0ec"></span>Fixed broken &#64;property decorator on
+template.last_modified<a class="changeset-link headerlink reference internal" href="#change-fc38c54c185a03815b882ae0235dd0ec">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.3-3"><span class="target" id="change-e351477ece87f96ce3b8dcbe2093927e"></span>Fixed error formatting when a stacktrace
+line contains no line number, as in when
+inside an eval/exec-generated function.<a class="changeset-link headerlink reference internal" href="#change-e351477ece87f96ce3b8dcbe2093927e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/132/">#132</a></p>
+</p>
+</li>
+<li><p id="change-0.3.3-4"><span class="target" id="change-8465d2f035b94270f61add8d37b484b6"></span>When a .py is being created, the tempfile
+where the source is stored temporarily is
+now made in the same directory as that of
+the .py file.  This ensures that the two
+files share the same filesystem, thus
+avoiding cross-filesystem synchronization
+issues.  Thanks to Charles Cazabon.<a class="changeset-link headerlink reference internal" href="#change-8465d2f035b94270f61add8d37b484b6">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.2">
+<h3>0.3.2<a class="headerlink" href="#change-0.3.2" title="Permalink to this headline">¶</a></h3>
+Released: Thu Mar 11 2010<ul class="simple">
+<li><p id="change-0.3.2-0"><span class="target" id="change-99967455a3839ef3b397981de9a7b95e"></span>Calling a def from the top, via
+template.get_def(...).render() now checks the
+argument signature the same way as it did in
+0.2.5, so that TypeError is not raised.
+reopen of<a class="changeset-link headerlink reference internal" href="#change-99967455a3839ef3b397981de9a7b95e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/116/">#116</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.1">
+<h3>0.3.1<a class="headerlink" href="#change-0.3.1" title="Permalink to this headline">¶</a></h3>
+Released: Sun Mar 7 2010<ul class="simple">
+<li><p id="change-0.3.1-0"><span class="target" id="change-10954fab107bd4f83df29f01b7a1db1a"></span>Fixed incorrect dir name in setup.py<a class="changeset-link headerlink reference internal" href="#change-10954fab107bd4f83df29f01b7a1db1a">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/129/">#129</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.3.0">
+<h3>0.3.0<a class="headerlink" href="#change-0.3.0" title="Permalink to this headline">¶</a></h3>
+Released: Fri Mar 5 2010<ul class="simple">
+<li><p id="change-0.3.0-0"><span class="target" id="change-6696642b595c45f48c676d4321c80f4e"></span>Python 2.3 support is dropped.<a class="changeset-link headerlink reference internal" href="#change-6696642b595c45f48c676d4321c80f4e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/123/">#123</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-1"><span class="target" id="change-4ac95d25798d0af74fcbbda6805f4117"></span>Python 3 support is added ! See README.py3k
+for installation and testing notes.<a class="changeset-link headerlink reference internal" href="#change-4ac95d25798d0af74fcbbda6805f4117">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/119/">#119</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-2"><span class="target" id="change-580b71306f06a35525d94dbbc866dff5"></span>Unit tests now run with nose.<a class="changeset-link headerlink reference internal" href="#change-580b71306f06a35525d94dbbc866dff5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/127/">#127</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-3"><span class="target" id="change-254948cdd845470bc120bd9537620480"></span>Source code escaping has been simplified.
+In particular, module source files are now
+generated with the Python &#8220;magic encoding
+comment&#8221;, and source code is passed through
+mostly unescaped, except for that code which
+is regenerated from parsed Python source.
+This fixes usage of unicode in
+&lt;%namespace:defname&gt; tags.<a class="changeset-link headerlink reference internal" href="#change-254948cdd845470bc120bd9537620480">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/99/">#99</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-4"><span class="target" id="change-b8d940f383df524cbcb09a4aa8785055"></span>RichTraceback(), html_error_template().render(),
+text_error_template().render() now accept &#8220;error&#8221;
+and &#8220;traceback&#8221; as optional arguments, and
+these are now actually used.<a class="changeset-link headerlink reference internal" href="#change-b8d940f383df524cbcb09a4aa8785055">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/122/">#122</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-5"><span class="target" id="change-c8b4a5c26a15e967ede79e6b3fc12673"></span>The exception output generated when
+format_exceptions=True will now be as a Python
+unicode if it occurred during render_unicode(),
+or an encoded string if during render().<a class="changeset-link headerlink reference internal" href="#change-c8b4a5c26a15e967ede79e6b3fc12673">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.3.0-6"><span class="target" id="change-3685f613780a1778275c5a1c06ffd14d"></span>A percent sign can be emitted as the first
+non-whitespace character on a line by escaping
+it as in &#8220;%%&#8221;.<a class="changeset-link headerlink reference internal" href="#change-3685f613780a1778275c5a1c06ffd14d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/112/">#112</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-7"><span class="target" id="change-0b344165d32f9da5eebc93d2e36b751d"></span>Template accepts empty control structure, i.e.
+% if: %endif, etc.<a class="changeset-link headerlink reference internal" href="#change-0b344165d32f9da5eebc93d2e36b751d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/94/">#94</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-8"><span class="target" id="change-4e41287388f6da51881b95c2fc27ff9d"></span>The &lt;%page args&gt; tag can now be used in a base
+inheriting template - the full set of render()
+arguments are passed down through the inherits
+chain.  Undeclared arguments go into <a href="#id7"><span class="problematic" id="id8">**</span></a>pageargs
+as usual.<a class="changeset-link headerlink reference internal" href="#change-4e41287388f6da51881b95c2fc27ff9d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/116/">#116</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-9"><span class="target" id="change-8f84b7484a62925c50f48334ee6a9756"></span>defs declared within a &lt;%namespace&gt; section, an
+uncommon feature, have been improved.  The defs
+no longer get doubly-rendered in the body() scope,
+and now allow local variable assignment without
+breakage.<a class="changeset-link headerlink reference internal" href="#change-8f84b7484a62925c50f48334ee6a9756">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/109/">#109</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-10"><span class="target" id="change-b282c56c8f7389792db2e50b26f4d871"></span>Windows paths are handled correctly if a Template
+is passed only an absolute filename (i.e. with c:
+drive etc.)  and no URI - the URI is converted
+to a forward-slash path and module_directory
+is treated as a windows path.<a class="changeset-link headerlink reference internal" href="#change-b282c56c8f7389792db2e50b26f4d871">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/128/">#128</a></p>
+</p>
+</li>
+<li><p id="change-0.3.0-11"><span class="target" id="change-5ea16c786c94f8e04c3e8f5ea3a3b423"></span>TemplateLookup raises TopLevelLookupException for
+a given path that is a directory, not a filename,
+instead of passing through to the template to
+generate IOError.<a class="changeset-link headerlink reference internal" href="#change-5ea16c786c94f8e04c3e8f5ea3a3b423">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/73/">#73</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.6">
+<h3>0.2.6<a class="headerlink" href="#change-0.2.6" title="Permalink to this headline">¶</a></h3>
+no release date<ul class="simple">
+<li><p id="change-0.2.6-0"><span class="target" id="change-d1e4c26171841e1c4fbc0e3f56d0bf96"></span>Fix mako function decorators to preserve the
+original function&#8217;s name in all cases. Patch
+from Scott Torborg.<a class="changeset-link headerlink reference internal" href="#change-d1e4c26171841e1c4fbc0e3f56d0bf96">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.6-1"><span class="target" id="change-d1851b428e06541460cbd70bd5c6131f"></span>Support the &lt;%namespacename:defname&gt; syntax in
+the babel extractor.<a class="changeset-link headerlink reference internal" href="#change-d1851b428e06541460cbd70bd5c6131f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/118/">#118</a></p>
+</p>
+</li>
+<li><p id="change-0.2.6-2"><span class="target" id="change-398bff9c71f24a9ff6c180d0a05018b4"></span>Further fixes to unicode handling of .py files with the
+html_error_template.<a class="changeset-link headerlink reference internal" href="#change-398bff9c71f24a9ff6c180d0a05018b4">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/88/">#88</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.5">
+<h3>0.2.5<a class="headerlink" href="#change-0.2.5" title="Permalink to this headline">¶</a></h3>
+Released: Mon Sep  7 2009<ul class="simple">
+<li><p id="change-0.2.5-0"><span class="target" id="change-c79258c92155abe15ab0f249e56d36f8"></span>Added a &#8220;decorator&#8221; kw argument to &lt;%def&gt;,
+allows custom decoration functions to wrap
+rendering callables.  Mainly intended for
+custom caching algorithms, not sure what
+other uses there may be (but there may be).
+Examples are in the &#8220;filtering&#8221; docs.<a class="changeset-link headerlink reference internal" href="#change-c79258c92155abe15ab0f249e56d36f8">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.5-1"><span class="target" id="change-4807d411f1e3cfa18c32decd089cab90"></span>When Mako creates subdirectories in which
+to store templates, it uses the more
+permissive mode of 0775 instead of 0750,
+helping out with certain multi-process
+scenarios. Note that the mode is always
+subject to the restrictions of the existing
+umask.<a class="changeset-link headerlink reference internal" href="#change-4807d411f1e3cfa18c32decd089cab90">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/101/">#101</a></p>
+</p>
+</li>
+<li><p id="change-0.2.5-2"><span class="target" id="change-8af1bb98b05bf16f832aaea1707f20fb"></span>Fixed namespace.__getattr__() to raise
+AttributeError on attribute not found
+instead of RuntimeError.<a class="changeset-link headerlink reference internal" href="#change-8af1bb98b05bf16f832aaea1707f20fb">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/104/">#104</a></p>
+</p>
+</li>
+<li><p id="change-0.2.5-3"><span class="target" id="change-ca99b7588c54e67a73569aad8e06c0ce"></span>Added last_modified accessor to Template,
+returns the time.time() when the module
+was created.<a class="changeset-link headerlink reference internal" href="#change-ca99b7588c54e67a73569aad8e06c0ce">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/97/">#97</a></p>
+</p>
+</li>
+<li><p id="change-0.2.5-4"><span class="target" id="change-d18e860647e39ec0f72eeb38740111cb"></span>Fixed lexing support for whitespace
+around &#8216;=&#8217; sign in defs.<a class="changeset-link headerlink reference internal" href="#change-d18e860647e39ec0f72eeb38740111cb">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/102/">#102</a></p>
+</p>
+</li>
+<li><p id="change-0.2.5-5"><span class="target" id="change-602d7edb91f7f94638496e5544c0b8ee"></span>Removed errant &#8220;lower()&#8221; in the lexer which
+was causing tags to compile with
+case-insensitive names, thus messing up
+custom &lt;%call&gt; names.<a class="changeset-link headerlink reference internal" href="#change-602d7edb91f7f94638496e5544c0b8ee">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/108/">#108</a></p>
+</p>
+</li>
+<li><p id="change-0.2.5-6"><span class="target" id="change-9980854809a31d4b404208e286a70d41"></span>added &#8220;mako.__version__&#8221; attribute to
+the base module.<a class="changeset-link headerlink reference internal" href="#change-9980854809a31d4b404208e286a70d41">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/110/">#110</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.4">
+<h3>0.2.4<a class="headerlink" href="#change-0.2.4" title="Permalink to this headline">¶</a></h3>
+Released: Tue Dec 23 2008<ul class="simple">
+<li><p id="change-0.2.4-0"><span class="target" id="change-4854b3f9b6cb5776937ab0695fff1435"></span>Fixed compatibility with Jython 2.5b1.<a class="changeset-link headerlink reference internal" href="#change-4854b3f9b6cb5776937ab0695fff1435">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.3">
+<h3>0.2.3<a class="headerlink" href="#change-0.2.3" title="Permalink to this headline">¶</a></h3>
+Released: Sun Nov 23 2008<ul class="simple">
+<li><p id="change-0.2.3-0"><span class="target" id="change-37bce8b359a8e44e7b91c12652eee2b8"></span>the &lt;%namespacename:defname&gt; syntax described at
+<a class="reference external" href="http://techspot.zzzeek.org/?p=28">http://techspot.zzzeek.org/?p=28</a> has now
+been added as a built in syntax, and is recommended
+as a more modern syntax versus &lt;%call expr=&#8221;expression&#8221;&gt;.
+The %call tag itself will always remain,
+with &lt;%namespacename:defname&gt; presenting a more HTML-like
+alternative to calling defs, both plain and
+nested.  Many examples of the new syntax are in the
+&#8220;Calling a def with embedded content&#8221; section
+of the docs.<a class="changeset-link headerlink reference internal" href="#change-37bce8b359a8e44e7b91c12652eee2b8">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-1"><span class="target" id="change-35a6c7b85a04372530f2be1805959799"></span>added support for Jython 2.5.<a class="changeset-link headerlink reference internal" href="#change-35a6c7b85a04372530f2be1805959799">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-2"><span class="target" id="change-f8334ef0e1678c06e374ba1a0d3931cd"></span>cache module now uses Beaker&#8217;s CacheManager
+object directly, so that all cache types are included.
+memcached is available as both &#8220;ext:memcached&#8221; and
+&#8220;memcached&#8221;, the latter for backwards compatibility.<a class="changeset-link headerlink reference internal" href="#change-f8334ef0e1678c06e374ba1a0d3931cd">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-3"><span class="target" id="change-ed3a6c17f2cbd83a593de4d2724a6a84"></span>added &#8220;cache&#8221; accessor to Template, Namespace.
+e.g.  ${local.cache.get(&#8216;somekey&#8217;)} or
+template.cache.invalidate_body()<a class="changeset-link headerlink reference internal" href="#change-ed3a6c17f2cbd83a593de4d2724a6a84">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-4"><span class="target" id="change-70e586f7cde0ac7b344e8e8986c58b9a"></span>added &#8220;cache_enabled=True&#8221; flag to Template,
+TemplateLookup.  Setting this to False causes cache
+operations to &#8220;pass through&#8221; and execute every time;
+this flag should be integrated in Pylons with its own
+cache_enabled configuration setting.<a class="changeset-link headerlink reference internal" href="#change-70e586f7cde0ac7b344e8e8986c58b9a">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-5"><span class="target" id="change-fe9e64fb24df2528a185b3317fce35fb"></span>the Cache object now supports invalidate_def(name),
+invalidate_body(), invalidate_closure(name),
+invalidate(key), which will remove the given key
+from the cache, if it exists.  The cache arguments
+(i.e. storage type) are derived from whatever has
+been already persisted for that template.<a class="changeset-link headerlink reference internal" href="#change-fe9e64fb24df2528a185b3317fce35fb">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/92/">#92</a></p>
+</p>
+</li>
+<li><p id="change-0.2.3-6"><span class="target" id="change-fc8e53f27e96f1442a8e85b52988d4c4"></span>For cache changes to work fully, Beaker 1.1 is required.
+1.0.1 and up will work as well with the exception of
+cache expiry.  Note that Beaker 1.1 is <strong>required</strong>
+for applications which use dynamically generated keys,
+since previous versions will permanently store state in memory
+for each individual key, thus consuming all available
+memory for an arbitrarily large number of distinct
+keys.<a class="changeset-link headerlink reference internal" href="#change-fc8e53f27e96f1442a8e85b52988d4c4">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-7"><span class="target" id="change-6215a523e4a44009dd085141f89bb1ea"></span>fixed bug whereby an &lt;%included&gt; template with
+&lt;%page&gt; args named the same as a __builtin__ would not
+honor the default value specified in &lt;%page&gt;<a class="changeset-link headerlink reference internal" href="#change-6215a523e4a44009dd085141f89bb1ea">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/93/">#93</a></p>
+</p>
+</li>
+<li><p id="change-0.2.3-8"><span class="target" id="change-c269853926ff7f52a94ddf94c705cff7"></span>fixed the html_error_template not handling tracebacks from
+normal .py files with a magic encoding comment<a class="changeset-link headerlink reference internal" href="#change-c269853926ff7f52a94ddf94c705cff7">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/88/">#88</a></p>
+</p>
+</li>
+<li><p id="change-0.2.3-9"><span class="target" id="change-87c44d844a042343e22d55e2a2b8d4e9"></span>RichTraceback() now accepts an optional traceback object
+to be used in place of sys.exc_info()[2].  html_error_template()
+and text_error_template() accept an optional
+render()-time argument &#8220;traceback&#8221; which is passed to the
+RichTraceback object.<a class="changeset-link headerlink reference internal" href="#change-87c44d844a042343e22d55e2a2b8d4e9">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-10"><span class="target" id="change-7a562520a57d62460f54fadac0d94100"></span>added ModuleTemplate class, which allows the construction
+of a Template given a Python module generated by a previous
+Template.   This allows Python modules alone to be used
+as templates with no compilation step.   Source code
+and template source are optional but allow error reporting
+to work correctly.<a class="changeset-link headerlink reference internal" href="#change-7a562520a57d62460f54fadac0d94100">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.3-11"><span class="target" id="change-6e699add881ad62aa72c44efa3899ae5"></span>fixed Python 2.3 compat. in mako.pyparser<a class="changeset-link headerlink reference internal" href="#change-6e699add881ad62aa72c44efa3899ae5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/90/">#90</a></p>
+</p>
+</li>
+<li><p id="change-0.2.3-12"><span class="target" id="change-54c464fa5c94b0aba86b2b99d13f9eb4"></span>fix Babel 0.9.3 compatibility; stripping comment tags is now
+optional (and enabled by default).<a class="changeset-link headerlink reference internal" href="#change-54c464fa5c94b0aba86b2b99d13f9eb4">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.2">
+<h3>0.2.2<a class="headerlink" href="#change-0.2.2" title="Permalink to this headline">¶</a></h3>
+Released: Mon Jun 23 2008<ul class="simple">
+<li><p id="change-0.2.2-0"><span class="target" id="change-df54b04a766bd7511f1b92e438573fdf"></span>cached blocks now use the current context when rendering
+an expired section, instead of the original context
+passed in<a class="changeset-link headerlink reference internal" href="#change-df54b04a766bd7511f1b92e438573fdf">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/87/">#87</a></p>
+</p>
+</li>
+<li><p id="change-0.2.2-1"><span class="target" id="change-c6f8379cfe314e3a5a202e256699d586"></span>fixed a critical issue regarding caching, whereby
+a cached block would raise an error when called within a
+cache-refresh operation that was initiated after the
+initiating template had completed rendering.<a class="changeset-link headerlink reference internal" href="#change-c6f8379cfe314e3a5a202e256699d586">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.1">
+<h3>0.2.1<a class="headerlink" href="#change-0.2.1" title="Permalink to this headline">¶</a></h3>
+Released: Mon Jun 16 2008<ul class="simple">
+<li><p id="change-0.2.1-0"><span class="target" id="change-908eed7e4807846bda8b7883b98f4a02"></span>fixed bug where &#8216;output_encoding&#8217; parameter would prevent
+render_unicode() from returning a unicode object.<a class="changeset-link headerlink reference internal" href="#change-908eed7e4807846bda8b7883b98f4a02">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.1-1"><span class="target" id="change-765658fae385e8c30cafd7372f7da000"></span>bumped magic number, which forces template recompile for
+this version (fixes incompatible compile symbols from 0.1
+series).<a class="changeset-link headerlink reference internal" href="#change-765658fae385e8c30cafd7372f7da000">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.1-2"><span class="target" id="change-00ae3ce99ec2767e28b645a85815d1f9"></span>added a few docs for cache options, specifically those that
+help with memcached.<a class="changeset-link headerlink reference internal" href="#change-00ae3ce99ec2767e28b645a85815d1f9">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.2.0">
+<h3>0.2.0<a class="headerlink" href="#change-0.2.0" title="Permalink to this headline">¶</a></h3>
+Released: Tue Jun  3 2008<ul class="simple">
+<li><p id="change-0.2.0-0"><span class="target" id="change-7df2aeab716d6fcf91429566949d3297"></span>Speed improvements (as though we needed them, but people
+contributed and there you go):<a class="changeset-link headerlink reference internal" href="#change-7df2aeab716d6fcf91429566949d3297">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.0-1"><span class="target" id="change-d9c6b2b32a4d7d52614f9557a59dd57d"></span>added &#8220;bytestring passthru&#8221; mode, via
+<cite>disable_unicode=True</cite> argument passed to Template or
+TemplateLookup. All unicode-awareness and filtering is
+turned off, and template modules are generated with
+the appropriate magic encoding comment. In this mode,
+template expressions can only receive raw bytestrings
+or Unicode objects which represent straight ASCII, and
+render_unicode() may not be used if multibyte
+characters are present. When enabled, speed
+improvement around 10-20%. (courtesy
+anonymous guest)<a class="changeset-link headerlink reference internal" href="#change-d9c6b2b32a4d7d52614f9557a59dd57d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/77/">#77</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-2"><span class="target" id="change-1e1d8d3bf89815e481535914ac54e954"></span>inlined the &#8220;write&#8221; function of Context into a local
+template variable. This affords a 12-30% speedup in
+template render time. (idea courtesy same anonymous
+guest)<a class="changeset-link headerlink reference internal" href="#change-1e1d8d3bf89815e481535914ac54e954">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/76/">#76</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-3"><span class="target" id="change-4425ad7ea582f24d81e9ca7ef4f92e6e"></span>New Features, API changes:<a class="changeset-link headerlink reference internal" href="#change-4425ad7ea582f24d81e9ca7ef4f92e6e">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.0-4"><span class="target" id="change-9da04566e35e386418120e4d29572595"></span>added &#8220;attr&#8221; accessor to namespaces. Returns
+attributes configured as module level attributes, i.e.
+within &lt;%! %&gt; sections.  i.e.:<p># somefile.html
+&lt;%!</p>
+<blockquote>
+<div>foo = 27</div></blockquote>
+<p>%&gt;</p>
+<p># some other template
+&lt;%namespace name=&#8221;myns&#8221; file=&#8221;somefile.html&#8221;/&gt;
+${myns.attr.foo}</p>
+<p>The slight backwards incompatibility here is, you
+can&#8217;t have namespace defs named &#8220;attr&#8221; since the
+&#8220;attr&#8221; descriptor will occlude it.</p>
+<a class="changeset-link headerlink reference internal" href="#change-9da04566e35e386418120e4d29572595">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/62/">#62</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-5"><span class="target" id="change-47006dc7aa8160f70e0ed126113f0f5a"></span>cache_key argument can now render arguments passed
+directly to the %page or %def, i.e. &lt;%def
+name=&#8221;foo(x)&#8221; cached=&#8221;True&#8221; cache_key=&#8221;${x}&#8221;/&gt;<a class="changeset-link headerlink reference internal" href="#change-47006dc7aa8160f70e0ed126113f0f5a">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/78/">#78</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-6"><span class="target" id="change-d5e0803b1807eb8f0128d3ccd973525f"></span>some functions on Context are now private:
+_push_buffer(), _pop_buffer(),
+caller_stack._push_frame(), caller_stack._pop_frame().<a class="changeset-link headerlink reference internal" href="#change-d5e0803b1807eb8f0128d3ccd973525f">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.0-7"><span class="target" id="change-c53f2fb7206af6bed4a266fc8e39da44"></span>added a runner script &#8220;mako-render&#8221; which renders
+standard input as a template to stdout<a class="changeset-link headerlink reference internal" href="#change-c53f2fb7206af6bed4a266fc8e39da44">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/56/">#56</a>, <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/81/">#81</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-8"><span class="target" id="change-1cf0feb7e1a86092b97d375978dba60d"><strong>[bugfixes] </strong></span>can now use most names from __builtins__ as variable
+names without explicit declaration (i.e. &#8216;id&#8217;,
+&#8216;exception&#8217;, &#8216;range&#8217;, etc.)<a class="changeset-link headerlink reference internal" href="#change-1cf0feb7e1a86092b97d375978dba60d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/83/">#83</a>, <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/84/">#84</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-9"><span class="target" id="change-b42dffceb4d5586db34c320d5368a1a0"><strong>[bugfixes] </strong></span>can also use builtin names as local variable names
+(i.e. dict, locals) (came from fix for)<a class="changeset-link headerlink reference internal" href="#change-b42dffceb4d5586db34c320d5368a1a0">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/84/">#84</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-10"><span class="target" id="change-66d96bea88684ee0d97467bfe1ccbd28"><strong>[bugfixes] </strong></span>fixed bug in python generation when variable names are
+used with identifiers like &#8220;else&#8221;, &#8220;finally&#8221;, etc.
+inside them<a class="changeset-link headerlink reference internal" href="#change-66d96bea88684ee0d97467bfe1ccbd28">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/68/">#68</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-11"><span class="target" id="change-bc4345614fb8e0b7a0f6a4cd7c824afa"><strong>[bugfixes] </strong></span>fixed codegen bug which occured when using &lt;%page&gt;
+level caching, combined with an expression-based
+cache_key, combined with the usage of &lt;%namespace
+import=&#8221;*&#8221;/&gt; - fixed lexer exceptions not cleaning up
+temporary files, which could lead to a maximum number
+of file descriptors used in the process<a class="changeset-link headerlink reference internal" href="#change-bc4345614fb8e0b7a0f6a4cd7c824afa">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/69/">#69</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-12"><span class="target" id="change-f7edc331eeedd9d0e4e390279db7f1c6"><strong>[bugfixes] </strong></span>fixed issue with inline format_exceptions that was
+producing blank exception pages when an inheriting
+template is present<a class="changeset-link headerlink reference internal" href="#change-f7edc331eeedd9d0e4e390279db7f1c6">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/71/">#71</a></p>
+</p>
+</li>
+<li><p id="change-0.2.0-13"><span class="target" id="change-c380b62194e7806f2ba96a72cf35f4a5"><strong>[bugfixes] </strong></span>format_exceptions will apply the encoding options of
+html_error_template() to the buffered output<a class="changeset-link headerlink reference internal" href="#change-c380b62194e7806f2ba96a72cf35f4a5">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.2.0-14"><span class="target" id="change-aaa77e397a4d5a128ee8ead89aca6552"><strong>[bugfixes] </strong></span>rewrote the &#8220;whitespace adjuster&#8221; function to work
+with more elaborate combinations of quotes and
+comments<a class="changeset-link headerlink reference internal" href="#change-aaa77e397a4d5a128ee8ead89aca6552">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/75/">#75</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.10">
+<h3>0.1.10<a class="headerlink" href="#change-0.1.10" title="Permalink to this headline">¶</a></h3>
+no release date<ul class="simple">
+<li><p id="change-0.1.10-0"><span class="target" id="change-35446d7c963081d4cb4420f1a2b68beb"></span>fixed propagation of &#8216;caller&#8217; such that nested %def calls
+within a &lt;%call&gt; tag&#8217;s argument list propigates &#8216;caller&#8217;
+to the %call function itself (propigates to the inner
+calls too, this is a slight side effect which previously
+existed anyway)<a class="changeset-link headerlink reference internal" href="#change-35446d7c963081d4cb4420f1a2b68beb">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.10-1"><span class="target" id="change-60935107d31e2d12b8725bfa98a4e15e"></span>fixed bug where local.get_namespace() could put an
+incorrect &#8220;self&#8221; in the current context<a class="changeset-link headerlink reference internal" href="#change-60935107d31e2d12b8725bfa98a4e15e">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.10-2"><span class="target" id="change-a03b9e4773bb4ad04e67baf857946095"></span>fixed another namespace bug where the namespace functions
+did not have access to the correct context containing
+their &#8216;self&#8217; and &#8216;parent&#8217;<a class="changeset-link headerlink reference internal" href="#change-a03b9e4773bb4ad04e67baf857946095">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.9">
+<h3>0.1.9<a class="headerlink" href="#change-0.1.9" title="Permalink to this headline">¶</a></h3>
+no release date<ul class="simple">
+<li><p id="change-0.1.9-0"><span class="target" id="change-b6be8d8f9ba7a78451926e2e5a00168a"></span>filters.Decode filter can also accept a non-basestring
+object and will call str() + unicode() on it<a class="changeset-link headerlink reference internal" href="#change-b6be8d8f9ba7a78451926e2e5a00168a">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/47/">#47</a></p>
+</p>
+</li>
+<li><p id="change-0.1.9-1"><span class="target" id="change-80d0f355df4c2e0e2044d9b34ba8ffe6"></span>comments can be placed at the end of control lines,
+i.e. if foo: # a comment,, thanks to
+Paul Colomiets<a class="changeset-link headerlink reference internal" href="#change-80d0f355df4c2e0e2044d9b34ba8ffe6">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/53/">#53</a></p>
+</p>
+</li>
+<li><p id="change-0.1.9-2"><span class="target" id="change-4a1a251233e66deb83ebbca806c75e7e"></span>fixed expressions and page tag arguments and with embedded
+newlines in CRLF templates, follow up to, thanks
+Eric Woroshow<a class="changeset-link headerlink reference internal" href="#change-4a1a251233e66deb83ebbca806c75e7e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/16/">#16</a></p>
+</p>
+</li>
+<li><p id="change-0.1.9-3"><span class="target" id="change-b3479ae6d58bd0ac59439c4b81428d3e"></span>added an IOError catch for source file not found in RichTraceback
+exception reporter<a class="changeset-link headerlink reference internal" href="#change-b3479ae6d58bd0ac59439c4b81428d3e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/51/">#51</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.8">
+<h3>0.1.8<a class="headerlink" href="#change-0.1.8" title="Permalink to this headline">¶</a></h3>
+Released: Tue Jun 26 2007<ul class="simple">
+<li><p id="change-0.1.8-0"><span class="target" id="change-bbc10b00b2959f71e6703161fe1a45a1"></span>variable names declared in render methods by internal
+codegen prefixed by &#8220;__M_&#8221; to prevent name collisions
+with user code<a class="changeset-link headerlink reference internal" href="#change-bbc10b00b2959f71e6703161fe1a45a1">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.8-1"><span class="target" id="change-12a94b4bec51562504cc0951143d7b14"></span>added a Babel (<a class="reference external" href="http://babel.edgewall.org/">http://babel.edgewall.org/</a>) extractor entry
+point, allowing extraction of gettext messages directly from
+mako templates via Babel<a class="changeset-link headerlink reference internal" href="#change-12a94b4bec51562504cc0951143d7b14">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/45/">#45</a></p>
+</p>
+</li>
+<li><p id="change-0.1.8-2"><span class="target" id="change-ff313c4aec5d1b008cf8253396b514d6"></span>fix to turbogears plugin to work with dot-separated names
+(i.e. load_template(&#8216;foo.bar&#8217;)).  also takes file extension
+as a keyword argument (default is &#8216;mak&#8217;).<a class="changeset-link headerlink reference internal" href="#change-ff313c4aec5d1b008cf8253396b514d6">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.8-3"><span class="target" id="change-7f4b2edc94747c2be57aebfd1f725cf9"></span>more tg fix:  fixed, allowing string-based
+templates with tgplugin even if non-compatible args were sent<a class="changeset-link headerlink reference internal" href="#change-7f4b2edc94747c2be57aebfd1f725cf9">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/35/">#35</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.7">
+<h3>0.1.7<a class="headerlink" href="#change-0.1.7" title="Permalink to this headline">¶</a></h3>
+Released: Wed Jun 13 2007<ul class="simple">
+<li><p id="change-0.1.7-0"><span class="target" id="change-f9d399621cbe00065331cffcfd726aaf"></span>one small fix to the unit tests to support python 2.3<a class="changeset-link headerlink reference internal" href="#change-f9d399621cbe00065331cffcfd726aaf">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.7-1"><span class="target" id="change-d54e6f740ac7e3c9302f434352c6ad24"></span>a slight hack to how cache.py detects Beaker&#8217;s memcached,
+works around unexplained import behavior observed on some
+python 2.3 installations<a class="changeset-link headerlink reference internal" href="#change-d54e6f740ac7e3c9302f434352c6ad24">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.6">
+<h3>0.1.6<a class="headerlink" href="#change-0.1.6" title="Permalink to this headline">¶</a></h3>
+Released: Fri May 18 2007<ul class="simple">
+<li><p id="change-0.1.6-0"><span class="target" id="change-52836ef58904a858efff55a21272a3aa"></span>caching is now supplied directly by Beaker, which has
+all of MyghtyUtils merged into it now.  The latest Beaker
+(0.7.1) also fixes a bug related to how Mako was using the
+cache API.<a class="changeset-link headerlink reference internal" href="#change-52836ef58904a858efff55a21272a3aa">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.6-1"><span class="target" id="change-7bc90d84523c2290a3350c133e269c20"></span>fix to module_directory path generation when the path is &#8221;./&#8221;<a class="changeset-link headerlink reference internal" href="#change-7bc90d84523c2290a3350c133e269c20">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/34/">#34</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-2"><span class="target" id="change-ea6d95d606ab7dd8f3b3f8b49bc0ca99"></span>TGPlugin passes options to string-based templates<a class="changeset-link headerlink reference internal" href="#change-ea6d95d606ab7dd8f3b3f8b49bc0ca99">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/35/">#35</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-3"><span class="target" id="change-31e1248422bcd0c78c13b47b458a9085"></span>added an explicit stack frame step to template runtime, which
+allows much simpler and hopefully bug-free tracking of &#8216;caller&#8217;,
+fixes<a class="changeset-link headerlink reference internal" href="#change-31e1248422bcd0c78c13b47b458a9085">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/28/">#28</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-4"><span class="target" id="change-54a970a9cf864a6c262da7b7d9216109"></span>if plain Python defs are used with &lt;%call&gt;, a decorator
+&#64;runtime.supports_callable exists to ensure that the &#8220;caller&#8221;
+stack is properly handled for the def.<a class="changeset-link headerlink reference internal" href="#change-54a970a9cf864a6c262da7b7d9216109">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.6-5"><span class="target" id="change-d2cd0326db0e6586eabcce097caf31ff"></span>fix to RichTraceback and exception reporting to get template
+source code as a unicode object<a class="changeset-link headerlink reference internal" href="#change-d2cd0326db0e6586eabcce097caf31ff">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/37/">#37</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-6"><span class="target" id="change-dc0199630744815964c1e6174ea78785"></span>html_error_template includes options &#8220;full=True&#8221;, &#8220;css=True&#8221;
+which control generation of HTML tags, CSS<a class="changeset-link headerlink reference internal" href="#change-dc0199630744815964c1e6174ea78785">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/39/">#39</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-7"><span class="target" id="change-b0a96b76069cee8cd44ba31774b27fa2"></span>added the &#8216;encoding_errors&#8217; parameter to Template/TemplateLookup
+for specifying the error handler associated with encoding to
+&#8216;output_encoding&#8217;<a class="changeset-link headerlink reference internal" href="#change-b0a96b76069cee8cd44ba31774b27fa2">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/40/">#40</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-8"><span class="target" id="change-528e7eeb36e454ad6679969c443b951c"></span>the Template returned by html_error_template now defaults to
+output_encoding=sys.getdefaultencoding(),
+encoding_errors=&#8217;htmlentityreplace&#8217;<a class="changeset-link headerlink reference internal" href="#change-528e7eeb36e454ad6679969c443b951c">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/37/">#37</a></p>
+</p>
+</li>
+<li><p id="change-0.1.6-9"><span class="target" id="change-87df4540a9078340f98f18122437d6dd"></span>control lines, i.e. % lines, support backslashes to continue long
+lines (#32)<a class="changeset-link headerlink reference internal" href="#change-87df4540a9078340f98f18122437d6dd">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.6-10"><span class="target" id="change-5a582713c17cb4654879f3adb098f00f"></span>fixed codegen bug when defining &lt;%def&gt; within &lt;%call&gt; within &lt;%call&gt;<a class="changeset-link headerlink reference internal" href="#change-5a582713c17cb4654879f3adb098f00f">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.6-11"><span class="target" id="change-e80dc8f529838d0f39320706a515d3fa"></span>leading utf-8 BOM in template files is honored according to pep-0263<a class="changeset-link headerlink reference internal" href="#change-e80dc8f529838d0f39320706a515d3fa">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.5">
+<h3>0.1.5<a class="headerlink" href="#change-0.1.5" title="Permalink to this headline">¶</a></h3>
+Released: Sat Mar 31 2007<ul class="simple">
+<li><p id="change-0.1.5-0"><span class="target" id="change-f55f1eaaa360047ad0dbf07496beae9c"></span>AST expression generation - added in just about everything
+expression-wise from the AST module<a class="changeset-link headerlink reference internal" href="#change-f55f1eaaa360047ad0dbf07496beae9c">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/26/">#26</a></p>
+</p>
+</li>
+<li><p id="change-0.1.5-1"><span class="target" id="change-038f363f37ffb6f6e1d81aaeb32d371d"></span>AST parsing, properly detects imports of the form &#8220;import foo.bar&#8221;<a class="changeset-link headerlink reference internal" href="#change-038f363f37ffb6f6e1d81aaeb32d371d">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/27/">#27</a></p>
+</p>
+</li>
+<li><p id="change-0.1.5-2"><span class="target" id="change-fe4577a3f1111e2f31098302811ed765"></span>fix to lexing of &lt;%docs&gt; tag nested in other tags<a class="changeset-link headerlink reference internal" href="#change-fe4577a3f1111e2f31098302811ed765">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.5-3"><span class="target" id="change-895781e7f1f9e56da8e1f7d84a2d75e8"></span>fix to context-arguments inside of &lt;%include&gt; tag which broke
+during 0.1.4<a class="changeset-link headerlink reference internal" href="#change-895781e7f1f9e56da8e1f7d84a2d75e8">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/29/">#29</a></p>
+</p>
+</li>
+<li><p id="change-0.1.5-4"><span class="target" id="change-f4a4e7c2e333277389fa0febf1b94548"></span>added &#8220;n&#8221; filter, disables <em>all</em> filters normally applied to an expression
+via &lt;%page&gt; or default_filters (but not those within the filter)<a class="changeset-link headerlink reference internal" href="#change-f4a4e7c2e333277389fa0febf1b94548">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.5-5"><span class="target" id="change-1373f4756af28d08dc3d0c42b55ba89f"></span>added buffer_filters argument, defines filters applied to the return value
+of buffered/cached/filtered %defs, after all filters defined with the %def
+itself have been applied.  allows the creation of default expression filters
+that let the output of return-valued %defs &#8220;opt out&#8221; of that filtering
+via passing special attributes or objects.<a class="changeset-link headerlink reference internal" href="#change-1373f4756af28d08dc3d0c42b55ba89f">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.4">
+<h3>0.1.4<a class="headerlink" href="#change-0.1.4" title="Permalink to this headline">¶</a></h3>
+Released: Sat Mar 10 2007<ul class="simple">
+<li><p id="change-0.1.4-0"><span class="target" id="change-d9a3f08eba0431ad7fcc2c4a44ebbae6"></span>got defs-within-defs to be cacheable<a class="changeset-link headerlink reference internal" href="#change-d9a3f08eba0431ad7fcc2c4a44ebbae6">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-1"><span class="target" id="change-810513a0fe251b003785e47c73c05d6b"></span>fixes to code parsing/whitespace adjusting where plain python comments
+may contain quote characters<a class="changeset-link headerlink reference internal" href="#change-810513a0fe251b003785e47c73c05d6b">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/23/">#23</a></p>
+</p>
+</li>
+<li><p id="change-0.1.4-2"><span class="target" id="change-02205b506bd613a4038f90d3894ff1e4"></span>fix to variable scoping for identifiers only referenced within
+functions<a class="changeset-link headerlink reference internal" href="#change-02205b506bd613a4038f90d3894ff1e4">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-3"><span class="target" id="change-dffdf2c7b62fa47b54cac838b32b5a15"></span>added a path normalization step to lookup so URIs like
+&#8220;/foo/bar/../etc/../foo&#8221; pre-process the &#8221;..&#8221; tokens before checking
+the filesystem<a class="changeset-link headerlink reference internal" href="#change-dffdf2c7b62fa47b54cac838b32b5a15">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-4"><span class="target" id="change-2a6fb9feefccb0dc5a6a53f4a1145389"></span>fixed/improved &#8220;caller&#8221; semantics so that undefined caller is
+&#8220;UNDEFINED&#8221;, propigates __nonzero__ method so it evaulates to False if
+not present, True otherwise. this way you can say % if caller:n
+${caller.body()}n% endif<a class="changeset-link headerlink reference internal" href="#change-2a6fb9feefccb0dc5a6a53f4a1145389">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-5"><span class="target" id="change-7969cae88e43d5ccd928a0e231e9d242"></span>&lt;%include&gt; has an &#8220;args&#8221; attribute that can pass arguments to the
+called template (keyword arguments only, must be declared in that
+page&#8217;s &lt;%page&gt; tag.)<a class="changeset-link headerlink reference internal" href="#change-7969cae88e43d5ccd928a0e231e9d242">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-6"><span class="target" id="change-4b7deb2ea46de8d9db7b502ced7728dd"></span>&lt;%include&gt; plus arguments is also programmatically available via
+self.include_file(&lt;filename&gt;, <a href="#id9"><span class="problematic" id="id10">**</span></a>kwargs)<a class="changeset-link headerlink reference internal" href="#change-4b7deb2ea46de8d9db7b502ced7728dd">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.4-7"><span class="target" id="change-5e3d31c7ecde9769cc0daf0a545e50da"></span>further escaping added for multibyte expressions in %def, %call
+attributes<a class="changeset-link headerlink reference internal" href="#change-5e3d31c7ecde9769cc0daf0a545e50da">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/24/">#24</a></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.3">
+<h3>0.1.3<a class="headerlink" href="#change-0.1.3" title="Permalink to this headline">¶</a></h3>
+Released: Wed Feb 21 2007<ul class="simple">
+<li><p id="change-0.1.3-0"><span class="target" id="change-18db551453b5679b3f20ea5bdb7bdc52"></span><strong>*Small Syntax Change*</strong> - the single line comment character is now
+<em>two</em> hash signs, i.e. &#8220;## this is a comment&#8221;.  This avoids a common
+collection with CSS selectors.<a class="changeset-link headerlink reference internal" href="#change-18db551453b5679b3f20ea5bdb7bdc52">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-1"><span class="target" id="change-e30c3dbf8c63dae51878e95465b46c4b"></span>the magic &#8220;coding&#8221; comment (i.e. # coding:utf-8) will still work with
+either one &#8220;#&#8221; sign or two for now; two is preferred going forward, i.e.
+## coding:&lt;someencoding&gt;.<a class="changeset-link headerlink reference internal" href="#change-e30c3dbf8c63dae51878e95465b46c4b">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-2"><span class="target" id="change-722a3aa892f188f6c474fbe157b52980"></span>new multiline comment form: &#8220;&lt;%doc&gt; a comment &lt;/%doc&gt;&#8221;<a class="changeset-link headerlink reference internal" href="#change-722a3aa892f188f6c474fbe157b52980">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-3"><span class="target" id="change-d38fba282e33819ce79a8f8f93bfd42c"></span>UNDEFINED evaluates to False<a class="changeset-link headerlink reference internal" href="#change-d38fba282e33819ce79a8f8f93bfd42c">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-4"><span class="target" id="change-921044895d61328452e3a335bad34172"></span>improvement to scoping of &#8220;caller&#8221; variable when using &lt;%call&gt; tag<a class="changeset-link headerlink reference internal" href="#change-921044895d61328452e3a335bad34172">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-5"><span class="target" id="change-8be7ad08f79e900b80f8c291c23e7fe1"></span>added lexer error for unclosed control-line (%) line<a class="changeset-link headerlink reference internal" href="#change-8be7ad08f79e900b80f8c291c23e7fe1">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-6"><span class="target" id="change-85b846c5476142b1c2506c5a32d50817"></span>added &#8220;preprocessor&#8221; argument to Template, TemplateLookup - is a single
+callable or list of callables which will be applied to the template text
+before lexing.  given the text as an argument, returns the new text.<a class="changeset-link headerlink reference internal" href="#change-85b846c5476142b1c2506c5a32d50817">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.3-7"><span class="target" id="change-43d0af8d5e881c09c61799065df23349"></span>added mako.ext.preprocessors package, contains one preprocessor so far:
+&#8216;convert_comments&#8217;, which will convert single # comments to the new ##
+format<a class="changeset-link headerlink reference internal" href="#change-43d0af8d5e881c09c61799065df23349">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.2">
+<h3>0.1.2<a class="headerlink" href="#change-0.1.2" title="Permalink to this headline">¶</a></h3>
+Released: Thu Feb  1 2007<ul class="simple">
+<li><p id="change-0.1.2-0"><span class="target" id="change-e5e97c09505aa0d25c29ce1e158d4a8f"></span>fix to parsing of code/expression blocks to insure that non-ascii
+characters, combined with a template that indicates a non-standard
+encoding, are expanded into backslash-escaped glyphs before being AST
+parsed<a class="changeset-link headerlink reference internal" href="#change-e5e97c09505aa0d25c29ce1e158d4a8f">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/11/">#11</a></p>
+</p>
+</li>
+<li><p id="change-0.1.2-1"><span class="target" id="change-3ff8d6c650379a6f712a25b5d9f0f67f"></span>all template lexing converts the template to unicode first, to
+immediately catch any encoding issues and ensure internal unicode
+representation.<a class="changeset-link headerlink reference internal" href="#change-3ff8d6c650379a6f712a25b5d9f0f67f">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-2"><span class="target" id="change-0b29735786156418071800fe54aa64cd"></span>added module_filename argument to Template to allow specification of a
+specific module file<a class="changeset-link headerlink reference internal" href="#change-0b29735786156418071800fe54aa64cd">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-3"><span class="target" id="change-6904da36fbdded623dc4b3ee751d5674"></span>added modulename_callable to TemplateLookup to allow a function to
+determine module filenames (takes filename, uri arguments). used for<a class="changeset-link headerlink reference internal" href="#change-6904da36fbdded623dc4b3ee751d5674">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/14/">#14</a></p>
+</p>
+</li>
+<li><p id="change-0.1.2-4"><span class="target" id="change-ecf4eb2962f40391b75f8ce8f2a94a08"></span>added optional input_encoding flag to Template, to allow sending a
+unicode() object with no magic encoding comment<a class="changeset-link headerlink reference internal" href="#change-ecf4eb2962f40391b75f8ce8f2a94a08">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-5"><span class="target" id="change-5ea31cc5e58c79c774aaa9458928f827"></span>&#8220;expression_filter&#8221; argument in &lt;%page&gt; applies only to expressions<a class="changeset-link headerlink reference internal" href="#change-5ea31cc5e58c79c774aaa9458928f827">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-6"><span class="target" id="change-84beefcbcdc568675b6e3fefd7940957"><strong>[&#8220;unicode&#8221;] </strong></span>added &#8220;default_filters&#8221; argument to Template, TemplateLookup. applies only
+to expressions, gets prepended to &#8220;expression_filter&#8221; arg from &lt;%page&gt;.
+defaults to, so that all expressions get stringified into u&#8217;&#8217;
+by default (this is what Mako already does). By setting to [], expressions
+are passed through raw.<a class="changeset-link headerlink reference internal" href="#change-84beefcbcdc568675b6e3fefd7940957">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-7"><span class="target" id="change-fd580f1d839dc719fa1f0563b46ba474"></span>added &#8220;imports&#8221; argument to Template, TemplateLookup. so you can predefine
+a list of import statements at the top of the template. can be used in
+conjunction with default_filters.<a class="changeset-link headerlink reference internal" href="#change-fd580f1d839dc719fa1f0563b46ba474">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-8"><span class="target" id="change-817d592b540ba64129e24055c5f8ec27"></span>support for CRLF templates...whoops ! welcome to all the windows users.<a class="changeset-link headerlink reference internal" href="#change-817d592b540ba64129e24055c5f8ec27">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/16/">#16</a></p>
+</p>
+</li>
+<li><p id="change-0.1.2-9"><span class="target" id="change-5976a1e5691f501b38fc485209ec52a1"></span>small fix to local variable propigation for locals that are conditionally
+declared<a class="changeset-link headerlink reference internal" href="#change-5976a1e5691f501b38fc485209ec52a1">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.2-10"><span class="target" id="change-e51de8d14422e4b2b7fb4d583f5fb5f3"></span>got &#8220;top level&#8221; def calls to work, i.e. template.get_def(&#8220;somedef&#8221;).render()<a class="changeset-link headerlink reference internal" href="#change-e51de8d14422e4b2b7fb4d583f5fb5f3">¶</a><p></p>
+</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-0.1.1">
+<h3>0.1.1<a class="headerlink" href="#change-0.1.1" title="Permalink to this headline">¶</a></h3>
+Released: Sun Jan 14 2007<ul class="simple">
+<li><p id="change-0.1.1-0"><span class="target" id="change-05b7c1f3eb0cb4630b5ebbd1a172f5d5"></span>buffet plugin supports string-based templates, allows ToscaWidgets to work<a class="changeset-link headerlink reference internal" href="#change-05b7c1f3eb0cb4630b5ebbd1a172f5d5">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/8/">#8</a></p>
+</p>
+</li>
+<li><p id="change-0.1.1-1"><span class="target" id="change-20940aacb7e79ba6e20a4826ed237c0b"></span>AST parsing fixes: fixed TryExcept identifier parsing<a class="changeset-link headerlink reference internal" href="#change-20940aacb7e79ba6e20a4826ed237c0b">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-2"><span class="target" id="change-eb9efa2f093687fd2d4f5f7ac4e51c3c"></span>removed textmate tmbundle from contrib and into separate SVN location;
+windows users cant handle those files, setuptools not very good at
+&#8220;pruning&#8221; certain directories<a class="changeset-link headerlink reference internal" href="#change-eb9efa2f093687fd2d4f5f7ac4e51c3c">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-3"><span class="target" id="change-e1142489a6eb32082650995d95b37a71"></span>fix so that &#8220;cache_timeout&#8221; parameter is propigated<a class="changeset-link headerlink reference internal" href="#change-e1142489a6eb32082650995d95b37a71">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-4"><span class="target" id="change-603cfb5b4987686ea04bebe62aa32b24"></span>fix to expression filters so that string conversion (actually unicode)
+properly occurs before filtering<a class="changeset-link headerlink reference internal" href="#change-603cfb5b4987686ea04bebe62aa32b24">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-5"><span class="target" id="change-b07fbe08a504a4fa5f2d9827be99693a"></span>better error message when a lookup is attempted with a template that has no
+lookup<a class="changeset-link headerlink reference internal" href="#change-b07fbe08a504a4fa5f2d9827be99693a">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-6"><span class="target" id="change-bf10710d0a3d4e00b23e4c12739df8d8"></span>implemented &#8220;module&#8221; attribute for namespace<a class="changeset-link headerlink reference internal" href="#change-bf10710d0a3d4e00b23e4c12739df8d8">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-7"><span class="target" id="change-d2a20975eda94230da878d7b2bc53081"></span>fix to code generation to correctly track multiple defs with the same name<a class="changeset-link headerlink reference internal" href="#change-d2a20975eda94230da878d7b2bc53081">¶</a><p></p>
+</p>
+</li>
+<li><p id="change-0.1.1-8"><span class="target" id="change-8e234744095c72fc80b927b7a27b3d4e"></span>&#8220;directories&#8221; can be passed to TemplateLookup as a scalar in which case it
+gets converted to a list<a class="changeset-link headerlink reference internal" href="#change-8e234744095c72fc80b927b7a27b3d4e">¶</a><p>References: <a class="reference external" href="https://bitbucket.org/zzzeek/mako/issue/9/">#9</a></p>
+</p>
+</li>
+</ul>
+</div>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="caching.html" title="previous chapter">Caching</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/defs.html b/doc/defs.html
new file mode 100644 (file)
index 0000000..df08f11
--- /dev/null
@@ -0,0 +1,737 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Defs and Blocks
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="The Mako Runtime Environment" href="runtime.html" />
+        <link rel="prev" title="Syntax" href="syntax.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="syntax.html" title="previous chapter">Syntax</a>
+            </li>
+            <li>Next:
+            <a href="runtime.html" title="next chapter">The Mako Runtime Environment</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/defs.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Defs and Blocks
+            
+
+        <h2>
+            
+                Defs and Blocks
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Defs and Blocks</a><ul>
+<li><a class="reference internal" href="#using-defs">Using Defs</a><ul>
+<li><a class="reference internal" href="#calling-defs-from-other-files">Calling Defs from Other Files</a></li>
+<li><a class="reference internal" href="#calling-defs-programmatically">Calling Defs Programmatically</a></li>
+<li><a class="reference internal" href="#defs-within-defs">Defs within Defs</a></li>
+<li><a class="reference internal" href="#calling-a-def-with-embedded-content-and-or-other-defs">Calling a Def with Embedded Content and/or Other Defs</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#using-blocks">Using Blocks</a><ul>
+<li><a class="reference internal" href="#using-named-blocks">Using Named Blocks</a></li>
+<li><a class="reference internal" href="#using-page-arguments-in-named-blocks">Using Page Arguments in Named Blocks</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="syntax.html" title="previous chapter">Syntax</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="runtime.html" title="next chapter">The Mako Runtime Environment</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="defs-and-blocks">
+<span id="defs-toplevel"></span><h1>Defs and Blocks<a class="headerlink" href="#defs-and-blocks" title="Permalink to this headline">¶</a></h1>
+<p><code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> and <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> are two tags that both demarcate any block of text
+and/or code.   They both exist within generated Python as a callable function,
+i.e., a Python <code class="docutils literal"><span class="pre">def</span></code>.   They differ in their scope and calling semantics.
+Whereas <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> provides a construct that is very much like a named Python
+<code class="docutils literal"><span class="pre">def</span></code>, the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> is more layout oriented.</p>
+<div class="section" id="using-defs">
+<h2>Using Defs<a class="headerlink" href="#using-defs" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tag requires a <code class="docutils literal"><span class="pre">name</span></code> attribute, where the <code class="docutils literal"><span class="pre">name</span></code> references
+a Python function signature:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;hello()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    hello world</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>To invoke the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>, it is normally called as an expression:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">the def:  </span><span class="cp">${</span><span class="n">hello</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>If the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> is not nested inside of another <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>,
+it&#8217;s known as a <strong>top level def</strong> and can be accessed anywhere in
+the template, including above where it was defined.</p>
+<p>All defs, top level or not, have access to the current
+contextual namespace in exactly the same way their containing
+template does. Suppose the template below is executed with the
+variables <code class="docutils literal"><span class="pre">username</span></code> and <code class="docutils literal"><span class="pre">accountdata</span></code> inside the context:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">Hello there </span><span class="cp">${</span><span class="n">username</span><span class="cp">}</span><span class="x">, how are ya.  Lets see what your account says:</span>
+
+<span class="cp">${</span><span class="n">account</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;account()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Account for </span><span class="cp">${</span><span class="n">username</span><span class="cp">}</span><span class="x">:&lt;br/&gt;</span>
+
+    <span class="cp">%</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">accountdata</span><span class="p">:</span><span class="x"></span>
+<span class="x">        Value: </span><span class="cp">${</span><span class="n">row</span><span class="cp">}</span><span class="x">&lt;br/&gt;</span>
+    <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">username</span></code> and <code class="docutils literal"><span class="pre">accountdata</span></code> variables are present
+within the main template body as well as the body of the
+<code class="docutils literal"><span class="pre">account()</span></code> def.</p>
+<p>Since defs are just Python functions, you can define and pass
+arguments to them as well:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">account</span><span class="p">(</span><span class="n">accountname</span><span class="o">=</span><span class="s1">&#39;john&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;account(accountname, type=&#39;regular&#39;)&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    account name: </span><span class="cp">${</span><span class="n">accountname</span><span class="cp">}</span><span class="x">, type: </span><span class="cp">${</span><span class="nb">type</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>When you declare an argument signature for your def, they are
+required to follow normal Python conventions (i.e., all
+arguments are required except keyword arguments with a default
+value). This is in contrast to using context-level variables,
+which evaluate to <code class="docutils literal"><span class="pre">UNDEFINED</span></code> if you reference a name that
+does not exist.</p>
+<div class="section" id="calling-defs-from-other-files">
+<h3>Calling Defs from Other Files<a class="headerlink" href="#calling-defs-from-other-files" title="Permalink to this headline">¶</a></h3>
+<p>Top level <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>s are <strong>exported</strong> by your template&#8217;s
+module, and can be called from the outside; including from other
+templates, as well as normal Python code. Calling a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>
+from another template is something like using an <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code>
+&#8211; except you are calling a specific function within the
+template, not the whole template.</p>
+<p>The remote <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> call is also a little bit like calling
+functions from other modules in Python. There is an &#8220;import&#8221;
+step to pull the names from another template into your own
+template; then the function or functions are available.</p>
+<p>To import another template, use the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;mystuff&quot;</span> <span class="na">file=</span><span class="s">&quot;mystuff.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above tag adds a local variable <code class="docutils literal"><span class="pre">mystuff</span></code> to the current
+scope.</p>
+<p>Then, just call the defs off of <code class="docutils literal"><span class="pre">mystuff</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">mystuff</span><span class="o">.</span><span class="n">somedef</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag also supports some of the other
+semantics of Python&#8217;s <code class="docutils literal"><span class="pre">import</span></code> statement, including pulling
+names into the local variable space, or using <code class="docutils literal"><span class="pre">*</span></code> to represent
+all names, using the <code class="docutils literal"><span class="pre">import</span></code> attribute:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">file=</span><span class="s">&quot;mystuff.html&quot;</span> <span class="na">import=</span><span class="s">&quot;foo, bar&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>This is just a quick intro to the concept of a <strong>namespace</strong>,
+which is a central Mako concept that has its own chapter in
+these docs. For more detail and examples, see
+<a class="reference internal" href="namespaces.html"><span class="std std-ref">Namespaces</span></a>.</p>
+</div>
+<div class="section" id="calling-defs-programmatically">
+<h3>Calling Defs Programmatically<a class="headerlink" href="#calling-defs-programmatically" title="Permalink to this headline">¶</a></h3>
+<p>You can call defs programmatically from any <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object
+using the <a class="reference internal" href="usage.html#mako.template.Template.get_def" title="mako.template.Template.get_def"><code class="xref py py-meth docutils literal"><span class="pre">get_def()</span></code></a> method, which returns a <a class="reference internal" href="usage.html#mako.template.DefTemplate" title="mako.template.DefTemplate"><code class="xref py py-class docutils literal"><span class="pre">DefTemplate</span></code></a>
+object. This is a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> subclass which the parent
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> creates, and is usable like any other template:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">template</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span>
+<span class="s2">    &lt;</span><span class="si">%d</span><span class="s2">ef name=&quot;hi(name)&quot;&gt;</span>
+<span class="s2">        hi ${name}!</span>
+<span class="s2">    &lt;/</span><span class="si">%d</span><span class="s2">ef&gt;</span>
+
+<span class="s2">    &lt;</span><span class="si">%d</span><span class="s2">ef name=&quot;bye(name)&quot;&gt;</span>
+<span class="s2">        bye ${name}!</span>
+<span class="s2">    &lt;/</span><span class="si">%d</span><span class="s2">ef&gt;</span>
+<span class="s2">&quot;&quot;&quot;</span><span class="p">)</span>
+
+<span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">get_def</span><span class="p">(</span><span class="s2">&quot;hi&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;ed&quot;</span><span class="p">))</span>
+<span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">get_def</span><span class="p">(</span><span class="s2">&quot;bye&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;ed&quot;</span><span class="p">))</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="defs-within-defs">
+<h3>Defs within Defs<a class="headerlink" href="#defs-within-defs" title="Permalink to this headline">¶</a></h3>
+<p>The def model follows regular Python rules for closures.
+Declaring <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> inside another <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> declares it
+within the parent&#8217;s <strong>enclosing scope</strong>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;mydef()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;subdef()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        a sub def</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">    i&#39;m the def, and the subcomponent is </span><span class="cp">${</span><span class="n">subdef</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Just like Python, names that exist outside the inner <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>
+exist inside it as well:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="n">x</span> <span class="o">=</span> <span class="mi">12</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;outer()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span>
+        <span class="n">y</span> <span class="o">=</span> <span class="mi">15</span>
+    <span class="cp">%&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;inner()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        inner, x is </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x">, y is </span><span class="cp">${</span><span class="n">y</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">    outer, x is </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x">, y is </span><span class="cp">${</span><span class="n">y</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Assigning to a name inside of a def declares that name as local
+to the scope of that def (again, like Python itself). This means
+the following code will raise an error:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="n">x</span> <span class="o">=</span> <span class="mi">10</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;somedef()&quot;</span><span class="cp">&gt;</span>
+    <span class="cp">## error !</span><span class="x"></span>
+<span class="x">    somedef, x is </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span>
+        <span class="n">x</span> <span class="o">=</span> <span class="mi">27</span>
+    <span class="cp">%&gt;</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>...because the assignment to <code class="docutils literal"><span class="pre">x</span></code> declares <code class="docutils literal"><span class="pre">x</span></code> as local to the
+scope of <code class="docutils literal"><span class="pre">somedef</span></code>, rendering the &#8220;outer&#8221; version unreachable
+in the expression that tries to render it.</p>
+</div>
+<div class="section" id="calling-a-def-with-embedded-content-and-or-other-defs">
+<span id="defs-with-content"></span><h3>Calling a Def with Embedded Content and/or Other Defs<a class="headerlink" href="#calling-a-def-with-embedded-content-and-or-other-defs" title="Permalink to this headline">¶</a></h3>
+<p>A flip-side to def within def is a def call with content. This
+is where you call a def, and at the same time declare a block of
+content (or multiple blocks) that can be used by the def being
+called. The main point of such a call is to create custom,
+nestable tags, just like any other template language&#8217;s
+custom-tag creation system &#8211; where the external tag controls the
+execution of the nested tags and can communicate state to them.
+Only with Mako, you don&#8217;t have to use any external Python
+modules, you can define arbitrarily nestable tags right in your
+templates.</p>
+<p>To achieve this, the target def is invoked using the form
+<code class="docutils literal"><span class="pre">&lt;%namespacename:defname&gt;</span></code> instead of the normal <code class="docutils literal"><span class="pre">${}</span></code>
+syntax. This syntax, introduced in Mako 0.2.3, is functionally
+equivalent to another tag known as <code class="docutils literal"><span class="pre">%call</span></code>, which takes the form
+<code class="docutils literal"><span class="pre">&lt;%call</span> <span class="pre">expr='namespacename.defname(args)'&gt;</span></code>. While <code class="docutils literal"><span class="pre">%call</span></code>
+is available in all versions of Mako, the newer style is
+probably more familiar looking. The <code class="docutils literal"><span class="pre">namespace</span></code> portion of the
+call is the name of the <strong>namespace</strong> in which the def is
+defined &#8211; in the most simple cases, this can be <code class="docutils literal"><span class="pre">local</span></code> or
+<code class="docutils literal"><span class="pre">self</span></code> to reference the current template&#8217;s namespace (the
+difference between <code class="docutils literal"><span class="pre">local</span></code> and <code class="docutils literal"><span class="pre">self</span></code> is one of inheritance
+&#8211; see <a class="reference internal" href="namespaces.html#namespaces-builtin"><span class="std std-ref">Built-in Namespaces</span></a> for details).</p>
+<p>When the target def is invoked, a variable <code class="docutils literal"><span class="pre">caller</span></code> is placed
+in its context which contains another namespace containing the
+body and other defs defined by the caller. The body itself is
+referenced by the method <code class="docutils literal"><span class="pre">body()</span></code>. Below, we build a <code class="docutils literal"><span class="pre">%def</span></code>
+that operates upon <code class="docutils literal"><span class="pre">caller.body()</span></code> to invoke the body of the
+custom tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;buildtable()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;table&gt;</span>
+<span class="x">        &lt;tr&gt;&lt;td&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/td&gt;&lt;/tr&gt;</span>
+<span class="x">    &lt;/table&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">self:buildtable</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    I am the table body.</span>
+<span class="cp">&lt;/%</span><span class="nb">self:buildtable</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>This produces the output (whitespace formatted):</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">table</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;&lt;</span><span class="nt">td</span><span class="p">&gt;</span>
+        I am the table body.
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">table</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>Using the older <code class="docutils literal"><span class="pre">%call</span></code> syntax looks like:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;buildtable()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;table&gt;</span>
+<span class="x">        &lt;tr&gt;&lt;td&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/td&gt;&lt;/tr&gt;</span>
+<span class="x">    &lt;/table&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">call</span> <span class="na">expr=</span><span class="s">&quot;buildtable()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    I am the table body.</span>
+<span class="cp">&lt;/%</span><span class="nb">call</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">body()</span></code> can be executed multiple times or not at all.
+This means you can use def-call-with-content to build iterators,
+conditionals, etc:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;lister(count)&quot;</span><span class="cp">&gt;</span>
+    <span class="cp">%</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">):</span><span class="x"></span>
+<span class="x">        </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span>
+    <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">self:lister</span> <span class="na">count=</span><span class="s">&quot;${3}&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    hi</span>
+<span class="cp">&lt;/%</span><span class="nb">self:lister</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Produces:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span>hi
+hi
+hi
+</pre></div>
+</div>
+<p>Notice above we pass <code class="docutils literal"><span class="pre">3</span></code> as a Python expression, so that it
+remains as an integer.</p>
+<p>A custom &#8220;conditional&#8221; tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;conditional(expression)&quot;</span><span class="cp">&gt;</span>
+    <span class="cp">%</span> <span class="k">if</span> <span class="n">expression</span><span class="p">:</span><span class="x"></span>
+<span class="x">        </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span>
+    <span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">self:conditional</span> <span class="na">expression=</span><span class="s">&quot;${4==4}&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    i&#39;m the result</span>
+<span class="cp">&lt;/%</span><span class="nb">self:conditional</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Produces:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span>i&#39;m the result
+</pre></div>
+</div>
+<p>But that&#8217;s not all. The <code class="docutils literal"><span class="pre">body()</span></code> function also can handle
+arguments, which will augment the local namespace of the body
+callable. The caller must define the arguments which it expects
+to receive from its target def using the <code class="docutils literal"><span class="pre">args</span></code> attribute,
+which is a comma-separated list of argument names. Below, our
+<code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> calls the <code class="docutils literal"><span class="pre">body()</span></code> of its caller, passing in an
+element of data from its argument:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;layoutdata(somedata)&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;table&gt;</span>
+    <span class="cp">%</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">somedata</span><span class="p">:</span><span class="x"></span>
+<span class="x">        &lt;tr&gt;</span>
+        <span class="cp">%</span> <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">item</span><span class="p">:</span><span class="x"></span>
+<span class="x">            &lt;td&gt;</span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">(</span><span class="n">col</span><span class="o">=</span><span class="n">col</span><span class="p">)</span><span class="cp">}</span><span class="x">&lt;/td&gt;</span>
+        <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">        &lt;/tr&gt;</span>
+    <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">    &lt;/table&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">self:layoutdata</span> <span class="na">somedata=</span><span class="s">&quot;${[[1,2,3],[4,5,6],[7,8,9]]}&quot;</span> <span class="na">args=</span><span class="s">&quot;col&quot;</span><span class="cp">&gt;</span><span class="x">\</span>
+<span class="x">Body data: </span><span class="cp">${</span><span class="n">col</span><span class="cp">}</span><span class="x">\</span>
+<span class="cp">&lt;/%</span><span class="nb">self:layoutdata</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Produces:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">table</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 1<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 2<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 3<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 4<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 5<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 6<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 7<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 8<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">td</span><span class="p">&gt;</span>Body data: 9<span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">table</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>You don&#8217;t have to stick to calling just the <code class="docutils literal"><span class="pre">body()</span></code> function.
+The caller can define any number of callables, allowing the
+<code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code> tag to produce whole layouts:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;layout()&quot;</span><span class="cp">&gt;</span>
+    <span class="cp">## a layout def</span><span class="x"></span>
+<span class="x">    &lt;div class=&quot;mainlayout&quot;&gt;</span>
+<span class="x">        &lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        &lt;div class=&quot;sidebar&quot;&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">sidebar</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        &lt;div class=&quot;content&quot;&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+<span class="x">    &lt;/div&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span>
+
+<span class="cp">## calls the layout def</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">self:layout</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        I am the header</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;sidebar()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;ul&gt;</span>
+<span class="x">            &lt;li&gt;sidebar 1&lt;/li&gt;</span>
+<span class="x">            &lt;li&gt;sidebar 2&lt;/li&gt;</span>
+<span class="x">        &lt;/ul&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">        this is the body</span>
+<span class="cp">&lt;/%</span><span class="nb">self:layout</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above layout would produce:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;mainlayout&quot;</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;header&quot;</span><span class="p">&gt;</span>
+    I am the header
+    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;sidebar&quot;</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>sidebar 1<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>sidebar 2<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;content&quot;</span><span class="p">&gt;</span>
+    this is the body
+    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>The number of things you can do with <code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code> and/or the
+<code class="docutils literal"><span class="pre">&lt;%namespacename:defname&gt;</span></code> calling syntax is enormous. You can
+create form widget libraries, such as an enclosing <code class="docutils literal"><span class="pre">&lt;FORM&gt;</span></code>
+tag and nested HTML input elements, or portable wrapping schemes
+using <code class="docutils literal"><span class="pre">&lt;div&gt;</span></code> or other elements. You can create tags that
+interpret rows of data, such as from a database, providing the
+individual columns of each row to a <code class="docutils literal"><span class="pre">body()</span></code> callable which
+lays out the row any way it wants. Basically anything you&#8217;d do
+with a &#8220;custom tag&#8221; or tag library in some other system, Mako
+provides via <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tags and plain Python callables which are
+invoked via <code class="docutils literal"><span class="pre">&lt;%namespacename:defname&gt;</span></code> or <code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code>.</p>
+</div>
+</div>
+<div class="section" id="using-blocks">
+<span id="blocks"></span><h2>Using Blocks<a class="headerlink" href="#using-blocks" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> tag introduces some new twists on the
+<code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tag which make it more closely tailored towards layout.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.4.1.</span></p>
+</div>
+<p>An example of a block:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        </span><span class="cp">&lt;%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">            this is a block.</span>
+<span class="x">        </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>In the above example, we define a simple block.  The block renders its content in the place
+that it&#8217;s defined.  Since the block is called for us, it doesn&#8217;t need a name and the above
+is referred to as an <strong>anonymous block</strong>.  So the output of the above template will be:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
+            this is a block.
+    <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>So in fact the above block has absolutely no effect.  Its usefulness comes when we start
+using modifiers.  Such as, we can apply a filter to our block:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">filter=</span><span class="s">&quot;h&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">            &lt;html&gt;this is some escaped html.&lt;/html&gt;</span>
+<span class="x">        </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>or perhaps a caching directive:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_timeout=</span><span class="s">&quot;60&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">            This content will be cached for 60 seconds.</span>
+<span class="x">        </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>Blocks also work in iterations, conditionals, just like defs:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">if</span> <span class="n">some_condition</span><span class="p">:</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x">condition is met</span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+<span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+</pre></div>
+</div>
+<p>While the block renders at the point it is defined in the template,
+the underlying function is present in the generated Python code only
+once, so there&#8217;s no issue with placing a block inside of a loop or
+similar. Anonymous blocks are defined as closures in the local
+rendering body, so have access to local variable scope:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">):</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x">i is </span><span class="cp">${</span><span class="n">i</span><span class="cp">}&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+</pre></div>
+</div>
+<div class="section" id="using-named-blocks">
+<h3>Using Named Blocks<a class="headerlink" href="#using-named-blocks" title="Permalink to this headline">¶</a></h3>
+<p>Possibly the more important area where blocks are useful is when we
+do actually give them names. Named blocks are tailored to behave
+somewhat closely to Jinja2&#8217;s block tag, in that they define an area
+of a layout which can be overridden by an inheriting template. In
+sharp contrast to the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tag, the name given to a block is
+global for the entire template regardless of how deeply it&#8217;s nested:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;head&gt;</span>
+<span class="x">        &lt;title&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">&gt;</span><span class="x">Title</span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;/title&gt;</span>
+<span class="x">    &lt;/head&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">&lt;body&gt;</span>
+<span class="x">    </span><span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>The above example has two named blocks &#8220;<code class="docutils literal"><span class="pre">header</span></code>&#8221; and &#8220;<code class="docutils literal"><span class="pre">title</span></code>&#8221;, both of which can be referred to
+by an inheriting template. A detailed walkthrough of this usage can be found at <a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+<p>Note above that named blocks don&#8217;t have any argument declaration the way defs do. They still implement themselves
+as Python functions, however, so they can be invoked additional times beyond their initial definition:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;div name=&quot;page&quot;&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;pagecontrol&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;a href=&quot;&quot;&gt;previous page&lt;/a&gt; |</span>
+<span class="x">        &lt;a href=&quot;&quot;&gt;next page&lt;/a&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">    &lt;table&gt;</span>
+<span class="x">        ## some content</span>
+<span class="x">    &lt;/table&gt;</span>
+
+<span class="x">    </span><span class="cp">${</span><span class="n">pagecontrol</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>The content referenced by <code class="docutils literal"><span class="pre">pagecontrol</span></code> above will be rendered both above and below the <code class="docutils literal"><span class="pre">&lt;table&gt;</span></code> tags.</p>
+<p>To keep things sane, named blocks have restrictions that defs do not:</p>
+<ul class="simple">
+<li>The <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> declaration cannot have any argument signature.</li>
+<li>The name of a <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> can only be defined once in a template &#8211; an error is raised if two blocks of the same
+name occur anywhere in a single template, regardless of nesting.  A similar error is raised if a top level def
+shares the same name as that of a block.</li>
+<li>A named <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> cannot be defined within a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>, or inside the body of a &#8220;call&#8221;, i.e.
+<code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code> or <code class="docutils literal"><span class="pre">&lt;%namespacename:defname&gt;</span></code> tag.  Anonymous blocks can, however.</li>
+</ul>
+</div>
+<div class="section" id="using-page-arguments-in-named-blocks">
+<h3>Using Page Arguments in Named Blocks<a class="headerlink" href="#using-page-arguments-in-named-blocks" title="Permalink to this headline">¶</a></h3>
+<p>A named block is very much like a top level def. It has a similar
+restriction to these types of defs in that arguments passed to the
+template via the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag aren&#8217;t automatically available.
+Using arguments with the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag is described in the section
+<a class="reference internal" href="namespaces.html#namespaces-body"><span class="std std-ref">The body() Method</span></a>, and refers to scenarios such as when the
+<code class="docutils literal"><span class="pre">body()</span></code> method of a template is called from an inherited template passing
+arguments, or the template is invoked from an <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag
+with arguments. To allow a named block to share the same arguments
+passed to the page, the <code class="docutils literal"><span class="pre">args</span></code> attribute can be used:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">args=</span><span class="s">&quot;post&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">&lt;a name=&quot;</span><span class="cp">${</span><span class="n">post</span><span class="o">.</span><span class="n">title</span><span class="cp">}</span><span class="x">&quot; /&gt;</span>
+
+<span class="x">&lt;span class=&quot;post_prose&quot;&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;post_prose&quot;</span> <span class="na">args=</span><span class="s">&quot;post&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        </span><span class="cp">${</span><span class="n">post</span><span class="o">.</span><span class="n">content</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">&lt;/span&gt;</span>
+</pre></div>
+</div>
+<p>Where above, if the template is called via a directive like
+<code class="docutils literal"><span class="pre">&lt;%include</span> <span class="pre">file=&quot;post.mako&quot;</span> <span class="pre">args=&quot;post=post&quot;</span> <span class="pre">/&gt;</span></code>, the <code class="docutils literal"><span class="pre">post</span></code>
+variable is available both in the main body as well as the
+<code class="docutils literal"><span class="pre">post_prose</span></code> block.</p>
+<p>Similarly, the <code class="docutils literal"><span class="pre">**pageargs</span></code> variable is present, in named blocks only,
+for those arguments not explicit in the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;post_prose&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="n">pageargs</span><span class="p">[</span><span class="s1">&#39;post&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">content</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">args</span></code> attribute is only allowed with named blocks. With
+anonymous blocks, the Python function is always rendered in the same
+scope as the call itself, so anything available directly outside the
+anonymous block is available inside as well.</p>
+</div>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="syntax.html" title="previous chapter">Syntax</a>
+        Next:
+        <a href="runtime.html" title="next chapter">The Mako Runtime Environment</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/filtering.html b/doc/filtering.html
new file mode 100644 (file)
index 0000000..0ac58ad
--- /dev/null
@@ -0,0 +1,488 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Filtering and Buffering
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="The Unicode Chapter" href="unicode.html" />
+        <link rel="prev" title="Inheritance" href="inheritance.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="inheritance.html" title="previous chapter">Inheritance</a>
+            </li>
+            <li>Next:
+            <a href="unicode.html" title="next chapter">The Unicode Chapter</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/filtering.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Filtering and Buffering
+            
+
+        <h2>
+            
+                Filtering and Buffering
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Filtering and Buffering</a><ul>
+<li><a class="reference internal" href="#expression-filtering">Expression Filtering</a><ul>
+<li><a class="reference internal" href="#the-default-filters-argument">The <code class="docutils literal"><span class="pre">default_filters</span></code> Argument</a></li>
+<li><a class="reference internal" href="#turning-off-filtering-with-the-n-filter">Turning off Filtering with the <code class="docutils literal"><span class="pre">n</span></code> Filter</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#filtering-defs-and-blocks">Filtering Defs and Blocks</a></li>
+<li><a class="reference internal" href="#buffering">Buffering</a></li>
+<li><a class="reference internal" href="#decorating">Decorating</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="inheritance.html" title="previous chapter">Inheritance</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="unicode.html" title="next chapter">The Unicode Chapter</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="filtering-and-buffering">
+<span id="filtering-toplevel"></span><h1>Filtering and Buffering<a class="headerlink" href="#filtering-and-buffering" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="expression-filtering">
+<h2>Expression Filtering<a class="headerlink" href="#expression-filtering" title="Permalink to this headline">¶</a></h2>
+<p>As described in the chapter <a class="reference internal" href="syntax.html"><span class="std std-ref">Syntax</span></a>, the &#8220;<code class="docutils literal"><span class="pre">|</span></code>&#8221; operator can be
+applied to a &#8220;<code class="docutils literal"><span class="pre">${}</span></code>&#8221; expression to apply escape filters to the
+output:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot;this is some text&quot;</span> <span class="o">|</span> <span class="n">u</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above expression applies URL escaping to the expression, and
+produces <code class="docutils literal"><span class="pre">this+is+some+text</span></code>.</p>
+<p>The built-in escape flags are:</p>
+<ul>
+<li><p class="first"><code class="docutils literal"><span class="pre">u</span></code> : URL escaping, provided by
+<code class="docutils literal"><span class="pre">urllib.quote_plus(string.encode('utf-8'))</span></code></p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">h</span></code> : HTML escaping, provided by
+<code class="docutils literal"><span class="pre">markupsafe.escape(string)</span></code></p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.3.4: </span>Prior versions use <code class="docutils literal"><span class="pre">cgi.escape(string,</span> <span class="pre">True)</span></code>.</p>
+</div>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">x</span></code> : XML escaping</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">trim</span></code> : whitespace trimming, provided by <code class="docutils literal"><span class="pre">string.strip()</span></code></p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">entity</span></code> : produces HTML entity references for applicable
+strings, derived from <code class="docutils literal"><span class="pre">htmlentitydefs</span></code></p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">unicode</span></code> (<code class="docutils literal"><span class="pre">str</span></code> on Python 3): produces a Python unicode
+string (this function is applied by default)</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">decode.&lt;some</span> <span class="pre">encoding&gt;</span></code>: decode input into a Python
+unicode with the specified encoding</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">n</span></code> : disable all default filtering; only filters specified
+in the local expression tag will be applied.</p>
+</li>
+</ul>
+<p>To apply more than one filter, separate them by a comma:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot; &lt;tag&gt;some value&lt;/tag&gt; &quot;</span> <span class="o">|</span> <span class="n">h</span><span class="p">,</span><span class="n">trim</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above produces <code class="docutils literal"><span class="pre">&amp;lt;tag&amp;gt;some</span> <span class="pre">value&amp;lt;/tag&amp;gt;</span></code>, with
+no leading or trailing whitespace. The HTML escaping function is
+applied first, the &#8220;trim&#8221; function second.</p>
+<p>Naturally, you can make your own filters too. A filter is just a
+Python function that accepts a single string argument, and
+returns the filtered result. The expressions after the <code class="docutils literal"><span class="pre">|</span></code>
+operator draw upon the local namespace of the template in which
+they appear, meaning you can define escaping functions locally:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="k">def</span> <span class="nf">myescape</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
+        <span class="k">return</span> <span class="s2">&quot;&lt;TAG&gt;&quot;</span> <span class="o">+</span> <span class="n">text</span> <span class="o">+</span> <span class="s2">&quot;&lt;/TAG&gt;&quot;</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="x">Here&#39;s some tagged text: </span><span class="cp">${</span><span class="s2">&quot;text&quot;</span> <span class="o">|</span> <span class="n">myescape</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Or from any Python module:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="kn">import</span> <span class="nn">myfilters</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="x">Here&#39;s some tagged text: </span><span class="cp">${</span><span class="s2">&quot;text&quot;</span> <span class="o">|</span> <span class="n">myfilters</span><span class="o">.</span><span class="n">tagfilter</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>A page can apply a default set of filters to all expression tags
+using the <code class="docutils literal"><span class="pre">expression_filter</span></code> argument to the <code class="docutils literal"><span class="pre">%page</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">expression_filter=</span><span class="s">&quot;h&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">Escaped text:  </span><span class="cp">${</span><span class="s2">&quot;&lt;html&gt;some html&lt;/html&gt;&quot;</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Result:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span>Escaped text: <span class="ni">&amp;lt;</span>html<span class="ni">&amp;gt;</span>some html<span class="ni">&amp;lt;</span>/html<span class="ni">&amp;gt;</span>
+</pre></div>
+</div>
+<div class="section" id="the-default-filters-argument">
+<span id="filtering-default-filters"></span><h3>The <code class="docutils literal"><span class="pre">default_filters</span></code> Argument<a class="headerlink" href="#the-default-filters-argument" title="Permalink to this headline">¶</a></h3>
+<p>In addition to the <code class="docutils literal"><span class="pre">expression_filter</span></code> argument, the
+<code class="docutils literal"><span class="pre">default_filters</span></code> argument to both <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> and
+<a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> can specify filtering for all expression tags
+at the programmatic level. This array-based argument, when given
+its default argument of <code class="docutils literal"><span class="pre">None</span></code>, will be internally set to
+<code class="docutils literal"><span class="pre">[&quot;unicode&quot;]</span></code> (or <code class="docutils literal"><span class="pre">[&quot;str&quot;]</span></code> on Python 3), except when
+<code class="docutils literal"><span class="pre">disable_unicode=True</span></code> is set in which case it defaults to
+<code class="docutils literal"><span class="pre">[&quot;str&quot;]</span></code>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/tmp&#39;</span><span class="p">],</span> <span class="n">default_filters</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;unicode&#39;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>To replace the usual <code class="docutils literal"><span class="pre">unicode</span></code>/<code class="docutils literal"><span class="pre">str</span></code> function with a
+specific encoding, the <code class="docutils literal"><span class="pre">decode</span></code> filter can be substituted:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/tmp&#39;</span><span class="p">],</span> <span class="n">default_filters</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;decode.utf8&#39;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>To disable <code class="docutils literal"><span class="pre">default_filters</span></code> entirely, set it to an empty
+list:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/tmp&#39;</span><span class="p">],</span> <span class="n">default_filters</span><span class="o">=</span><span class="p">[])</span>
+</pre></div>
+</div>
+<p>Any string name can be added to <code class="docutils literal"><span class="pre">default_filters</span></code> where it
+will be added to all expressions as a filter. The filters are
+applied from left to right, meaning the leftmost filter is
+applied first.</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="n">templatetext</span><span class="p">,</span> <span class="n">default_filters</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;unicode&#39;</span><span class="p">,</span> <span class="s1">&#39;myfilter&#39;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>To ease the usage of <code class="docutils literal"><span class="pre">default_filters</span></code> with custom filters,
+you can also add imports (or other code) to all templates using
+the <code class="docutils literal"><span class="pre">imports</span></code> argument:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/tmp&#39;</span><span class="p">],</span>
+                   <span class="n">default_filters</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;unicode&#39;</span><span class="p">,</span> <span class="s1">&#39;myfilter&#39;</span><span class="p">],</span>
+                   <span class="n">imports</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;from mypackage import myfilter&#39;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>The above will generate templates something like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># ....</span>
+<span class="kn">from</span> <span class="nn">mypackage</span> <span class="kn">import</span> <span class="n">myfilter</span>
+
+<span class="k">def</span> <span class="nf">render_body</span><span class="p">(</span><span class="n">context</span><span class="p">):</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">myfilter</span><span class="p">(</span><span class="nb">unicode</span><span class="p">(</span><span class="s2">&quot;some text&quot;</span><span class="p">)))</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="turning-off-filtering-with-the-n-filter">
+<h3>Turning off Filtering with the <code class="docutils literal"><span class="pre">n</span></code> Filter<a class="headerlink" href="#turning-off-filtering-with-the-n-filter" title="Permalink to this headline">¶</a></h3>
+<p>In all cases the special <code class="docutils literal"><span class="pre">n</span></code> filter, used locally within an
+expression, will <strong>disable</strong> all filters declared in the
+<code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag as well as in <code class="docutils literal"><span class="pre">default_filters</span></code>. Such as:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s1">&#39;myexpression&#39;</span> <span class="o">|</span> <span class="n">n</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>will render <code class="docutils literal"><span class="pre">myexpression</span></code> with no filtering of any kind, and:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s1">&#39;myexpression&#39;</span> <span class="o">|</span> <span class="n">n</span><span class="p">,</span><span class="n">trim</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>will render <code class="docutils literal"><span class="pre">myexpression</span></code> using the <code class="docutils literal"><span class="pre">trim</span></code> filter only.</p>
+</div>
+</div>
+<div class="section" id="filtering-defs-and-blocks">
+<h2>Filtering Defs and Blocks<a class="headerlink" href="#filtering-defs-and-blocks" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">%def</span></code> and <code class="docutils literal"><span class="pre">%block</span></code> tags have an argument called <code class="docutils literal"><span class="pre">filter</span></code> which will apply the
+given list of filter functions to the output of the <code class="docutils literal"><span class="pre">%def</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;foo()&quot;</span> <span class="na">filter=</span><span class="s">&quot;h, trim&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;b&gt;this is bold&lt;/b&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>When the <code class="docutils literal"><span class="pre">filter</span></code> attribute is applied to a def as above, the def
+is automatically <strong>buffered</strong> as well. This is described next.</p>
+</div>
+<div class="section" id="buffering">
+<h2>Buffering<a class="headerlink" href="#buffering" title="Permalink to this headline">¶</a></h2>
+<p>One of Mako&#8217;s central design goals is speed. To this end, all of
+the textual content within a template and its various callables
+is by default piped directly to the single buffer that is stored
+within the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object. While this normally is easy to
+miss, it has certain side effects. The main one is that when you
+call a def using the normal expression syntax, i.e.
+<code class="docutils literal"><span class="pre">${somedef()}</span></code>, it may appear that the return value of the
+function is the content it produced, which is then delivered to
+your template just like any other expression substitution,
+except that normally, this is not the case; the return value of
+<code class="docutils literal"><span class="pre">${somedef()}</span></code> is simply the empty string <code class="docutils literal"><span class="pre">''</span></code>. By the time
+you receive this empty string, the output of <code class="docutils literal"><span class="pre">somedef()</span></code> has
+been sent to the underlying buffer.</p>
+<p>You may not want this effect, if for example you are doing
+something like this:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot; results &quot;</span> <span class="o">+</span> <span class="n">somedef</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&quot; more results &quot;</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>If the <code class="docutils literal"><span class="pre">somedef()</span></code> function produced the content &#8220;<code class="docutils literal"><span class="pre">somedef's</span>
+<span class="pre">results</span></code>&#8221;, the above template would produce this output:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span>somedef&#39;s results results more results
+</pre></div>
+</div>
+<p>This is because <code class="docutils literal"><span class="pre">somedef()</span></code> fully executes before the
+expression returns the results of its concatenation; the
+concatenation in turn receives just the empty string as its
+middle expression.</p>
+<p>Mako provides two ways to work around this. One is by applying
+buffering to the <code class="docutils literal"><span class="pre">%def</span></code> itself:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;somedef()&quot;</span> <span class="na">buffered=</span><span class="s">&quot;True&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    somedef&#39;s results</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above definition will generate code similar to this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">somedef</span><span class="p">():</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">push_buffer</span><span class="p">()</span>
+    <span class="k">try</span><span class="p">:</span>
+        <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;somedef&#39;s results&quot;</span><span class="p">)</span>
+    <span class="k">finally</span><span class="p">:</span>
+        <span class="n">buf</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">pop_buffer</span><span class="p">()</span>
+    <span class="k">return</span> <span class="n">buf</span><span class="o">.</span><span class="n">getvalue</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>So that the content of <code class="docutils literal"><span class="pre">somedef()</span></code> is sent to a second buffer,
+which is then popped off the stack and its value returned. The
+speed hit inherent in buffering the output of a def is also
+apparent.</p>
+<p>Note that the <code class="docutils literal"><span class="pre">filter</span></code> argument on <code class="docutils literal"><span class="pre">%def</span></code> also causes the def to
+be buffered. This is so that the final content of the <code class="docutils literal"><span class="pre">%def</span></code> can
+be delivered to the escaping function in one batch, which
+reduces method calls and also produces more deterministic
+behavior for the filtering function itself, which can possibly
+be useful for a filtering function that wishes to apply a
+transformation to the text as a whole.</p>
+<p>The other way to buffer the output of a def or any Mako callable
+is by using the built-in <code class="docutils literal"><span class="pre">capture</span></code> function. This function
+performs an operation similar to the above buffering operation
+except it is specified by the caller.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot; results &quot;</span> <span class="o">+</span> <span class="n">capture</span><span class="p">(</span><span class="n">somedef</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot; more results &quot;</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Note that the first argument to the <code class="docutils literal"><span class="pre">capture</span></code> function is
+<strong>the function itself</strong>, not the result of calling it. This is
+because the <code class="docutils literal"><span class="pre">capture</span></code> function takes over the job of actually
+calling the target function, after setting up a buffered
+environment. To send arguments to the function, just send them
+to <code class="docutils literal"><span class="pre">capture</span></code> instead:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">capture</span><span class="p">(</span><span class="n">somedef</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="s1">&#39;hi&#39;</span><span class="p">,</span> <span class="n">use_paging</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above call is equivalent to the unbuffered call:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">somedef</span><span class="p">(</span><span class="mi">17</span><span class="p">,</span> <span class="s1">&#39;hi&#39;</span><span class="p">,</span> <span class="n">use_paging</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="decorating">
+<h2>Decorating<a class="headerlink" href="#decorating" title="Permalink to this headline">¶</a></h2>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.2.5.</span></p>
+</div>
+<p>Somewhat like a filter for a <code class="docutils literal"><span class="pre">%def</span></code> but more flexible, the <code class="docutils literal"><span class="pre">decorator</span></code>
+argument to <code class="docutils literal"><span class="pre">%def</span></code> allows the creation of a function that will
+work in a similar manner to a Python decorator. The function can
+control whether or not the function executes. The original
+intent of this function is to allow the creation of custom cache
+logic, but there may be other uses as well.</p>
+<p><code class="docutils literal"><span class="pre">decorator</span></code> is intended to be used with a regular Python
+function, such as one defined in a library module. Here we&#8217;ll
+illustrate the python function defined in the template for
+simplicities&#8217; sake:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="n">fn</span><span class="p">):</span>
+        <span class="k">def</span> <span class="nf">decorate</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+            <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;BAR&quot;</span><span class="p">)</span>
+            <span class="n">fn</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+            <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;BAR&quot;</span><span class="p">)</span>
+            <span class="k">return</span> <span class="s1">&#39;&#39;</span>
+        <span class="k">return</span> <span class="n">decorate</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;foo()&quot;</span> <span class="na">decorator=</span><span class="s">&quot;bar&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is foo</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="n">foo</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above template will return, with more whitespace than this,
+<code class="docutils literal"><span class="pre">&quot;BAR</span> <span class="pre">this</span> <span class="pre">is</span> <span class="pre">foo</span> <span class="pre">BAR&quot;</span></code>. The function is the render callable
+itself (or possibly a wrapper around it), and by default will
+write to the context. To capture its output, use the <a class="reference internal" href="namespaces.html#mako.runtime.capture" title="mako.runtime.capture"><code class="xref py py-func docutils literal"><span class="pre">capture()</span></code></a>
+callable in the <code class="docutils literal"><span class="pre">mako.runtime</span></code> module (available in templates
+as just <code class="docutils literal"><span class="pre">runtime</span></code>):</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="n">fn</span><span class="p">):</span>
+        <span class="k">def</span> <span class="nf">decorate</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+            <span class="k">return</span> <span class="s2">&quot;BAR&quot;</span> <span class="o">+</span> <span class="n">runtime</span><span class="o">.</span><span class="n">capture</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">fn</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> <span class="o">+</span> <span class="s2">&quot;BAR&quot;</span>
+        <span class="k">return</span> <span class="n">decorate</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;foo()&quot;</span> <span class="na">decorator=</span><span class="s">&quot;bar&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is foo</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="n">foo</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The decorator can be used with top-level defs as well as nested
+defs, and blocks too. Note that when calling a top-level def from the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> API, i.e. <code class="docutils literal"><span class="pre">template.get_def('somedef').render()</span></code>,
+the decorator has to write the output to the <code class="docutils literal"><span class="pre">context</span></code>, i.e.
+as in the first example. The return value gets discarded.</p>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="inheritance.html" title="previous chapter">Inheritance</a>
+        Next:
+        <a href="unicode.html" title="next chapter">The Unicode Chapter</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/genindex.html b/doc/genindex.html
new file mode 100644 (file)
index 0000000..b6c6317
--- /dev/null
@@ -0,0 +1,1275 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+    Index
+ &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="#" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="#">Index</a>
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+    Index
+
+
+        <h2>
+            
+    Index
+
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+
+    <div id="docs-body" class="" >
+        
+
+
+
+   <h1 id="index">Index</h1>
+
+    <a href="#Symbols"><strong>Symbols</strong></a>
+    | <a href="#A"><strong>A</strong></a>
+    | <a href="#B"><strong>B</strong></a>
+    | <a href="#C"><strong>C</strong></a>
+    | <a href="#D"><strong>D</strong></a>
+    | <a href="#E"><strong>E</strong></a>
+    | <a href="#F"><strong>F</strong></a>
+    | <a href="#G"><strong>G</strong></a>
+    | <a href="#H"><strong>H</strong></a>
+    | <a href="#I"><strong>I</strong></a>
+    | <a href="#K"><strong>K</strong></a>
+    | <a href="#L"><strong>L</strong></a>
+    | <a href="#M"><strong>M</strong></a>
+    | <a href="#N"><strong>N</strong></a>
+    | <a href="#O"><strong>O</strong></a>
+    | <a href="#P"><strong>P</strong></a>
+    | <a href="#R"><strong>R</strong></a>
+    | <a href="#S"><strong>S</strong></a>
+    | <a href="#T"><strong>T</strong></a>
+    | <a href="#U"><strong>U</strong></a>
+    | <a href="#V"><strong>V</strong></a>
+    | <a href="#W"><strong>W</strong></a>
+
+   <hr />
+
+<h2 id="Symbols">Symbols</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.get.params.**kw">**kw (mako.cache.Cache.get parameter)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.Cache.invalidate.params.**kw">(mako.cache.Cache.invalidate parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.Cache.set.params.**kw">(mako.cache.Cache.set parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get.params.**kw">(mako.cache.CacheImpl.get parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get_or_create.params.**kw">(mako.cache.CacheImpl.get_or_create parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.invalidate.params.**kw">(mako.cache.CacheImpl.invalidate parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.set.params.**kw">(mako.cache.CacheImpl.set parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="A">A</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.adjust_uri">adjust_uri() (mako.lookup.TemplateCollection method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#mako.lookup.TemplateLookup.adjust_uri">(mako.lookup.TemplateLookup method)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.attr">attr (mako.runtime.Namespace attribute)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="B">B</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.ext.beaker_cache.BeakerCacheImpl">BeakerCacheImpl (class in mako.ext.beaker_cache)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.buffer_filters">buffer_filters (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.bytestring_passthrough">bytestring_passthrough (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="C">C</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache">Cache (class in mako.cache)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.cache">cache (mako.runtime.Namespace attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_args">cache_args (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_dir">cache_dir (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_enabled">cache_enabled (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_impl">cache_impl (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_type">cache_type (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.cache_url">cache_url (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.CacheImpl">CacheImpl (class in mako.cache)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.capture">capture() (in module mako.runtime)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.code">code (mako.template.Template attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.params.collection_size">collection_size (mako.lookup.TemplateLookup parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context">Context (class in mako.runtime)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.context">context (mako.runtime.Namespace attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.CacheImpl.get_or_create.params.creation_function">creation_function (mako.cache.CacheImpl.get_or_create parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.LoopContext.cycle">cycle() (mako.runtime.LoopContext method)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="D">D</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.default_filters">default_filters (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.DefTemplate">DefTemplate (class in mako.template)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.params.directories">directories (mako.lookup.TemplateLookup parameter)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.disable_unicode">disable_unicode (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="E">E</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.enable_loop">enable_loop (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.encoding_errors">encoding_errors (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#RichTraceback.error">error (RichTraceback attribute)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.error_handler">error_handler (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="F">F</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="namespaces.html#mako.runtime.ModuleNamespace.filename">filename (mako.runtime.ModuleNamespace attribute)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="namespaces.html#mako.runtime.Namespace.filename">(mako.runtime.Namespace attribute)</a>
+      </dt>
+      <dt><a href="namespaces.html#mako.runtime.TemplateNamespace.filename">(mako.runtime.TemplateNamespace attribute)</a>
+      </dt>
+      <dt><a href="usage.html#mako.template.Template.params.filename">(mako.template.Template parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.filename_to_uri">filename_to_uri() (mako.lookup.TemplateCollection method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#mako.lookup.TemplateLookup.filename_to_uri">(mako.lookup.TemplateLookup method)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.params.filesystem_checks">filesystem_checks (mako.lookup.TemplateLookup parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.format_exceptions">format_exceptions (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.future_imports">future_imports (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="G">G</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.get">get() (mako.cache.Cache method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get">(mako.cache.CacheImpl method)</a>
+      </dt>
+      <dt><a href="runtime.html#mako.runtime.Context.get">(mako.runtime.Context method)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.get_cached">get_cached() (mako.runtime.Namespace method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.get_def">get_def() (mako.template.Template method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.get_namespace">get_namespace() (mako.runtime.Namespace method)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.get_or_create">get_or_create() (mako.cache.Cache method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get_or_create">(mako.cache.CacheImpl method)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.get_template">get_template() (mako.lookup.TemplateCollection method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#mako.lookup.TemplateLookup.get_template">(mako.lookup.TemplateLookup method)</a>
+      </dt>
+      <dt><a href="namespaces.html#mako.runtime.Namespace.get_template">(mako.runtime.Namespace method)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="H">H</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.has_template">has_template() (mako.lookup.TemplateCollection method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.exceptions.html_error_template">html_error_template() (in module mako.exceptions)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="I">I</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.id">id (mako.cache.Cache attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.impl">impl (mako.cache.Cache attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.imports">imports (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.include_error_handler">include_error_handler (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.include_file">include_file() (mako.runtime.Namespace method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.input_encoding">input_encoding (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.invalidate">invalidate() (mako.cache.Cache method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.CacheImpl.invalidate">(mako.cache.CacheImpl method)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.invalidate_body">invalidate_body() (mako.cache.Cache method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.invalidate_closure">invalidate_closure() (mako.cache.Cache method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.invalidate_def">invalidate_def() (mako.cache.Cache method)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="K">K</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.get.params.key">key (mako.cache.Cache.get parameter)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.Cache.invalidate.params.key">(mako.cache.Cache.invalidate parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.Cache.set.params.key">(mako.cache.Cache.set parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get.params.key">(mako.cache.CacheImpl.get parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.get_or_create.params.key">(mako.cache.CacheImpl.get_or_create parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.invalidate.params.key">(mako.cache.CacheImpl.invalidate parameter)</a>
+      </dt>
+      <dt><a href="caching.html#mako.cache.CacheImpl.set.params.key">(mako.cache.CacheImpl.set parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.keys">keys() (mako.runtime.Context method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.kwargs">kwargs (mako.runtime.Context attribute)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="L">L</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.lexer_cls">lexer_cls (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#RichTraceback.lineno">lineno (RichTraceback attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.list_defs">list_defs() (mako.template.Template method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.lookup">lookup (mako.runtime.Context attribute)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#mako.template.Template.params.lookup">(mako.template.Template parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.LoopContext">LoopContext (class in mako.runtime)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="M">M</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#RichTraceback.message">message (RichTraceback attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.module">module (mako.runtime.Namespace attribute)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="namespaces.html#mako.runtime.TemplateNamespace.module">(mako.runtime.TemplateNamespace attribute)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.module_directory">module_directory (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.module_filename">module_filename (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.module_writer">module_writer (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.params.modulename_callable">modulename_callable (mako.lookup.TemplateLookup parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.ModuleNamespace">ModuleNamespace (class in mako.runtime)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="N">N</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace">Namespace (class in mako.runtime)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="O">O</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.output_encoding">output_encoding (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="P">P</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.CacheImpl.pass_context">pass_context (mako.cache.CacheImpl attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.pop_caller">pop_caller() (mako.runtime.Context method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.preprocessor">preprocessor (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.push_caller">push_caller() (mako.runtime.Context method)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.put">put() (mako.cache.Cache method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.put_string">put_string() (mako.lookup.TemplateLookup method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup.put_template">put_template() (mako.lookup.TemplateLookup method)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="R">R</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#RichTraceback.records">records (RichTraceback attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="caching.html#mako.cache.register_plugin">register_plugin() (in module mako.cache)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.get_template.params.relativeto">relativeto (mako.lookup.TemplateCollection.get_template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.render">render() (mako.template.Template method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.render_context">render_context() (mako.template.Template method)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.render_unicode">render_unicode() (mako.template.Template method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#RichTraceback.reverse_records">reverse_records (RichTraceback attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#RichTraceback.reverse_traceback">reverse_traceback (RichTraceback attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.exceptions.RichTraceback">RichTraceback (class in mako.exceptions)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="S">S</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.set">set() (mako.cache.Cache method)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.CacheImpl.set">(mako.cache.CacheImpl method)</a>
+      </dt>
+    </dl></dd>
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.source">source (mako.template.Template attribute)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#RichTraceback.source">(RichTraceback attribute)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.starttime">starttime (mako.cache.Cache attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.strict_undefined">strict_undefined (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.supports_caller">supports_caller() (in module mako.runtime)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="T">T</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="usage.html#mako.template.Template">Template (class in mako.template)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.Namespace.template">template (mako.runtime.Namespace attribute)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection">TemplateCollection (class in mako.lookup)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateLookup">TemplateLookup (class in mako.lookup)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+
+<dt>
+        <a href="namespaces.html#mako.runtime.TemplateNamespace">TemplateNamespace (class in mako.runtime)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.template.Template.params.text">text (mako.template.Template parameter)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.exceptions.text_error_template">text_error_template() (in module mako.exceptions)</a>
+</dt>
+
+
+  
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="U">U</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="runtime.html#mako.runtime.Undefined">Undefined (class in mako.runtime)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="usage.html#mako.lookup.TemplateCollection.get_template.params.uri">uri (mako.lookup.TemplateCollection.get_template parameter)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="usage.html#mako.lookup.TemplateCollection.has_template.params.uri">(mako.lookup.TemplateCollection.has_template parameter)</a>
+      </dt>
+      <dt><a href="namespaces.html#mako.runtime.Namespace.uri">(mako.runtime.Namespace attribute)</a>
+      </dt>
+      <dt><a href="namespaces.html#mako.runtime.TemplateNamespace.uri">(mako.runtime.TemplateNamespace attribute)</a>
+      </dt>
+      <dt><a href="usage.html#mako.template.Template.params.uri">(mako.template.Template parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="V">V</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="caching.html#mako.cache.Cache.set.params.value">value (mako.cache.Cache.set parameter)</a>
+</dt>
+
+    <dd><dl>
+      <dt><a href="caching.html#mako.cache.CacheImpl.set.params.value">(mako.cache.CacheImpl.set parameter)</a>
+      </dt>
+    </dl></dd>
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+<h2 id="W">W</h2>
+<table width="100%" class="indextable genindextable"><tr><td width="33%" valign="top">
+<dl>
+    
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.write">write() (mako.runtime.Context method)</a>
+</dt>
+
+
+  
+
+
+<dt>
+        <a href="runtime.html#mako.runtime.Context.writer">writer() (mako.runtime.Context method)</a>
+</dt>
+
+
+  
+     
+        </dl></td><td width="33%" valign="top"><dl>
+
+<dt></dt></dl>
+</td></tr></table>
+
+
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/index.html b/doc/index.html
new file mode 100644 (file)
index 0000000..e09b6b5
--- /dev/null
@@ -0,0 +1,248 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="#" />
+        <link rel="next" title="Usage" href="usage.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Next:
+            <a href="usage.html" title="next chapter">Usage</a>
+            </li>
+
+        <li>
+            <a href="#">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/index.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="#">Mako 1.0.6 Documentation</a>
+
+        <h2>
+            
+                Table of Contents
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+
+    <div id="docs-body" class="" >
+        
+<div class="section" id="table-of-contents">
+<h1>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline">¶</a></h1>
+<div class="toctree-wrapper compound">
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="usage.html">Usage</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#basic-usage">Basic Usage</a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#using-file-based-templates">Using File-Based Templates</a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#using-templatelookup">Using <code class="docutils literal"><span class="pre">TemplateLookup</span></code></a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#using-unicode-and-encoding">Using Unicode and Encoding</a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#handling-exceptions">Handling Exceptions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#common-framework-integrations">Common Framework Integrations</a></li>
+<li class="toctree-l2"><a class="reference internal" href="usage.html#api-reference">API Reference</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="syntax.html">Syntax</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#expression-substitution">Expression Substitution</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#expression-escaping">Expression Escaping</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#control-structures">Control Structures</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#comments">Comments</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#newline-filters">Newline Filters</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#python-blocks">Python Blocks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#module-level-blocks">Module-level Blocks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#tags">Tags</a></li>
+<li class="toctree-l2"><a class="reference internal" href="syntax.html#exiting-early-from-a-template">Exiting Early from a Template</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="defs.html">Defs and Blocks</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="defs.html#using-defs">Using Defs</a></li>
+<li class="toctree-l2"><a class="reference internal" href="defs.html#using-blocks">Using Blocks</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="runtime.html">The Mako Runtime Environment</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="runtime.html#context">Context</a></li>
+<li class="toctree-l2"><a class="reference internal" href="runtime.html#the-loop-context">The Loop Context</a></li>
+<li class="toctree-l2"><a class="reference internal" href="runtime.html#all-the-built-in-names">All the Built-in Names</a></li>
+<li class="toctree-l2"><a class="reference internal" href="runtime.html#api-reference">API Reference</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="namespaces.html">Namespaces</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#ways-to-call-namespaces">Ways to Call Namespaces</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#namespaces-from-regular-python-modules">Namespaces from Regular Python Modules</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#declaring-defs-in-namespaces">Declaring Defs in Namespaces</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#the-body-method">The <code class="docutils literal"><span class="pre">body()</span></code> Method</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#built-in-namespaces">Built-in Namespaces</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#inheritable-namespaces">Inheritable Namespaces</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#namespace-api-usage-example-static-dependencies">Namespace API Usage Example - Static Dependencies</a></li>
+<li class="toctree-l2"><a class="reference internal" href="namespaces.html#api-reference">API Reference</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="inheritance.html">Inheritance</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#nesting-blocks">Nesting Blocks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#rendering-a-named-block-multiple-times">Rendering a Named Block Multiple Times</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#but-what-about-defs">But what about Defs?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#using-the-next-namespace-to-produce-content-wrapping">Using the <code class="docutils literal"><span class="pre">next</span></code> Namespace to Produce Content Wrapping</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#using-the-parent-namespace-to-augment-defs">Using the <code class="docutils literal"><span class="pre">parent</span></code> Namespace to Augment Defs</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#using-include-with-template-inheritance">Using <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> with Template Inheritance</a></li>
+<li class="toctree-l2"><a class="reference internal" href="inheritance.html#inheritable-attributes">Inheritable Attributes</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="filtering.html">Filtering and Buffering</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="filtering.html#expression-filtering">Expression Filtering</a></li>
+<li class="toctree-l2"><a class="reference internal" href="filtering.html#filtering-defs-and-blocks">Filtering Defs and Blocks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="filtering.html#buffering">Buffering</a></li>
+<li class="toctree-l2"><a class="reference internal" href="filtering.html#decorating">Decorating</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="unicode.html">The Unicode Chapter</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="unicode.html#specifying-the-encoding-of-a-template-file">Specifying the Encoding of a Template File</a></li>
+<li class="toctree-l2"><a class="reference internal" href="unicode.html#handling-expressions">Handling Expressions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="unicode.html#defining-output-encoding">Defining Output Encoding</a></li>
+<li class="toctree-l2"><a class="reference internal" href="unicode.html#saying-to-heck-with-it-disabling-the-usage-of-unicode-entirely">Saying to Heck with It: Disabling the Usage of Unicode Entirely</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="caching.html">Caching</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="caching.html#cache-arguments">Cache Arguments</a></li>
+<li class="toctree-l2"><a class="reference internal" href="caching.html#programmatic-cache-access">Programmatic Cache Access</a></li>
+<li class="toctree-l2"><a class="reference internal" href="caching.html#cache-plugins">Cache Plugins</a></li>
+<li class="toctree-l2"><a class="reference internal" href="caching.html#api-reference">API Reference</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="changelog.html">Changelog</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="changelog.html#id1">1.0</a></li>
+<li class="toctree-l2"><a class="reference internal" href="changelog.html#id2">0.9</a></li>
+<li class="toctree-l2"><a class="reference internal" href="changelog.html#id3">0.8</a></li>
+<li class="toctree-l2"><a class="reference internal" href="changelog.html#id4">0.7</a></li>
+<li class="toctree-l2"><a class="reference internal" href="changelog.html#older-versions">Older Versions</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="indices-and-tables">
+<h2>Indices and Tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h2>
+<ul class="simple">
+<li><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></li>
+<li><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></li>
+</ul>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Next:
+        <a href="usage.html" title="next chapter">Usage</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/inheritance.html b/doc/inheritance.html
new file mode 100644 (file)
index 0000000..aa83ae3
--- /dev/null
@@ -0,0 +1,778 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Inheritance
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Filtering and Buffering" href="filtering.html" />
+        <link rel="prev" title="Namespaces" href="namespaces.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="namespaces.html" title="previous chapter">Namespaces</a>
+            </li>
+            <li>Next:
+            <a href="filtering.html" title="next chapter">Filtering and Buffering</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/inheritance.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Inheritance
+            
+
+        <h2>
+            
+                Inheritance
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Inheritance</a><ul>
+<li><a class="reference internal" href="#nesting-blocks">Nesting Blocks</a></li>
+<li><a class="reference internal" href="#rendering-a-named-block-multiple-times">Rendering a Named Block Multiple Times</a></li>
+<li><a class="reference internal" href="#but-what-about-defs">But what about Defs?</a></li>
+<li><a class="reference internal" href="#using-the-next-namespace-to-produce-content-wrapping">Using the <code class="docutils literal"><span class="pre">next</span></code> Namespace to Produce Content Wrapping</a></li>
+<li><a class="reference internal" href="#using-the-parent-namespace-to-augment-defs">Using the <code class="docutils literal"><span class="pre">parent</span></code> Namespace to Augment Defs</a></li>
+<li><a class="reference internal" href="#using-include-with-template-inheritance">Using <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> with Template Inheritance</a></li>
+<li><a class="reference internal" href="#inheritable-attributes">Inheritable Attributes</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="namespaces.html" title="previous chapter">Namespaces</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="filtering.html" title="next chapter">Filtering and Buffering</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="inheritance">
+<span id="inheritance-toplevel"></span><h1>Inheritance<a class="headerlink" href="#inheritance" title="Permalink to this headline">¶</a></h1>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">Most of the inheritance examples here take advantage of a feature that&#8217;s
+new in Mako as of version 0.4.1 called the &#8220;block&#8221;.  This tag is very similar to
+the &#8220;def&#8221; tag but is more streamlined for usage with inheritance.  Note that
+all of the examples here which use blocks can also use defs instead.  Contrasting
+usages will be illustrated.</p>
+</div>
+<p>Using template inheritance, two or more templates can organize
+themselves into an <strong>inheritance chain</strong>, where content and
+functions from all involved templates can be intermixed. The
+general paradigm of template inheritance is this: if a template
+<code class="docutils literal"><span class="pre">A</span></code> inherits from template <code class="docutils literal"><span class="pre">B</span></code>, then template <code class="docutils literal"><span class="pre">A</span></code> agrees
+to send the executional control to template <code class="docutils literal"><span class="pre">B</span></code> at runtime
+(<code class="docutils literal"><span class="pre">A</span></code> is called the <strong>inheriting</strong> template). Template <code class="docutils literal"><span class="pre">B</span></code>,
+the <strong>inherited</strong> template, then makes decisions as to what
+resources from <code class="docutils literal"><span class="pre">A</span></code> shall be executed.</p>
+<p>In practice, it looks like this. Here&#8217;s a hypothetical inheriting
+template, <code class="docutils literal"><span class="pre">index.html</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is some header content</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">this is the body content.</span>
+</pre></div>
+</div>
+<p>And <code class="docutils literal"><span class="pre">base.html</span></code>, the inherited template:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        &lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="x">        &lt;div class=&quot;footer&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;footer&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">                this is the footer</span>
+<span class="x">            </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>Here is a breakdown of the execution:</p>
+<ol class="arabic">
+<li><p class="first">When <code class="docutils literal"><span class="pre">index.html</span></code> is rendered, control immediately passes to
+<code class="docutils literal"><span class="pre">base.html</span></code>.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">base.html</span></code> then renders the top part of an HTML document,
+then invokes the <code class="docutils literal"><span class="pre">&lt;%block</span> <span class="pre">name=&quot;header&quot;&gt;</span></code> block.  It invokes the
+underlying <code class="docutils literal"><span class="pre">header()</span></code> function off of a built-in namespace
+called <code class="docutils literal"><span class="pre">self</span></code> (this namespace was first introduced in the
+<a class="reference internal" href="namespaces.html"><span class="doc">Namespaces chapter</span></a> in <a class="reference internal" href="namespaces.html#namespace-self"><span class="std std-ref">self</span></a>). Since
+<code class="docutils literal"><span class="pre">index.html</span></code> is the topmost template and also defines a block
+called <code class="docutils literal"><span class="pre">header</span></code>, it&#8217;s this <code class="docutils literal"><span class="pre">header</span></code> block that ultimately gets
+executed &#8211; instead of the one that&#8217;s present in <code class="docutils literal"><span class="pre">base.html</span></code>.</p>
+</li>
+<li><p class="first">Control comes back to <code class="docutils literal"><span class="pre">base.html</span></code>. Some more HTML is
+rendered.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">base.html</span></code> executes <code class="docutils literal"><span class="pre">self.body()</span></code>. The <code class="docutils literal"><span class="pre">body()</span></code>
+function on all template-based namespaces refers to the main
+body of the template, therefore the main body of
+<code class="docutils literal"><span class="pre">index.html</span></code> is rendered.</p>
+</li>
+<li><p class="first">When <code class="docutils literal"><span class="pre">&lt;%block</span> <span class="pre">name=&quot;header&quot;&gt;</span></code> is encountered in <code class="docutils literal"><span class="pre">index.html</span></code>
+during the <code class="docutils literal"><span class="pre">self.body()</span></code> call, a conditional is checked &#8211; does the
+current inherited template, i.e. <code class="docutils literal"><span class="pre">base.html</span></code>, also define this block? If yes,
+the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> is <strong>not</strong> executed here &#8211; the inheritance
+mechanism knows that the parent template is responsible for rendering
+this block (and in fact it already has).  In other words a block
+only renders in its <em>basemost scope</em>.</p>
+</li>
+<li><p class="first">Control comes back to <code class="docutils literal"><span class="pre">base.html</span></code>. More HTML is rendered,
+then the <code class="docutils literal"><span class="pre">&lt;%block</span> <span class="pre">name=&quot;footer&quot;&gt;</span></code> expression is invoked.</p>
+</li>
+<li><p class="first">The <code class="docutils literal"><span class="pre">footer</span></code> block is only defined in <code class="docutils literal"><span class="pre">base.html</span></code>, so being
+the topmost definition of <code class="docutils literal"><span class="pre">footer</span></code>, it&#8217;s the one that
+executes. If <code class="docutils literal"><span class="pre">index.html</span></code> also specified <code class="docutils literal"><span class="pre">footer</span></code>, then
+its version would <strong>override</strong> that of the base.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">base.html</span></code> finishes up rendering its HTML and the template
+is complete, producing:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;header&quot;</span><span class="p">&gt;</span>
+            this is some header content
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+        this is the body content.
+
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;footer&quot;</span><span class="p">&gt;</span>
+            this is the footer
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+</li>
+</ol>
+<p>...and that is template inheritance in a nutshell. The main idea
+is that the methods that you call upon <code class="docutils literal"><span class="pre">self</span></code> always
+correspond to the topmost definition of that method. Very much
+the way <code class="docutils literal"><span class="pre">self</span></code> works in a Python class, even though Mako is
+not actually using Python class inheritance to implement this
+functionality. (Mako doesn&#8217;t take the &#8220;inheritance&#8221; metaphor too
+seriously; while useful to setup some commonly recognized
+semantics, a textual template is not very much like an
+object-oriented class construct in practice).</p>
+<div class="section" id="nesting-blocks">
+<h2>Nesting Blocks<a class="headerlink" href="#nesting-blocks" title="Permalink to this headline">¶</a></h2>
+<p>The named blocks defined in an inherited template can also be nested within
+other blocks.  The name given to each block is globally accessible via any inheriting
+template.  We can add a new block <code class="docutils literal"><span class="pre">title</span></code> to our <code class="docutils literal"><span class="pre">header</span></code> block:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        &lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">                &lt;h2&gt;</span>
+<span class="x">                    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">                &lt;/h2&gt;</span>
+<span class="x">            </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="x">        &lt;div class=&quot;footer&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;footer&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">                this is the footer</span>
+<span class="x">            </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>The inheriting template can name either or both of <code class="docutils literal"><span class="pre">header</span></code> and <code class="docutils literal"><span class="pre">title</span></code>, separately
+or nested themselves:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is some header content</span>
+<span class="x">    </span><span class="cp">${</span><span class="n">parent</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is the title</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">this is the body content.</span>
+</pre></div>
+</div>
+<p>Note when we overrode <code class="docutils literal"><span class="pre">header</span></code>, we added an extra call <code class="docutils literal"><span class="pre">${parent.header()}</span></code> in order to invoke
+the parent&#8217;s <code class="docutils literal"><span class="pre">header</span></code> block in addition to our own.  That&#8217;s described in more detail below,
+in <a class="reference internal" href="#parent-namespace"><span class="std std-ref">Using the parent Namespace to Augment Defs</span></a>.</p>
+</div>
+<div class="section" id="rendering-a-named-block-multiple-times">
+<h2>Rendering a Named Block Multiple Times<a class="headerlink" href="#rendering-a-named-block-multiple-times" title="Permalink to this headline">¶</a></h2>
+<p>Recall from the section <a class="reference internal" href="defs.html#blocks"><span class="std std-ref">Using Blocks</span></a> that a named block is just like a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>,
+with some different usage rules.  We can call one of our named sections distinctly, for example
+a section that is used more than once, such as the title of a page:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;head&gt;</span>
+<span class="x">        &lt;title&gt;</span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="cp">}</span><span class="x">&lt;/title&gt;</span>
+<span class="x">    &lt;/head&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;h2&gt;</span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">/&gt;</span><span class="x">&lt;/h2&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>Where above an inheriting template can define <code class="docutils literal"><span class="pre">&lt;%block</span> <span class="pre">name=&quot;title&quot;&gt;</span></code> just once, and it will be
+used in the base template both in the <code class="docutils literal"><span class="pre">&lt;title&gt;</span></code> section as well as the <code class="docutils literal"><span class="pre">&lt;h2&gt;</span></code>.</p>
+</div>
+<div class="section" id="but-what-about-defs">
+<h2>But what about Defs?<a class="headerlink" href="#but-what-about-defs" title="Permalink to this headline">¶</a></h2>
+<p>The previous example used the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> tag to produce areas of content
+to be overridden.  Before Mako 0.4.1, there wasn&#8217;t any such tag &#8211; instead
+there was only the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> tag.   As it turns out, named blocks and defs are
+largely interchangeable.  The def simply doesn&#8217;t call itself automatically,
+and has more open-ended naming and scoping rules that are more flexible and similar
+to Python itself, but less suited towards layout.  The first example from
+this chapter using defs would look like:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is some header content</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">this is the body content.</span>
+</pre></div>
+</div>
+<p>And <code class="docutils literal"><span class="pre">base.html</span></code>, the inherited template:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        &lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="x">        &lt;div class=&quot;footer&quot;&gt;</span>
+<span class="x">            </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">footer</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;footer()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is the footer</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Above, we illustrate that defs differ from blocks in that their definition
+and invocation are defined in two separate places, instead of at once. You can <em>almost</em> do exactly what a
+block does if you put the two together:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">&gt;&lt;/%</span><span class="nb">def</span><span class="cp">&gt;${</span><span class="bp">self</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> is obviously more streamlined than the <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> for this kind
+of usage.  In addition,
+the above &#8220;inline&#8221; approach with <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> does not work with nesting:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;head&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;title&gt;</span>
+<span class="x">        ## this won&#39;t work !</span>
+<span class="x">        </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;title()&quot;</span><span class="cp">&gt;</span><span class="x">default title</span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;${</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/title&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;${</span><span class="bp">self</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/head&gt;</span>
+</pre></div>
+</div>
+<p>Where above, the <code class="docutils literal"><span class="pre">title()</span></code> def, because it&#8217;s a def within a def, is not part of the
+template&#8217;s exported namespace and will not be part of <code class="docutils literal"><span class="pre">self</span></code>.  If the inherited template
+did define its own <code class="docutils literal"><span class="pre">title</span></code> def at the top level, it would be called, but the &#8220;default title&#8221;
+above is not present at all on <code class="docutils literal"><span class="pre">self</span></code> no matter what.  For this to work as expected
+you&#8217;d instead need to say:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;head&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;header()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;title&gt;</span>
+<span class="x">        </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">        &lt;/title&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;${</span><span class="bp">self</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;title()&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">&lt;/head&gt;</span>
+</pre></div>
+</div>
+<p>That is, <code class="docutils literal"><span class="pre">title</span></code> is defined outside of any other defs so that it is in the <code class="docutils literal"><span class="pre">self</span></code> namespace.
+It works, but the definition needs to be potentially far away from the point of render.</p>
+<p>A named block is always placed in the <code class="docutils literal"><span class="pre">self</span></code> namespace, regardless of nesting,
+so this restriction is lifted:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="x">&lt;head&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;title&gt;</span>
+<span class="x">        </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">        &lt;/title&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">&lt;/head&gt;</span>
+</pre></div>
+</div>
+<p>The above template defines <code class="docutils literal"><span class="pre">title</span></code> inside of <code class="docutils literal"><span class="pre">header</span></code>, and an inheriting template can define
+one or both in <strong>any</strong> configuration, nested inside each other or not, in order for them to be used:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    the title</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    the header</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>So while the <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> tag lifts the restriction of nested blocks not being available externally,
+in order to achieve this it <em>adds</em> the restriction that all block names in a single template need
+to be globally unique within the template, and additionally that a <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> can&#8217;t be defined
+inside of a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>. It&#8217;s a more restricted tag suited towards a more specific use case than <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>.</p>
+</div>
+<div class="section" id="using-the-next-namespace-to-produce-content-wrapping">
+<h2>Using the <code class="docutils literal"><span class="pre">next</span></code> Namespace to Produce Content Wrapping<a class="headerlink" href="#using-the-next-namespace-to-produce-content-wrapping" title="Permalink to this headline">¶</a></h2>
+<p>Sometimes you have an inheritance chain that spans more than two
+templates. Or maybe you don&#8217;t, but you&#8217;d like to build your
+system such that extra inherited templates can be inserted in
+the middle of a chain where they would be smoothly integrated.
+If each template wants to define its layout just within its main
+body, you can&#8217;t just call <code class="docutils literal"><span class="pre">self.body()</span></code> to get at the
+inheriting template&#8217;s body, since that is only the topmost body.
+To get at the body of the <em>next</em> template, you call upon the
+namespace <code class="docutils literal"><span class="pre">next</span></code>, which is the namespace of the template
+<strong>immediately following</strong> the current template.</p>
+<p>Lets change the line in <code class="docutils literal"><span class="pre">base.html</span></code> which calls upon
+<code class="docutils literal"><span class="pre">self.body()</span></code> to instead call upon <code class="docutils literal"><span class="pre">next.body()</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">        &lt;div class=&quot;header&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+
+<span class="x">        </span><span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+
+<span class="x">        &lt;div class=&quot;footer&quot;&gt;</span>
+<span class="x">            </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;footer&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">                this is the footer</span>
+<span class="x">            </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;/div&gt;</span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>Lets also add an intermediate template called <code class="docutils literal"><span class="pre">layout.html</span></code>,
+which inherits from <code class="docutils literal"><span class="pre">base.html</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## layout.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="x">&lt;ul&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;toolbar&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;li&gt;selection 1&lt;/li&gt;</span>
+<span class="x">        &lt;li&gt;selection 2&lt;/li&gt;</span>
+<span class="x">        &lt;li&gt;selection 3&lt;/li&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">&lt;/ul&gt;</span>
+<span class="x">&lt;div class=&quot;mainlayout&quot;&gt;</span>
+<span class="x">    </span><span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>And finally change <code class="docutils literal"><span class="pre">index.html</span></code> to inherit from
+<code class="docutils literal"><span class="pre">layout.html</span></code> instead:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;layout.html&quot;</span><span class="cp">/&gt;</span>
+
+<span class="cp">## .. rest of template</span><span class="x"></span>
+</pre></div>
+</div>
+<p>In this setup, each call to <code class="docutils literal"><span class="pre">next.body()</span></code> will render the body
+of the next template in the inheritance chain (which can be
+written as <code class="docutils literal"><span class="pre">base.html</span> <span class="pre">-&gt;</span> <span class="pre">layout.html</span> <span class="pre">-&gt;</span> <span class="pre">index.html</span></code>). Control
+is still first passed to the bottommost template <code class="docutils literal"><span class="pre">base.html</span></code>,
+and <code class="docutils literal"><span class="pre">self</span></code> still references the topmost definition of any
+particular def.</p>
+<p>The output we get would be:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;header&quot;</span><span class="p">&gt;</span>
+            this is some header content
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 1<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 2<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 3<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+        <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;mainlayout&quot;</span><span class="p">&gt;</span>
+        this is the body content.
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;footer&quot;</span><span class="p">&gt;</span>
+            this is the footer
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>So above, we have the <code class="docutils literal"><span class="pre">&lt;html&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;body&gt;</span></code> and
+<code class="docutils literal"><span class="pre">header</span></code>/<code class="docutils literal"><span class="pre">footer</span></code> layout of <code class="docutils literal"><span class="pre">base.html</span></code>, we have the
+<code class="docutils literal"><span class="pre">&lt;ul&gt;</span></code> and <code class="docutils literal"><span class="pre">mainlayout</span></code> section of <code class="docutils literal"><span class="pre">layout.html</span></code>, and the
+main body of <code class="docutils literal"><span class="pre">index.html</span></code> as well as its overridden <code class="docutils literal"><span class="pre">header</span></code>
+def. The <code class="docutils literal"><span class="pre">layout.html</span></code> template is inserted into the middle of
+the chain without <code class="docutils literal"><span class="pre">base.html</span></code> having to change anything.
+Without the <code class="docutils literal"><span class="pre">next</span></code> namespace, only the main body of
+<code class="docutils literal"><span class="pre">index.html</span></code> could be used; there would be no way to call
+<code class="docutils literal"><span class="pre">layout.html</span></code>&#8216;s body content.</p>
+</div>
+<div class="section" id="using-the-parent-namespace-to-augment-defs">
+<span id="parent-namespace"></span><h2>Using the <code class="docutils literal"><span class="pre">parent</span></code> Namespace to Augment Defs<a class="headerlink" href="#using-the-parent-namespace-to-augment-defs" title="Permalink to this headline">¶</a></h2>
+<p>Lets now look at the other inheritance-specific namespace, the
+opposite of <code class="docutils literal"><span class="pre">next</span></code> called <code class="docutils literal"><span class="pre">parent</span></code>. <code class="docutils literal"><span class="pre">parent</span></code> is the
+namespace of the template <strong>immediately preceding</strong> the current
+template. What&#8217;s useful about this namespace is that
+defs or blocks can call upon their overridden versions.
+This is not as hard as it sounds and
+is very much like using the <code class="docutils literal"><span class="pre">super</span></code> keyword in Python. Lets
+modify <code class="docutils literal"><span class="pre">index.html</span></code> to augment the list of selections provided
+by the <code class="docutils literal"><span class="pre">toolbar</span></code> function in <code class="docutils literal"><span class="pre">layout.html</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;layout.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is some header content</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;toolbar&quot;</span><span class="cp">&gt;</span>
+    <span class="cp">## call the parent&#39;s toolbar first</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="n">parent</span><span class="o">.</span><span class="n">toolbar</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    &lt;li&gt;selection 4&lt;/li&gt;</span>
+<span class="x">    &lt;li&gt;selection 5&lt;/li&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="x">this is the body content.</span>
+</pre></div>
+</div>
+<p>Above, we implemented a <code class="docutils literal"><span class="pre">toolbar()</span></code> function, which is meant
+to override the definition of <code class="docutils literal"><span class="pre">toolbar</span></code> within the inherited
+template <code class="docutils literal"><span class="pre">layout.html</span></code>. However, since we want the content
+from that of <code class="docutils literal"><span class="pre">layout.html</span></code> as well, we call it via the
+<code class="docutils literal"><span class="pre">parent</span></code> namespace whenever we want it&#8217;s content, in this case
+before we add our own selections. So the output for the whole
+thing is now:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;header&quot;</span><span class="p">&gt;</span>
+            this is some header content
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 1<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 2<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 3<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 4<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+            <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>selection 5<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+        <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;mainlayout&quot;</span><span class="p">&gt;</span>
+        this is the body content.
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+
+        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;footer&quot;</span><span class="p">&gt;</span>
+            this is the footer
+        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+    <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<p>and you&#8217;re now a template inheritance ninja!</p>
+</div>
+<div class="section" id="using-include-with-template-inheritance">
+<h2>Using <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> with Template Inheritance<a class="headerlink" href="#using-include-with-template-inheritance" title="Permalink to this headline">¶</a></h2>
+<p>A common source of confusion is the behavior of the <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag,
+often in conjunction with its interaction within template inheritance.
+Key to understanding the <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag is that it is a <em>dynamic</em>, e.g.
+runtime, include, and not a static include.   The <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> is only processed
+as the template renders, and not at inheritance setup time.   When encountered,
+the referenced template is run fully as an entirely separate template with no
+linkage to any current inheritance structure.</p>
+<p>If the tag were on the other hand a <em>static</em> include, this would allow source
+within the included template to interact within the same inheritance context
+as the calling template, but currently Mako has no static include facility.</p>
+<p>In practice, this means that <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> elements defined in an <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code>
+file will not interact with corresponding <code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code> elements in the calling
+template.</p>
+<p>A common mistake is along these lines:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## partials.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Global Header</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+
+<span class="cp">## parent.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;partials.mako&quot;</span><span class="cp">&gt;</span>
+
+<span class="cp">## child.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;parent.mako&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Custom Header</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Above, one might expect that the <code class="docutils literal"><span class="pre">&quot;header&quot;</span></code> block declared in <code class="docutils literal"><span class="pre">child.mako</span></code>
+might be invoked, as a result of it overriding the same block present in
+<code class="docutils literal"><span class="pre">parent.mako</span></code> via the include for <code class="docutils literal"><span class="pre">partials.mako</span></code>.  But this is not the case.
+Instead, <code class="docutils literal"><span class="pre">parent.mako</span></code> will invoke <code class="docutils literal"><span class="pre">partials.mako</span></code>, which then invokes
+<code class="docutils literal"><span class="pre">&quot;header&quot;</span></code> in <code class="docutils literal"><span class="pre">partials.mako</span></code>, and then is finished rendering.  Nothing
+from <code class="docutils literal"><span class="pre">child.mako</span></code> will render; there is no interaction between the <code class="docutils literal"><span class="pre">&quot;header&quot;</span></code>
+block in <code class="docutils literal"><span class="pre">child.mako</span></code> and the <code class="docutils literal"><span class="pre">&quot;header&quot;</span></code> block in <code class="docutils literal"><span class="pre">partials.mako</span></code>.</p>
+<p>Instead, <code class="docutils literal"><span class="pre">parent.mako</span></code> must explicitly state the inheritance structure.
+In order to call upon specific elements of <code class="docutils literal"><span class="pre">partials.mako</span></code>, we will call upon
+it as a namespace:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## partials.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Global Header</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+
+<span class="cp">## parent.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;partials&quot;</span> <span class="na">file=</span><span class="s">&quot;partials.mako&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="n">partials</span><span class="o">.</span><span class="n">header</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+
+<span class="cp">## child.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;parent.mako&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Custom Header</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Where above, <code class="docutils literal"><span class="pre">parent.mako</span></code> states the inheritance structure that <code class="docutils literal"><span class="pre">child.mako</span></code>
+is to participate within.  <code class="docutils literal"><span class="pre">partials.mako</span></code> only defines defs/blocks that can be
+used on a per-name basis.</p>
+<p>Another scenario is below, which results in both <code class="docutils literal"><span class="pre">&quot;SectionA&quot;</span></code> blocks being rendered for the <code class="docutils literal"><span class="pre">child.mako</span></code> document:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.mako</span><span class="x"></span>
+<span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;SectionA&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    base.mako</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span>
+
+<span class="cp">## parent.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.mako&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;child.mako&quot;</span><span class="cp">&gt;</span>
+
+<span class="cp">## child.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;SectionA&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    child.mako</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The resolution is similar; instead of using <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code>, we call upon the blocks
+of <code class="docutils literal"><span class="pre">child.mako</span></code> using a namespace:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## parent.mako</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.mako&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;child&quot;</span> <span class="na">file=</span><span class="s">&quot;child.mako&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;SectionA&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="n">child</span><span class="o">.</span><span class="n">SectionA</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="inheritable-attributes">
+<span id="inheritance-attr"></span><h2>Inheritable Attributes<a class="headerlink" href="#inheritable-attributes" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference internal" href="namespaces.html#mako.runtime.Namespace.attr" title="mako.runtime.Namespace.attr"><code class="xref py py-attr docutils literal"><span class="pre">attr</span></code></a> accessor of the <a class="reference internal" href="namespaces.html#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> object
+allows access to module level variables declared in a template. By accessing
+<code class="docutils literal"><span class="pre">self.attr</span></code>, you can access regular attributes from the
+inheritance chain as declared in <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code> sections. Such as:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="n">class_</span> <span class="o">=</span> <span class="s2">&quot;grey&quot;</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="x">&lt;div class=&quot;</span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">attr</span><span class="o">.</span><span class="n">class_</span><span class="cp">}</span><span class="x">&quot;&gt;</span>
+<span class="x">    </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>If an inheriting template overrides <code class="docutils literal"><span class="pre">class_</span></code> to be
+<code class="docutils literal"><span class="pre">&quot;white&quot;</span></code>, as in:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="n">class_</span> <span class="o">=</span> <span class="s2">&quot;white&quot;</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;parent.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">This is the body</span>
+</pre></div>
+</div>
+<p>you&#8217;ll get output like:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;white&quot;</span><span class="p">&gt;</span>
+    This is the body
+<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<p class="last"><a class="reference internal" href="namespaces.html#namespace-attr-for-includes"><span class="std std-ref">Version One - Use Namespace.attr</span></a> - a more sophisticated example using
+<a class="reference internal" href="namespaces.html#mako.runtime.Namespace.attr" title="mako.runtime.Namespace.attr"><code class="xref py py-attr docutils literal"><span class="pre">Namespace.attr</span></code></a>.</p>
+</div>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="namespaces.html" title="previous chapter">Namespaces</a>
+        Next:
+        <a href="filtering.html" title="next chapter">Filtering and Buffering</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/namespaces.html b/doc/namespaces.html
new file mode 100644 (file)
index 0000000..f91cd7d
--- /dev/null
@@ -0,0 +1,780 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Namespaces
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Inheritance" href="inheritance.html" />
+        <link rel="prev" title="The Mako Runtime Environment" href="runtime.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="runtime.html" title="previous chapter">The Mako Runtime Environment</a>
+            </li>
+            <li>Next:
+            <a href="inheritance.html" title="next chapter">Inheritance</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/namespaces.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Namespaces
+            
+
+        <h2>
+            
+                Namespaces
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Namespaces</a><ul>
+<li><a class="reference internal" href="#ways-to-call-namespaces">Ways to Call Namespaces</a></li>
+<li><a class="reference internal" href="#namespaces-from-regular-python-modules">Namespaces from Regular Python Modules</a></li>
+<li><a class="reference internal" href="#declaring-defs-in-namespaces">Declaring Defs in Namespaces</a></li>
+<li><a class="reference internal" href="#the-body-method">The <code class="docutils literal"><span class="pre">body()</span></code> Method</a></li>
+<li><a class="reference internal" href="#built-in-namespaces">Built-in Namespaces</a><ul>
+<li><a class="reference internal" href="#local"><code class="docutils literal"><span class="pre">local</span></code></a></li>
+<li><a class="reference internal" href="#self"><code class="docutils literal"><span class="pre">self</span></code></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#inheritable-namespaces">Inheritable Namespaces</a></li>
+<li><a class="reference internal" href="#namespace-api-usage-example-static-dependencies">Namespace API Usage Example - Static Dependencies</a><ul>
+<li><a class="reference internal" href="#version-one-use-namespace-attr">Version One - Use <code class="docutils literal"><span class="pre">Namespace.attr</span></code></a></li>
+<li><a class="reference internal" href="#version-two-use-a-specific-named-def">Version Two - Use a specific named def</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#api-reference">API Reference</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="runtime.html" title="previous chapter">The Mako Runtime Environment</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="inheritance.html" title="next chapter">Inheritance</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="namespaces">
+<span id="namespaces-toplevel"></span><h1>Namespaces<a class="headerlink" href="#namespaces" title="Permalink to this headline">¶</a></h1>
+<p>Namespaces are used to organize groups of defs into
+categories, and also to &#8220;import&#8221; defs from other files.</p>
+<p>If the file <code class="docutils literal"><span class="pre">components.html</span></code> defines these two defs:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## components.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;comp1()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is comp1</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;comp2(x)&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is comp2, x is </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>you can make another file, for example <code class="docutils literal"><span class="pre">index.html</span></code>, that
+pulls those two defs into a namespace called <code class="docutils literal"><span class="pre">comp</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## index.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;comp&quot;</span> <span class="na">file=</span><span class="s">&quot;components.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">Here&#39;s comp1:  </span><span class="cp">${</span><span class="n">comp</span><span class="o">.</span><span class="n">comp1</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">Here&#39;s comp2:  </span><span class="cp">${</span><span class="n">comp</span><span class="o">.</span><span class="n">comp2</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">comp</span></code> variable above is an instance of
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, a <strong>proxy object</strong> which delivers
+method calls to the underlying template callable using the
+current context.</p>
+<p><code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> also provides an <code class="docutils literal"><span class="pre">import</span></code> attribute which can
+be used to pull the names into the local namespace, removing the
+need to call it via the &#8220;<code class="docutils literal"><span class="pre">.</span></code>&#8221; operator. When <code class="docutils literal"><span class="pre">import</span></code> is used, the
+<code class="docutils literal"><span class="pre">name</span></code> attribute is optional.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">file=</span><span class="s">&quot;components.html&quot;</span> <span class="na">import=</span><span class="s">&quot;comp1, comp2&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">Heres comp1:  </span><span class="cp">${</span><span class="n">comp1</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">Heres comp2:  </span><span class="cp">${</span><span class="n">comp2</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p><code class="docutils literal"><span class="pre">import</span></code> also supports the &#8220;<code class="docutils literal"><span class="pre">*</span></code>&#8221; operator:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">file=</span><span class="s">&quot;components.html&quot;</span> <span class="na">import=</span><span class="s">&quot;*&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">Heres comp1:  </span><span class="cp">${</span><span class="n">comp1</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">Heres comp2:  </span><span class="cp">${</span><span class="n">comp2</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The names imported by the <code class="docutils literal"><span class="pre">import</span></code> attribute take precedence
+over any names that exist within the current context.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">In current versions of Mako, usage of <code class="docutils literal"><span class="pre">import='*'</span></code> is
+known to decrease performance of the template. This will be
+fixed in a future release.</p>
+</div>
+<p>The <code class="docutils literal"><span class="pre">file</span></code> argument allows expressions &#8211; if looking for
+context variables, the <code class="docutils literal"><span class="pre">context</span></code> must be named explicitly:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;dyn&quot;</span> <span class="na">file=</span><span class="s">&quot;${context[&#39;namespace_name&#39;]}&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<div class="section" id="ways-to-call-namespaces">
+<h2>Ways to Call Namespaces<a class="headerlink" href="#ways-to-call-namespaces" title="Permalink to this headline">¶</a></h2>
+<p>There are essentially four ways to call a function from a
+namespace.</p>
+<p>The &#8220;expression&#8221; format, as described previously. Namespaces are
+just Python objects with functions on them, and can be used in
+expressions like any other function:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">mynamespace</span><span class="o">.</span><span class="n">somefunction</span><span class="p">(</span><span class="s1">&#39;some arg1&#39;</span><span class="p">,</span> <span class="s1">&#39;some arg2&#39;</span><span class="p">,</span> <span class="n">arg3</span><span class="o">=</span><span class="s1">&#39;some arg3&#39;</span><span class="p">,</span> <span class="n">arg4</span><span class="o">=</span><span class="s1">&#39;some arg4&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Synonymous with the &#8220;expression&#8221; format is the &#8220;custom tag&#8221;
+format, when a &#8220;closed&#8221; tag is used. This format, introduced in
+Mako 0.2.3, allows the usage of a &#8220;custom&#8221; Mako tag, with the
+function arguments passed in using named attributes:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">mynamespace:somefunction</span> <span class="na">arg1=</span><span class="s">&quot;some arg1&quot;</span> <span class="na">arg2=</span><span class="s">&quot;some arg2&quot;</span> <span class="na">arg3=</span><span class="s">&quot;some arg3&quot;</span> <span class="na">arg4=</span><span class="s">&quot;some arg4&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>When using tags, the values of the arguments are taken as
+literal strings by default. To embed Python expressions as
+arguments, use the embedded expression format:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">mynamespace:somefunction</span> <span class="na">arg1=</span><span class="s">&quot;${someobject.format()}&quot;</span> <span class="na">arg2=</span><span class="s">&quot;${somedef(5, 12)}&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The &#8220;custom tag&#8221; format is intended mainly for namespace
+functions which recognize body content, which in Mako is known
+as a &#8220;def with embedded content&#8221;:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">mynamespace:somefunction</span> <span class="na">arg1=</span><span class="s">&quot;some argument&quot;</span> <span class="na">args=</span><span class="s">&quot;x, y&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Some record: </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x">, </span><span class="cp">${</span><span class="n">y</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">mynamespace:somefunction</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The &#8220;classic&#8221; way to call defs with embedded content is the <code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">call</span> <span class="na">expr=</span><span class="s">&quot;mynamespace.somefunction(arg1=&#39;some argument&#39;)&quot;</span> <span class="na">args=</span><span class="s">&quot;x, y&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    Some record: </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x">, </span><span class="cp">${</span><span class="n">y</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">call</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>For information on how to construct defs that embed content from
+the caller, see <a class="reference internal" href="defs.html#defs-with-content"><span class="std std-ref">Calling a Def with Embedded Content and/or Other Defs</span></a>.</p>
+</div>
+<div class="section" id="namespaces-from-regular-python-modules">
+<span id="namespaces-python-modules"></span><h2>Namespaces from Regular Python Modules<a class="headerlink" href="#namespaces-from-regular-python-modules" title="Permalink to this headline">¶</a></h2>
+<p>Namespaces can also import regular Python functions from
+modules. These callables need to take at least one argument,
+<code class="docutils literal"><span class="pre">context</span></code>, an instance of <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>. A module file
+<code class="docutils literal"><span class="pre">some/module.py</span></code> might contain the callable:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_tag</span><span class="p">(</span><span class="n">context</span><span class="p">):</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;hello world&quot;</span><span class="p">)</span>
+    <span class="k">return</span> <span class="s1">&#39;&#39;</span>
+</pre></div>
+</div>
+<p>A template can use this module via:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;hw&quot;</span> <span class="na">module=</span><span class="s">&quot;some.module&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="n">hw</span><span class="o">.</span><span class="n">my_tag</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Note that the <code class="docutils literal"><span class="pre">context</span></code> argument is not needed in the call;
+the <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> tag creates a locally-scoped callable which
+takes care of it. The <code class="docutils literal"><span class="pre">return</span> <span class="pre">''</span></code> is so that the def does not
+dump a <code class="docutils literal"><span class="pre">None</span></code> into the output stream &#8211; the return value of any
+def is rendered after the def completes, in addition to whatever
+was passed to <a class="reference internal" href="runtime.html#mako.runtime.Context.write" title="mako.runtime.Context.write"><code class="xref py py-meth docutils literal"><span class="pre">Context.write()</span></code></a> within its body.</p>
+<p>If your def is to be called in an &#8220;embedded content&#8221; context,
+that is as described in <a class="reference internal" href="defs.html#defs-with-content"><span class="std std-ref">Calling a Def with Embedded Content and/or Other Defs</span></a>, you should use
+the <a class="reference internal" href="#mako.runtime.supports_caller" title="mako.runtime.supports_caller"><code class="xref py py-func docutils literal"><span class="pre">supports_caller()</span></code></a> decorator, which will ensure that Mako
+will ensure the correct &#8220;caller&#8221; variable is available when your
+def is called, supporting embedded content:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.runtime</span> <span class="kn">import</span> <span class="n">supports_caller</span>
+
+<span class="nd">@supports_caller</span>
+<span class="k">def</span> <span class="nf">my_tag</span><span class="p">(</span><span class="n">context</span><span class="p">):</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&lt;div&gt;&quot;</span><span class="p">)</span>
+    <span class="n">context</span><span class="p">[</span><span class="s1">&#39;caller&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">body</span><span class="p">()</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;&lt;/div&gt;&quot;</span><span class="p">)</span>
+    <span class="k">return</span> <span class="s1">&#39;&#39;</span>
+</pre></div>
+</div>
+<p>Capturing of output is available as well, using the
+outside-of-templates version of the <a class="reference internal" href="#mako.runtime.capture" title="mako.runtime.capture"><code class="xref py py-func docutils literal"><span class="pre">capture()</span></code></a> function,
+which accepts the &#8220;context&#8221; as its first argument:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.runtime</span> <span class="kn">import</span> <span class="n">supports_caller</span><span class="p">,</span> <span class="n">capture</span>
+
+<span class="nd">@supports_caller</span>
+<span class="k">def</span> <span class="nf">my_tag</span><span class="p">(</span><span class="n">context</span><span class="p">):</span>
+    <span class="k">return</span> <span class="s2">&quot;&lt;div&gt;</span><span class="si">%s</span><span class="s2">&lt;/div&gt;&quot;</span> <span class="o">%</span> \
+            <span class="n">capture</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">context</span><span class="p">[</span><span class="s1">&#39;caller&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="declaring-defs-in-namespaces">
+<h2>Declaring Defs in Namespaces<a class="headerlink" href="#declaring-defs-in-namespaces" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag supports the definition of <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>s
+directly inside the tag. These defs become part of the namespace
+like any other function, and will override the definitions
+pulled in from a remote template or module:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## define a namespace</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;stuff&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;comp1()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        comp1</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">namespace</span><span class="cp">&gt;</span>
+
+<span class="cp">## then call it</span><span class="x"></span>
+<span class="cp">${</span><span class="n">stuff</span><span class="o">.</span><span class="n">comp1</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-body-method">
+<span id="namespaces-body"></span><h2>The <code class="docutils literal"><span class="pre">body()</span></code> Method<a class="headerlink" href="#the-body-method" title="Permalink to this headline">¶</a></h2>
+<p>Every namespace that is generated from a template contains a
+method called <code class="docutils literal"><span class="pre">body()</span></code>. This method corresponds to the main
+body of the template, and plays its most important roles when
+using inheritance relationships as well as
+def-calls-with-content.</p>
+<p>Since the <code class="docutils literal"><span class="pre">body()</span></code> method is available from a namespace just
+like all the other defs defined in a template, what happens if
+you send arguments to it? By default, the <code class="docutils literal"><span class="pre">body()</span></code> method
+accepts no positional arguments, and for usefulness in
+inheritance scenarios will by default dump all keyword arguments
+into a dictionary called <code class="docutils literal"><span class="pre">pageargs</span></code>. But if you actually want
+to get at the keyword arguments, Mako recommends you define your
+own argument signature explicitly. You do this via using the
+<code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">args=</span><span class="s">&quot;x, y, someval=8, scope=&#39;foo&#39;, **kwargs&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>A template which defines the above signature requires that the
+variables <code class="docutils literal"><span class="pre">x</span></code> and <code class="docutils literal"><span class="pre">y</span></code> are defined, defines default values
+for <code class="docutils literal"><span class="pre">someval</span></code> and <code class="docutils literal"><span class="pre">scope</span></code>, and sets up <code class="docutils literal"><span class="pre">**kwargs</span></code> to
+receive all other keyword arguments. If <code class="docutils literal"><span class="pre">**kwargs</span></code> or similar
+is not present, the argument <code class="docutils literal"><span class="pre">**pageargs</span></code> gets tacked on by
+Mako. When the template is called as a top-level template (i.e.
+via <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a>) or via the <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag, the
+values for these arguments will be pulled from the <code class="docutils literal"><span class="pre">Context</span></code>.
+In all other cases, i.e. via calling the <code class="docutils literal"><span class="pre">body()</span></code> method, the
+arguments are taken as ordinary arguments from the method call.
+So above, the body might be called as:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">someval</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span> <span class="n">delta</span><span class="o">=</span><span class="mi">7</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object also supplies a <a class="reference internal" href="runtime.html#mako.runtime.Context.kwargs" title="mako.runtime.Context.kwargs"><code class="xref py py-attr docutils literal"><span class="pre">kwargs</span></code></a>
+accessor, for cases when you&#8217;d like to pass along the top level context
+arguments to a <code class="docutils literal"><span class="pre">body()</span></code> callable:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">(</span><span class="o">**</span><span class="n">context</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The usefulness of calls like the above become more apparent when
+one works with inheriting templates. For more information on
+this, as well as the meanings of the names <code class="docutils literal"><span class="pre">self</span></code> and
+<code class="docutils literal"><span class="pre">next</span></code>, see <a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+</div>
+<div class="section" id="built-in-namespaces">
+<span id="namespaces-builtin"></span><h2>Built-in Namespaces<a class="headerlink" href="#built-in-namespaces" title="Permalink to this headline">¶</a></h2>
+<p>The namespace is so great that Mako gives your template one (or
+two) for free. The names of these namespaces are <code class="docutils literal"><span class="pre">local</span></code> and
+<code class="docutils literal"><span class="pre">self</span></code>. Other built-in namespaces include <code class="docutils literal"><span class="pre">parent</span></code> and
+<code class="docutils literal"><span class="pre">next</span></code>, which are optional and are described in
+<a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+<div class="section" id="local">
+<span id="namespace-local"></span><h3><code class="docutils literal"><span class="pre">local</span></code><a class="headerlink" href="#local" title="Permalink to this headline">¶</a></h3>
+<p>The <code class="docutils literal"><span class="pre">local</span></code> namespace is basically the namespace for the
+currently executing template. This means that all of the top
+level defs defined in your template, as well as your template&#8217;s
+<code class="docutils literal"><span class="pre">body()</span></code> function, are also available off of the <code class="docutils literal"><span class="pre">local</span></code>
+namespace.</p>
+<p>The <code class="docutils literal"><span class="pre">local</span></code> namespace is also where properties like <code class="docutils literal"><span class="pre">uri</span></code>,
+<code class="docutils literal"><span class="pre">filename</span></code>, and <code class="docutils literal"><span class="pre">module</span></code> and the <code class="docutils literal"><span class="pre">get_namespace</span></code> method
+can be particularly useful.</p>
+</div>
+<div class="section" id="self">
+<span id="namespace-self"></span><h3><code class="docutils literal"><span class="pre">self</span></code><a class="headerlink" href="#self" title="Permalink to this headline">¶</a></h3>
+<p>The <code class="docutils literal"><span class="pre">self</span></code> namespace, in the case of a template that does not
+use inheritance, is synonymous with <code class="docutils literal"><span class="pre">local</span></code>. If inheritance is
+used, then <code class="docutils literal"><span class="pre">self</span></code> references the topmost template in the
+inheritance chain, where it is most useful for providing the
+ultimate form of various &#8220;method&#8221; calls which may have been
+overridden at various points in an inheritance chain. See
+<a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+</div>
+</div>
+<div class="section" id="inheritable-namespaces">
+<h2>Inheritable Namespaces<a class="headerlink" href="#inheritable-namespaces" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag includes an optional attribute
+<code class="docutils literal"><span class="pre">inheritable=&quot;True&quot;</span></code>, which will cause the namespace to be
+attached to the <code class="docutils literal"><span class="pre">self</span></code> namespace. Since <code class="docutils literal"><span class="pre">self</span></code> is globally
+available throughout an inheritance chain (described in the next
+section), all the templates in an inheritance chain can get at
+the namespace imported in a super-template via <code class="docutils literal"><span class="pre">self</span></code>.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;foo&quot;</span> <span class="na">file=</span><span class="s">&quot;foo.html&quot;</span> <span class="na">inheritable=</span><span class="s">&quot;True&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span>
+
+<span class="cp">## somefile.html</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">foo</span><span class="o">.</span><span class="n">bar</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>This allows a super-template to load a whole bunch of namespaces
+that its inheriting templates can get to, without them having to
+explicitly load those namespaces themselves.</p>
+<p>The <code class="docutils literal"><span class="pre">import=&quot;*&quot;</span></code> part of the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag doesn&#8217;t yet
+interact with the <code class="docutils literal"><span class="pre">inheritable</span></code> flag, so currently you have to
+use the explicit namespace name off of <code class="docutils literal"><span class="pre">self</span></code>, followed by the
+desired function name. But more on this in a future release.</p>
+</div>
+<div class="section" id="namespace-api-usage-example-static-dependencies">
+<h2>Namespace API Usage Example - Static Dependencies<a class="headerlink" href="#namespace-api-usage-example-static-dependencies" title="Permalink to this headline">¶</a></h2>
+<p>The <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag at runtime produces an instance of
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>.   Programmatic access of <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> can be used
+to build various kinds of scaffolding in templates and between templates.</p>
+<p>A common request is the ability for a particular template to declare
+&#8220;static includes&#8221; - meaning, the usage of a particular set of defs requires
+that certain Javascript/CSS files are present.   Using <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> as the
+object that holds together the various templates present, we can build a variety
+of such schemes.   In particular, the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> has a <code class="docutils literal"><span class="pre">namespaces</span></code>
+attribute, which is a dictionary of all <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> objects declared.
+Iterating the values of this dictionary will provide a <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>
+object for each time the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag was used, anywhere within the
+inheritance chain.</p>
+<div class="section" id="version-one-use-namespace-attr">
+<span id="namespace-attr-for-includes"></span><h3>Version One - Use <a class="reference internal" href="#mako.runtime.Namespace.attr" title="mako.runtime.Namespace.attr"><code class="xref py py-attr docutils literal"><span class="pre">Namespace.attr</span></code></a><a class="headerlink" href="#version-one-use-namespace-attr" title="Permalink to this headline">¶</a></h3>
+<p>The <a class="reference internal" href="#mako.runtime.Namespace.attr" title="mako.runtime.Namespace.attr"><code class="xref py py-attr docutils literal"><span class="pre">Namespace.attr</span></code></a> attribute allows us to locate any variables declared
+in the <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code> of a template.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.mako</span><span class="x"></span>
+<span class="cp">## base-most template, renders layout etc.</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">&lt;head&gt;</span>
+<span class="cp">## traverse through all namespaces present,</span><span class="x"></span>
+<span class="cp">## look for an attribute named &#39;includes&#39;</span><span class="x"></span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">ns</span> <span class="ow">in</span> <span class="n">context</span><span class="o">.</span><span class="n">namespaces</span><span class="o">.</span><span class="n">values</span><span class="p">():</span><span class="x"></span>
+    <span class="cp">%</span> <span class="k">for</span> <span class="n">incl</span> <span class="ow">in</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">ns</span><span class="o">.</span><span class="n">attr</span><span class="p">,</span> <span class="s1">&#39;includes&#39;</span><span class="p">,</span> <span class="p">[]):</span><span class="x"></span>
+<span class="x">        </span><span class="cp">${</span><span class="n">incl</span><span class="cp">}</span>
+    <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/head&gt;</span>
+<span class="x">&lt;body&gt;</span>
+<span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/body</span>
+<span class="x">&lt;/html&gt;</span>
+
+<span class="cp">## library.mako</span><span class="x"></span>
+<span class="cp">## library functions.</span><span class="x"></span>
+<span class="cp">&lt;%!</span>
+    <span class="n">includes</span> <span class="o">=</span> <span class="p">[</span>
+        <span class="s1">&#39;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;mystyle.css&quot;/&gt;&#39;</span><span class="p">,</span>
+        <span class="s1">&#39;&lt;script type=&quot;text/javascript&quot; src=&quot;functions.js&quot;&gt;&lt;/script&gt;&#39;</span>
+    <span class="p">]</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;mytag()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;form&gt;</span>
+<span class="x">        </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    &lt;/form&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span>
+
+<span class="cp">## index.mako</span><span class="x"></span>
+<span class="cp">## calling template.</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.mako&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;foo&quot;</span> <span class="na">file=</span><span class="s">&quot;library.mako&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">foo:mytag</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    a form</span>
+<span class="cp">&lt;/%</span><span class="nb">foo:mytag</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Above, the file <code class="docutils literal"><span class="pre">library.mako</span></code> declares an attribute <code class="docutils literal"><span class="pre">includes</span></code> inside its global <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code> section.
+<code class="docutils literal"><span class="pre">index.mako</span></code> includes this template using the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag.  The base template <code class="docutils literal"><span class="pre">base.mako</span></code>, which is the inherited parent of <code class="docutils literal"><span class="pre">index.mako</span></code> and is reponsible for layout, then locates this attribute and iterates through its contents to produce the includes that are specific to <code class="docutils literal"><span class="pre">library.mako</span></code>.</p>
+</div>
+<div class="section" id="version-two-use-a-specific-named-def">
+<h3>Version Two - Use a specific named def<a class="headerlink" href="#version-two-use-a-specific-named-def" title="Permalink to this headline">¶</a></h3>
+<p>In this version, we put the includes into a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> that
+follows a naming convention.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## base.mako</span><span class="x"></span>
+<span class="cp">## base-most template, renders layout etc.</span><span class="x"></span>
+<span class="x">&lt;html&gt;</span>
+<span class="x">&lt;head&gt;</span>
+<span class="cp">## traverse through all namespaces present,</span><span class="x"></span>
+<span class="cp">## look for a %def named &#39;includes&#39;</span><span class="x"></span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">ns</span> <span class="ow">in</span> <span class="n">context</span><span class="o">.</span><span class="n">namespaces</span><span class="o">.</span><span class="n">values</span><span class="p">():</span><span class="x"></span>
+    <span class="cp">%</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">ns</span><span class="p">,</span> <span class="s1">&#39;includes&#39;</span><span class="p">):</span><span class="x"></span>
+<span class="x">        </span><span class="cp">${</span><span class="n">ns</span><span class="o">.</span><span class="n">includes</span><span class="p">()</span><span class="cp">}</span>
+    <span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/head&gt;</span>
+<span class="x">&lt;body&gt;</span>
+<span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/body</span>
+<span class="x">&lt;/html&gt;</span>
+
+<span class="cp">## library.mako</span><span class="x"></span>
+<span class="cp">## library functions.</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;includes()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;mystyle.css&quot;/&gt;</span>
+<span class="x">    &lt;script type=&quot;text/javascript&quot; src=&quot;functions.js&quot;&gt;&lt;/script&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;mytag()&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    &lt;form&gt;</span>
+<span class="x">        </span><span class="cp">${</span><span class="n">caller</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    &lt;/form&gt;</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span>
+
+
+<span class="cp">## index.mako</span><span class="x"></span>
+<span class="cp">## calling template.</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.mako&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+<span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">name=</span><span class="s">&quot;foo&quot;</span> <span class="na">file=</span><span class="s">&quot;library.mako&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">foo:mytag</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    a form</span>
+<span class="cp">&lt;/%</span><span class="nb">foo:mytag</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>In this version, <code class="docutils literal"><span class="pre">library.mako</span></code> declares a <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code> named <code class="docutils literal"><span class="pre">includes</span></code>.   The example works
+identically to the previous one, except that <code class="docutils literal"><span class="pre">base.mako</span></code> looks for defs named <code class="docutils literal"><span class="pre">include</span></code>
+on each namespace it examines.</p>
+</div>
+</div>
+<div class="section" id="api-reference">
+<h2>API Reference<a class="headerlink" href="#api-reference" title="Permalink to this headline">¶</a></h2>
+<dl class="class">
+<dt id="mako.runtime.Namespace">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">Namespace</code><span class="sig-paren">(</span><em>name</em>, <em>context</em>, <em>callables=None</em>, <em>inherits=None</em>, <em>populate_self=True</em>, <em>calling_uri=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Namespace" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Provides access to collections of rendering methods, which
+can be local, from other templates, or from imported modules.</p>
+<p>To access a particular rendering method referenced by a
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, use plain attribute access:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">some_namespace</span><span class="o">.</span><span class="n">foo</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p><a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> also contains several built-in attributes
+described here.</p>
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.attr">
+<code class="descname">attr</code><a class="headerlink" href="#mako.runtime.Namespace.attr" title="Permalink to this definition">¶</a></dt>
+<dd><p>Access module level attributes by name.</p>
+<p>This accessor allows templates to supply &#8220;scalar&#8221;
+attributes which are particularly handy in inheritance
+relationships.</p>
+<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<p><a class="reference internal" href="inheritance.html#inheritance-attr"><span class="std std-ref">Inheritable Attributes</span></a></p>
+<p class="last"><a class="reference internal" href="#namespace-attr-for-includes"><span class="std std-ref">Version One - Use Namespace.attr</span></a></p>
+</div>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.cache">
+<code class="descname">cache</code><a class="headerlink" href="#mako.runtime.Namespace.cache" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the <a class="reference internal" href="caching.html#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> object referenced
+by this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> object&#8217;s
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.context">
+<code class="descname">context</code><em class="property"> = None</em><a class="headerlink" href="#mako.runtime.Namespace.context" title="Permalink to this definition">¶</a></dt>
+<dd><p>The <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object for this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>.</p>
+<p>Namespaces are often created with copies of contexts that
+contain slightly different data, particularly in inheritance
+scenarios. Using the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> off of a <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> one
+can traverse an entire chain of templates that inherit from
+one-another.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.filename">
+<code class="descname">filename</code><em class="property"> = None</em><a class="headerlink" href="#mako.runtime.Namespace.filename" title="Permalink to this definition">¶</a></dt>
+<dd><p>The path of the filesystem file used for this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>&#8216;s module or template.</p>
+<p>If this is a pure module-based
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, this evaluates to <code class="docutils literal"><span class="pre">module.__file__</span></code>. If a
+template-based namespace, it evaluates to the original
+template file location.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Namespace.get_cached">
+<code class="descname">get_cached</code><span class="sig-paren">(</span><em>key</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Namespace.get_cached" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a value from the <a class="reference internal" href="caching.html#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> referenced by this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> object&#8217;s <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+<p>The advantage to this method versus direct access to the
+<a class="reference internal" href="caching.html#mako.cache.Cache" title="mako.cache.Cache"><code class="xref py py-class docutils literal"><span class="pre">Cache</span></code></a> is that the configuration parameters
+declared in <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> take effect here, thereby calling
+up the same configured backend as that configured
+by <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Namespace.get_namespace">
+<code class="descname">get_namespace</code><span class="sig-paren">(</span><em>uri</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Namespace.get_namespace" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> corresponding to the given <code class="docutils literal"><span class="pre">uri</span></code>.</p>
+<p>If the given <code class="docutils literal"><span class="pre">uri</span></code> is a relative URI (i.e. it does not
+contain a leading slash <code class="docutils literal"><span class="pre">/</span></code>), the <code class="docutils literal"><span class="pre">uri</span></code> is adjusted to
+be relative to the <code class="docutils literal"><span class="pre">uri</span></code> of the namespace itself. This
+method is therefore mostly useful off of the built-in
+<code class="docutils literal"><span class="pre">local</span></code> namespace, described in <a class="reference internal" href="#namespace-local"><span class="std std-ref">local</span></a>.</p>
+<p>In
+most cases, a template wouldn&#8217;t need this function, and
+should instead use the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tag to load
+namespaces. However, since all <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code> tags are
+evaluated before the body of a template ever runs,
+this method can be used to locate namespaces using
+expressions that were generated within the body code of
+the template, or to conditionally use a particular
+namespace.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Namespace.get_template">
+<code class="descname">get_template</code><span class="sig-paren">(</span><em>uri</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Namespace.get_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> from the given <code class="docutils literal"><span class="pre">uri</span></code>.</p>
+<p>The <code class="docutils literal"><span class="pre">uri</span></code> resolution is relative to the <code class="docutils literal"><span class="pre">uri</span></code> of this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> object&#8217;s <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Namespace.include_file">
+<code class="descname">include_file</code><span class="sig-paren">(</span><em>uri</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Namespace.include_file" title="Permalink to this definition">¶</a></dt>
+<dd><p>Include a file at the given <code class="docutils literal"><span class="pre">uri</span></code>.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.module">
+<code class="descname">module</code><em class="property"> = None</em><a class="headerlink" href="#mako.runtime.Namespace.module" title="Permalink to this definition">¶</a></dt>
+<dd><p>The Python module referenced by this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>.</p>
+<p>If the namespace references a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>, then
+this module is the equivalent of <code class="docutils literal"><span class="pre">template.module</span></code>,
+i.e. the generated module for the template.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.template">
+<code class="descname">template</code><em class="property"> = None</em><a class="headerlink" href="#mako.runtime.Namespace.template" title="Permalink to this definition">¶</a></dt>
+<dd><p>The <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object referenced by this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, if any.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Namespace.uri">
+<code class="descname">uri</code><em class="property"> = None</em><a class="headerlink" href="#mako.runtime.Namespace.uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>The URI for this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>&#8216;s template.</p>
+<p>I.e. whatever was sent to <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">TemplateLookup.get_template()</span></code></a>.</p>
+<p>This is the equivalent of <code class="xref py py-attr docutils literal"><span class="pre">Template.uri</span></code>.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.runtime.TemplateNamespace">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">TemplateNamespace</code><span class="sig-paren">(</span><em>name</em>, <em>context</em>, <em>template=None</em>, <em>templateuri=None</em>, <em>callables=None</em>, <em>inherits=None</em>, <em>populate_self=True</em>, <em>calling_uri=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.TemplateNamespace" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">mako.runtime.Namespace</span></code></a></p>
+<p>A <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> specific to a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> instance.</p>
+<dl class="attribute">
+<dt id="mako.runtime.TemplateNamespace.filename">
+<code class="descname">filename</code><a class="headerlink" href="#mako.runtime.TemplateNamespace.filename" title="Permalink to this definition">¶</a></dt>
+<dd><p>The path of the filesystem file used for this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>&#8216;s module or template.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.TemplateNamespace.module">
+<code class="descname">module</code><a class="headerlink" href="#mako.runtime.TemplateNamespace.module" title="Permalink to this definition">¶</a></dt>
+<dd><p>The Python module referenced by this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>.</p>
+<p>If the namespace references a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>, then
+this module is the equivalent of <code class="docutils literal"><span class="pre">template.module</span></code>,
+i.e. the generated module for the template.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.TemplateNamespace.uri">
+<code class="descname">uri</code><a class="headerlink" href="#mako.runtime.TemplateNamespace.uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>The URI for this <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>&#8216;s template.</p>
+<p>I.e. whatever was sent to <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">TemplateLookup.get_template()</span></code></a>.</p>
+<p>This is the equivalent of <code class="xref py py-attr docutils literal"><span class="pre">Template.uri</span></code>.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.runtime.ModuleNamespace">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">ModuleNamespace</code><span class="sig-paren">(</span><em>name</em>, <em>context</em>, <em>module</em>, <em>callables=None</em>, <em>inherits=None</em>, <em>populate_self=True</em>, <em>calling_uri=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.ModuleNamespace" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">mako.runtime.Namespace</span></code></a></p>
+<p>A <a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a> specific to a Python module instance.</p>
+<dl class="attribute">
+<dt id="mako.runtime.ModuleNamespace.filename">
+<code class="descname">filename</code><a class="headerlink" href="#mako.runtime.ModuleNamespace.filename" title="Permalink to this definition">¶</a></dt>
+<dd><p>The path of the filesystem file used for this
+<a class="reference internal" href="#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>&#8216;s module or template.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="function">
+<dt id="mako.runtime.supports_caller">
+<code class="descclassname">mako.runtime.</code><code class="descname">supports_caller</code><span class="sig-paren">(</span><em>func</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.supports_caller" title="Permalink to this definition">¶</a></dt>
+<dd><p>Apply a caller_stack compatibility decorator to a plain
+Python function.</p>
+<p>See the example in <a class="reference internal" href="#namespaces-python-modules"><span class="std std-ref">Namespaces from Regular Python Modules</span></a>.</p>
+</dd></dl>
+
+<dl class="function">
+<dt id="mako.runtime.capture">
+<code class="descclassname">mako.runtime.</code><code class="descname">capture</code><span class="sig-paren">(</span><em>context</em>, <em>callable_</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.capture" title="Permalink to this definition">¶</a></dt>
+<dd><p>Execute the given template def, capturing the output into
+a buffer.</p>
+<p>See the example in <a class="reference internal" href="#namespaces-python-modules"><span class="std std-ref">Namespaces from Regular Python Modules</span></a>.</p>
+</dd></dl>
+
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="runtime.html" title="previous chapter">The Mako Runtime Environment</a>
+        Next:
+        <a href="inheritance.html" title="next chapter">Inheritance</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/runtime.html b/doc/runtime.html
new file mode 100644 (file)
index 0000000..8081477
--- /dev/null
@@ -0,0 +1,728 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                The Mako Runtime Environment
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Namespaces" href="namespaces.html" />
+        <link rel="prev" title="Defs and Blocks" href="defs.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="defs.html" title="previous chapter">Defs and Blocks</a>
+            </li>
+            <li>Next:
+            <a href="namespaces.html" title="next chapter">Namespaces</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/runtime.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                The Mako Runtime Environment
+            
+
+        <h2>
+            
+                The Mako Runtime Environment
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">The Mako Runtime Environment</a><ul>
+<li><a class="reference internal" href="#context">Context</a><ul>
+<li><a class="reference internal" href="#the-buffer">The Buffer</a></li>
+<li><a class="reference internal" href="#context-variables">Context Variables</a></li>
+<li><a class="reference internal" href="#context-methods-and-accessors">Context Methods and Accessors</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#the-loop-context">The Loop Context</a><ul>
+<li><a class="reference internal" href="#iterations">Iterations</a></li>
+<li><a class="reference internal" href="#cycling">Cycling</a></li>
+<li><a class="reference internal" href="#parent-loops">Parent Loops</a></li>
+<li><a class="reference internal" href="#migrating-legacy-templates-that-use-the-word-loop">Migrating Legacy Templates that Use the Word &#8220;loop&#8221;</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#all-the-built-in-names">All the Built-in Names</a><ul>
+<li><a class="reference internal" href="#reserved-names">Reserved Names</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#api-reference">API Reference</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="defs.html" title="previous chapter">Defs and Blocks</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="namespaces.html" title="next chapter">Namespaces</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="the-mako-runtime-environment">
+<span id="runtime-toplevel"></span><h1>The Mako Runtime Environment<a class="headerlink" href="#the-mako-runtime-environment" title="Permalink to this headline">¶</a></h1>
+<p>This section describes a little bit about the objects and
+built-in functions that are available in templates.</p>
+<div class="section" id="context">
+<span id="id1"></span><h2>Context<a class="headerlink" href="#context" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> is the central object that is created when
+a template is first executed, and is responsible for handling
+all communication with the outside world.  Within the template
+environment, it is available via the <a class="reference internal" href="#reserved-names"><span class="std std-ref">reserved name</span></a>
+<code class="docutils literal"><span class="pre">context</span></code>.  The <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> includes two
+major components, one of which is the output buffer, which is a
+file-like object such as Python&#8217;s <code class="docutils literal"><span class="pre">StringIO</span></code> or similar, and
+the other a dictionary of variables that can be freely
+referenced within a template; this dictionary is a combination
+of the arguments sent to the <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> function and
+some built-in variables provided by Mako&#8217;s runtime environment.</p>
+<div class="section" id="the-buffer">
+<h3>The Buffer<a class="headerlink" href="#the-buffer" title="Permalink to this headline">¶</a></h3>
+<p>The buffer is stored within the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>, and writing
+to it is achieved by calling the <a class="reference internal" href="#mako.runtime.Context.write" title="mako.runtime.Context.write"><code class="xref py py-meth docutils literal"><span class="pre">write()</span></code></a> method
+&#8211; in a template this looks like <code class="docutils literal"><span class="pre">context.write('some</span> <span class="pre">string')</span></code>.
+You usually don&#8217;t need to care about this, as all text within a template, as
+well as all expressions provided by <code class="docutils literal"><span class="pre">${}</span></code>, automatically send
+everything to this method. The cases you might want to be aware
+of its existence are if you are dealing with various
+filtering/buffering scenarios, which are described in
+<a class="reference internal" href="filtering.html"><span class="std std-ref">Filtering and Buffering</span></a>, or if you want to programmatically
+send content to the output stream, such as within a <code class="docutils literal"><span class="pre">&lt;%</span> <span class="pre">%&gt;</span></code>
+block.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;some programmatic text&quot;</span><span class="p">)</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The actual buffer may or may not be the original buffer sent to
+the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object, as various filtering/caching
+scenarios may &#8220;push&#8221; a new buffer onto the context&#8217;s underlying
+buffer stack. For this reason, just stick with
+<code class="docutils literal"><span class="pre">context.write()</span></code> and content will always go to the topmost
+buffer.</p>
+</div>
+<div class="section" id="context-variables">
+<span id="context-vars"></span><h3>Context Variables<a class="headerlink" href="#context-variables" title="Permalink to this headline">¶</a></h3>
+<p>When your template is compiled into a Python module, the body
+content is enclosed within a Python function called
+<code class="docutils literal"><span class="pre">render_body</span></code>. Other top-level defs defined in the template are
+defined within their own function bodies which are named after
+the def&#8217;s name with the prefix <code class="docutils literal"><span class="pre">render_</span></code> (i.e. <code class="docutils literal"><span class="pre">render_mydef</span></code>).
+One of the first things that happens within these functions is
+that all variable names that are referenced within the function
+which are not defined in some other way (i.e. such as via
+assignment, module level imports, etc.) are pulled from the
+<a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object&#8217;s dictionary of variables. This is how you&#8217;re
+able to freely reference variable names in a template which
+automatically correspond to what was passed into the current
+<a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+<ul>
+<li><p class="first"><strong>What happens if I reference a variable name that is not in
+the current context?</strong> - The value you get back is a special
+value called <code class="docutils literal"><span class="pre">UNDEFINED</span></code>, or if the <code class="docutils literal"><span class="pre">strict_undefined=True</span></code> flag
+is used a <code class="docutils literal"><span class="pre">NameError</span></code> is raised. <code class="docutils literal"><span class="pre">UNDEFINED</span></code> is just a simple global
+variable with the class <a class="reference internal" href="#mako.runtime.Undefined" title="mako.runtime.Undefined"><code class="xref py py-class docutils literal"><span class="pre">mako.runtime.Undefined</span></code></a>. The
+<code class="docutils literal"><span class="pre">UNDEFINED</span></code> object throws an error when you call <code class="docutils literal"><span class="pre">str()</span></code> on
+it, which is what happens if you try to use it in an
+expression.</p>
+</li>
+<li><p class="first"><strong>UNDEFINED makes it hard for me to find what name is missing</strong> - An alternative
+is to specify the option <code class="docutils literal"><span class="pre">strict_undefined=True</span></code>
+to the <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>.  This will cause
+any non-present variables to raise an immediate <code class="docutils literal"><span class="pre">NameError</span></code>
+which includes the name of the variable in its message
+when <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> is called &#8211; <code class="docutils literal"><span class="pre">UNDEFINED</span></code> is not used.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.3.6.</span></p>
+</div>
+</li>
+<li><p class="first"><strong>Why not just return None?</strong> Using <code class="docutils literal"><span class="pre">UNDEFINED</span></code>, or
+raising a <code class="docutils literal"><span class="pre">NameError</span></code> is more
+explicit and allows differentiation between a value of <code class="docutils literal"><span class="pre">None</span></code>
+that was explicitly passed to the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> and a value that
+wasn&#8217;t present at all.</p>
+</li>
+<li><p class="first"><strong>Why raise an exception when you call str() on it ? Why not
+just return a blank string?</strong> - Mako tries to stick to the
+Python philosophy of &#8220;explicit is better than implicit&#8221;. In
+this case, it&#8217;s decided that the template author should be made
+to specifically handle a missing value rather than
+experiencing what may be a silent failure. Since <code class="docutils literal"><span class="pre">UNDEFINED</span></code>
+is a singleton object just like Python&#8217;s <code class="docutils literal"><span class="pre">True</span></code> or <code class="docutils literal"><span class="pre">False</span></code>,
+you can use the <code class="docutils literal"><span class="pre">is</span></code> operator to check for it:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">if</span> <span class="n">someval</span> <span class="ow">is</span> <span class="n">UNDEFINED</span><span class="p">:</span><span class="x"></span>
+<span class="x">    someval is: no value</span>
+<span class="cp">%</span> <span class="k">else</span><span class="p">:</span><span class="x"></span>
+<span class="x">    someval is: </span><span class="cp">${</span><span class="n">someval</span><span class="cp">}</span>
+<span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+</pre></div>
+</div>
+</li>
+</ul>
+<p>Another facet of the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> is that its dictionary of
+variables is <strong>immutable</strong>. Whatever is set when
+<a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> is called is what stays. Of course, since
+its Python, you can hack around this and change values in the
+context&#8217;s internal dictionary, but this will probably will not
+work as well as you&#8217;d think. The reason for this is that Mako in
+many cases creates copies of the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object, which
+get sent to various elements of the template and inheriting
+templates used in an execution. So changing the value in your
+local <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> will not necessarily make that value
+available in other parts of the template&#8217;s execution. Examples
+of where Mako creates copies of the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> include
+within top-level def calls from the main body of the template
+(the context is used to propagate locally assigned variables
+into the scope of defs; since in the template&#8217;s body they appear
+as inlined functions, Mako tries to make them act that way), and
+within an inheritance chain (each template in an inheritance
+chain has a different notion of <code class="docutils literal"><span class="pre">parent</span></code> and <code class="docutils literal"><span class="pre">next</span></code>, which
+are all stored in unique <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> instances).</p>
+<ul>
+<li><p class="first"><strong>So what if I want to set values that are global to everyone
+within a template request?</strong> - All you have to do is provide a
+dictionary to your <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> when the template first
+runs, and everyone can just get/set variables from that. Lets
+say its called <code class="docutils literal"><span class="pre">attributes</span></code>.</p>
+<p>Running the template looks like:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">output</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">attributes</span><span class="o">=</span><span class="p">{})</span>
+</pre></div>
+</div>
+<p>Within a template, just reference the dictionary:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="n">attributes</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;bar&#39;</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+<span class="x">&#39;foo&#39; attribute is: </span><span class="cp">${</span><span class="n">attributes</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">]</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+</li>
+<li><p class="first"><strong>Why can&#8217;t &#8220;attributes&#8221; be a built-in feature of the
+Context?</strong> - This is an area where Mako is trying to make as
+few decisions about your application as it possibly can.
+Perhaps you don&#8217;t want your templates to use this technique of
+assigning and sharing data, or perhaps you have a different
+notion of the names and kinds of data structures that should
+be passed around. Once again Mako would rather ask the user to
+be explicit.</p>
+</li>
+</ul>
+</div>
+<div class="section" id="context-methods-and-accessors">
+<h3>Context Methods and Accessors<a class="headerlink" href="#context-methods-and-accessors" title="Permalink to this headline">¶</a></h3>
+<p>Significant members of <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> include:</p>
+<ul>
+<li><p class="first"><code class="docutils literal"><span class="pre">context[key]</span></code> / <code class="docutils literal"><span class="pre">context.get(key,</span> <span class="pre">default=None)</span></code> -
+dictionary-like accessors for the context. Normally, any
+variable you use in your template is automatically pulled from
+the context if it isn&#8217;t defined somewhere already. Use the
+dictionary accessor and/or <code class="docutils literal"><span class="pre">get</span></code> method when you want a
+variable that <em>is</em> already defined somewhere else, such as in
+the local arguments sent to a <code class="docutils literal"><span class="pre">%def</span></code> call. If a key is not
+present, like a dictionary it raises <code class="docutils literal"><span class="pre">KeyError</span></code>.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">keys()</span></code> - all the names defined within this context.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">kwargs</span></code> - this returns a <strong>copy</strong> of the context&#8217;s
+dictionary of variables. This is useful when you want to
+propagate the variables in the current context to a function
+as keyword arguments, i.e.:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="nb">next</span><span class="o">.</span><span class="n">body</span><span class="p">(</span><span class="o">**</span><span class="n">context</span><span class="o">.</span><span class="n">kwargs</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">write(text)</span></code> - write some text to the current output
+stream.</p>
+</li>
+<li><p class="first"><code class="docutils literal"><span class="pre">lookup</span></code> - returns the <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> instance that is
+used for all file-lookups within the current execution (even
+though individual <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> instances can conceivably have
+different instances of a <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, only the
+<a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> of the originally-called <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> gets
+used in a particular execution).</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="the-loop-context">
+<span id="loop-context"></span><h2>The Loop Context<a class="headerlink" href="#the-loop-context" title="Permalink to this headline">¶</a></h2>
+<p>Within <code class="docutils literal"><span class="pre">%</span> <span class="pre">for</span></code> blocks, the <a class="reference internal" href="#reserved-names"><span class="std std-ref">reserved name</span></a> <code class="docutils literal"><span class="pre">loop</span></code>
+is available.  <code class="docutils literal"><span class="pre">loop</span></code> tracks the progress of
+the <code class="docutils literal"><span class="pre">for</span></code> loop and makes it easy to use the iteration state to control
+template behavior:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;ul&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;one&quot;</span><span class="p">,</span> <span class="s2">&quot;two&quot;</span><span class="p">,</span> <span class="s2">&quot;three&quot;</span><span class="p">):</span><span class="x"></span>
+<span class="x">    &lt;li&gt;Item </span><span class="cp">${</span><span class="n">loop</span><span class="o">.</span><span class="n">index</span><span class="cp">}</span><span class="x">: </span><span class="cp">${</span><span class="n">a</span><span class="cp">}</span><span class="x">&lt;/li&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/ul&gt;</span>
+</pre></div>
+</div>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.7.</span></p>
+</div>
+<div class="section" id="iterations">
+<h3>Iterations<a class="headerlink" href="#iterations" title="Permalink to this headline">¶</a></h3>
+<p>Regardless of the type of iterable you&#8217;re looping over, <code class="docutils literal"><span class="pre">loop</span></code> always tracks
+the 0-indexed iteration count (available at <code class="docutils literal"><span class="pre">loop.index</span></code>), its parity
+(through the <code class="docutils literal"><span class="pre">loop.even</span></code> and <code class="docutils literal"><span class="pre">loop.odd</span></code> bools), and <code class="docutils literal"><span class="pre">loop.first</span></code>, a bool
+indicating whether the loop is on its first iteration.  If your iterable
+provides a <code class="docutils literal"><span class="pre">__len__</span></code> method, <code class="docutils literal"><span class="pre">loop</span></code> also provides access to
+a count of iterations remaining at <code class="docutils literal"><span class="pre">loop.reverse_index</span></code> and <code class="docutils literal"><span class="pre">loop.last</span></code>,
+a bool indicating whether the loop is on its last iteration; accessing these
+without <code class="docutils literal"><span class="pre">__len__</span></code> will raise a <code class="docutils literal"><span class="pre">TypeError</span></code>.</p>
+</div>
+<div class="section" id="cycling">
+<h3>Cycling<a class="headerlink" href="#cycling" title="Permalink to this headline">¶</a></h3>
+<p>Cycling is available regardless of whether the iterable you&#8217;re using provides
+a <code class="docutils literal"><span class="pre">__len__</span></code> method.  Prior to Mako 0.7, you might have generated a simple
+zebra striped list using <code class="docutils literal"><span class="pre">enumerate</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;ul&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">item</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">((</span><span class="s1">&#39;spam&#39;</span><span class="p">,</span> <span class="s1">&#39;ham&#39;</span><span class="p">,</span> <span class="s1">&#39;eggs&#39;</span><span class="p">)):</span><span class="x"></span>
+<span class="x">  &lt;li class=&quot;</span><span class="cp">${</span><span class="s1">&#39;odd&#39;</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="k">else</span> <span class="s1">&#39;even&#39;</span><span class="cp">}</span><span class="x">&quot;&gt;</span><span class="cp">${</span><span class="n">item</span><span class="cp">}</span><span class="x">&lt;/li&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/ul&gt;</span>
+</pre></div>
+</div>
+<p>With <code class="docutils literal"><span class="pre">loop.cycle</span></code>, you get the same results with cleaner code and less prep work:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;ul&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;spam&#39;</span><span class="p">,</span> <span class="s1">&#39;ham&#39;</span><span class="p">,</span> <span class="s1">&#39;eggs&#39;</span><span class="p">):</span><span class="x"></span>
+<span class="x">  &lt;li class=&quot;</span><span class="cp">${</span><span class="n">loop</span><span class="o">.</span><span class="n">cycle</span><span class="p">(</span><span class="s1">&#39;even&#39;</span><span class="p">,</span> <span class="s1">&#39;odd&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x">&quot;&gt;</span><span class="cp">${</span><span class="n">item</span><span class="cp">}</span><span class="x">&lt;/li&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/ul&gt;</span>
+</pre></div>
+</div>
+<p>Both approaches produce output like the following:</p>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;even&quot;</span><span class="p">&gt;</span>spam<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;odd&quot;</span><span class="p">&gt;</span>ham<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;even&quot;</span><span class="p">&gt;</span>eggs<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="parent-loops">
+<h3>Parent Loops<a class="headerlink" href="#parent-loops" title="Permalink to this headline">¶</a></h3>
+<p>Loop contexts can also be transparently nested, and the Mako runtime will do
+the right thing and manage the scope for you.  You can access the parent loop
+context through <code class="docutils literal"><span class="pre">loop.parent</span></code>.</p>
+<p>This allows you to reach all the way back up through the loop stack by
+chaining <code class="docutils literal"><span class="pre">parent</span></code> attribute accesses, i.e. <code class="docutils literal"><span class="pre">loop.parent.parent....</span></code> as
+long as the stack depth isn&#8217;t exceeded.  For example, you can use the parent
+loop to make a checkered table:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;table&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">consonant</span> <span class="ow">in</span> <span class="s1">&#39;pbj&#39;</span><span class="p">:</span><span class="x"></span>
+<span class="x">  &lt;tr&gt;</span>
+  <span class="cp">%</span> <span class="k">for</span> <span class="n">vowel</span> <span class="ow">in</span> <span class="s1">&#39;iou&#39;</span><span class="p">:</span><span class="x"></span>
+<span class="x">    &lt;td class=&quot;</span><span class="cp">${</span><span class="s1">&#39;black&#39;</span> <span class="k">if</span> <span class="p">(</span><span class="n">loop</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">even</span> <span class="o">==</span> <span class="n">loop</span><span class="o">.</span><span class="n">even</span><span class="p">)</span> <span class="k">else</span> <span class="s1">&#39;red&#39;</span><span class="cp">}</span><span class="x">&quot;&gt;</span>
+<span class="x">      </span><span class="cp">${</span><span class="n">consonant</span> <span class="o">+</span> <span class="n">vowel</span><span class="cp">}</span><span class="x">t</span>
+<span class="x">    &lt;/td&gt;</span>
+  <span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">  &lt;/tr&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/table&gt;</span>
+</pre></div>
+</div>
+<div class="highlight-html"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">table</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;black&quot;</span><span class="p">&gt;</span>
+      pit
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;red&quot;</span><span class="p">&gt;</span>
+      pot
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;black&quot;</span><span class="p">&gt;</span>
+      put
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;red&quot;</span><span class="p">&gt;</span>
+      bit
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;black&quot;</span><span class="p">&gt;</span>
+      bot
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;red&quot;</span><span class="p">&gt;</span>
+      but
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+  <span class="p">&lt;</span><span class="nt">tr</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;black&quot;</span><span class="p">&gt;</span>
+      jit
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;red&quot;</span><span class="p">&gt;</span>
+      jot
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+    <span class="p">&lt;</span><span class="nt">td</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;black&quot;</span><span class="p">&gt;</span>
+      jut
+    <span class="p">&lt;/</span><span class="nt">td</span><span class="p">&gt;</span>
+  <span class="p">&lt;/</span><span class="nt">tr</span><span class="p">&gt;</span>
+<span class="p">&lt;/</span><span class="nt">table</span><span class="p">&gt;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="migrating-legacy-templates-that-use-the-word-loop">
+<span id="migrating-loop"></span><h3>Migrating Legacy Templates that Use the Word &#8220;loop&#8221;<a class="headerlink" href="#migrating-legacy-templates-that-use-the-word-loop" title="Permalink to this headline">¶</a></h3>
+<div class="versionchanged">
+<p><span class="versionmodified">Changed in version 0.7: </span>The <code class="docutils literal"><span class="pre">loop</span></code> name is now <a class="reference internal" href="#reserved-names"><span class="std std-ref">reserved</span></a> in Mako,
+which means a template that refers to a variable named <code class="docutils literal"><span class="pre">loop</span></code>
+won&#8217;t function correctly when used in Mako 0.7.</p>
+</div>
+<p>To ease the transition for such systems, the feature can be disabled across the board for
+all templates, then re-enabled on a per-template basis for those templates which wish
+to make use of the new system.</p>
+<p>First, the <code class="docutils literal"><span class="pre">enable_loop=False</span></code> flag is passed to either the <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>
+or <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object in use:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">lookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">],</span> <span class="n">enable_loop</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>or:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">template</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;some template&quot;</span><span class="p">,</span> <span class="n">enable_loop</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>An individual template can make usage of the feature when <code class="docutils literal"><span class="pre">enable_loop</span></code> is set to
+<code class="docutils literal"><span class="pre">False</span></code> by switching it back on within the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">enable_loop=</span><span class="s">&quot;True&quot;</span><span class="cp">/&gt;</span>
+
+<span class="cp">%</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">collection</span><span class="p">:</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="n">i</span><span class="cp">}</span><span class="x"> </span><span class="cp">${</span><span class="n">loop</span><span class="o">.</span><span class="n">index</span><span class="cp">}</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Using the above scheme, it&#8217;s safe to pass the name <code class="docutils literal"><span class="pre">loop</span></code> to the <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">Template.render()</span></code></a>
+method as well as to freely make usage of a variable named <code class="docutils literal"><span class="pre">loop</span></code> within a template, provided
+the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag doesn&#8217;t override it.  New templates that want to use the <code class="docutils literal"><span class="pre">loop</span></code> context
+can then set up <code class="docutils literal"><span class="pre">&lt;%page</span> <span class="pre">enable_loop=&quot;True&quot;/&gt;</span></code> to use the new feature without affecting
+old templates.</p>
+</div>
+</div>
+<div class="section" id="all-the-built-in-names">
+<h2>All the Built-in Names<a class="headerlink" href="#all-the-built-in-names" title="Permalink to this headline">¶</a></h2>
+<p>A one-stop shop for all the names Mako defines. Most of these
+names are instances of <a class="reference internal" href="namespaces.html#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">Namespace</span></code></a>, which are described
+in the next section, <a class="reference internal" href="namespaces.html"><span class="std std-ref">Namespaces</span></a>. Also, most of
+these names other than <code class="docutils literal"><span class="pre">context</span></code>, <code class="docutils literal"><span class="pre">UNDEFINED</span></code>, and <code class="docutils literal"><span class="pre">loop</span></code> are
+also present <em>within</em> the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> itself.   The names
+<code class="docutils literal"><span class="pre">context</span></code>, <code class="docutils literal"><span class="pre">loop</span></code> and <code class="docutils literal"><span class="pre">UNDEFINED</span></code> themselves can&#8217;t be passed
+to the context and can&#8217;t be substituted &#8211; see the section <a class="reference internal" href="#reserved-names"><span class="std std-ref">Reserved Names</span></a>.</p>
+<ul class="simple">
+<li><code class="docutils literal"><span class="pre">context</span></code> - this is the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object, introduced
+at <a class="reference internal" href="#context"><span class="std std-ref">Context</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">local</span></code> - the namespace of the current template, described
+in <a class="reference internal" href="namespaces.html#namespaces-builtin"><span class="std std-ref">Built-in Namespaces</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">self</span></code> - the namespace of the topmost template in an
+inheritance chain (if any, otherwise the same as <code class="docutils literal"><span class="pre">local</span></code>),
+mostly described in <a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">parent</span></code> - the namespace of the parent template in an
+inheritance chain (otherwise undefined); see
+<a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">next</span></code> - the namespace of the next template in an
+inheritance chain (otherwise undefined); see
+<a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">caller</span></code> - a &#8220;mini&#8221; namespace created when using the
+<code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code> tag to define a &#8220;def call with content&#8221;; described
+in <a class="reference internal" href="defs.html#defs-with-content"><span class="std std-ref">Calling a Def with Embedded Content and/or Other Defs</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">loop</span></code> - this provides access to <a class="reference internal" href="#mako.runtime.LoopContext" title="mako.runtime.LoopContext"><code class="xref py py-class docutils literal"><span class="pre">LoopContext</span></code></a> objects when
+they are requested within <code class="docutils literal"><span class="pre">%</span> <span class="pre">for</span></code> loops, introduced at <a class="reference internal" href="#loop-context"><span class="std std-ref">The Loop Context</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">capture</span></code> - a function that calls a given def and captures
+its resulting content into a string, which is returned. Usage
+is described in <a class="reference internal" href="filtering.html"><span class="std std-ref">Filtering and Buffering</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">UNDEFINED</span></code> - a global singleton that is applied to all
+otherwise uninitialized template variables that were not
+located within the <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> when rendering began,
+unless the <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> flag <code class="docutils literal"><span class="pre">strict_undefined</span></code>
+is set to <code class="docutils literal"><span class="pre">True</span></code>. <code class="docutils literal"><span class="pre">UNDEFINED</span></code> is
+an instance of <a class="reference internal" href="#mako.runtime.Undefined" title="mako.runtime.Undefined"><code class="xref py py-class docutils literal"><span class="pre">Undefined</span></code></a>, and raises an
+exception when its <code class="docutils literal"><span class="pre">__str__()</span></code> method is called.</li>
+<li><code class="docutils literal"><span class="pre">pageargs</span></code> - this is a dictionary which is present in a
+template which does not define any <code class="docutils literal"><span class="pre">**kwargs</span></code> section in its
+<code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag. All keyword arguments sent to the <code class="docutils literal"><span class="pre">body()</span></code>
+function of a template (when used via namespaces) go here by
+default unless otherwise defined as a page argument. If this
+makes no sense, it shouldn&#8217;t; read the section
+<a class="reference internal" href="namespaces.html#namespaces-body"><span class="std std-ref">The body() Method</span></a>.</li>
+</ul>
+<div class="section" id="reserved-names">
+<span id="id2"></span><h3>Reserved Names<a class="headerlink" href="#reserved-names" title="Permalink to this headline">¶</a></h3>
+<p>Mako has a few names that are considered to be &#8220;reserved&#8221; and can&#8217;t be used
+as variable names.</p>
+<div class="versionchanged">
+<p><span class="versionmodified">Changed in version 0.7: </span>Mako raises an error if these words are found passed to the template
+as context arguments, whereas in previous versions they&#8217;d be silently
+ignored or lead to other error messages.</p>
+</div>
+<ul class="simple">
+<li><code class="docutils literal"><span class="pre">context</span></code> - see <a class="reference internal" href="#context"><span class="std std-ref">Context</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">UNDEFINED</span></code> - see <a class="reference internal" href="#context-vars"><span class="std std-ref">Context Variables</span></a>.</li>
+<li><code class="docutils literal"><span class="pre">loop</span></code> - see <a class="reference internal" href="#loop-context"><span class="std std-ref">The Loop Context</span></a>.  Note this can be disabled for legacy templates
+via the <code class="docutils literal"><span class="pre">enable_loop=False</span></code> argument; see <a class="reference internal" href="#migrating-loop"><span class="std std-ref">Migrating Legacy Templates that Use the Word &#8220;loop&#8221;</span></a>.</li>
+</ul>
+</div>
+</div>
+<div class="section" id="api-reference">
+<h2>API Reference<a class="headerlink" href="#api-reference" title="Permalink to this headline">¶</a></h2>
+<dl class="class">
+<dt id="mako.runtime.Context">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">Context</code><span class="sig-paren">(</span><em>buffer</em>, <em>**data</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Provides runtime namespace, output buffer, and various
+callstacks for templates.</p>
+<p>See <a class="reference internal" href="#"><span class="std std-ref">The Mako Runtime Environment</span></a> for detail on the usage of
+<a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+<dl class="method">
+<dt id="mako.runtime.Context.get">
+<code class="descname">get</code><span class="sig-paren">(</span><em>key</em>, <em>default=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.get" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a value from this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Context.keys">
+<code class="descname">keys</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.keys" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a list of all names established in this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Context.kwargs">
+<code class="descname">kwargs</code><a class="headerlink" href="#mako.runtime.Context.kwargs" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the dictionary of top level keyword arguments associated
+with this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+<p>This dictionary only includes the top-level arguments passed to
+<a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">Template.render()</span></code></a>.  It does not include names produced within
+the template execution such as local variable names or special names
+such as <code class="docutils literal"><span class="pre">self</span></code>, <code class="docutils literal"><span class="pre">next</span></code>, etc.</p>
+<p>The purpose of this dictionary is primarily for the case that
+a <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> accepts arguments via its <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag,
+which are normally expected to be passed via <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">Template.render()</span></code></a>,
+except the template is being called in an inheritance context,
+using the <code class="docutils literal"><span class="pre">body()</span></code> method.   <a class="reference internal" href="#mako.runtime.Context.kwargs" title="mako.runtime.Context.kwargs"><code class="xref py py-attr docutils literal"><span class="pre">Context.kwargs</span></code></a> can then be
+used to propagate these arguments to the inheriting template:</p>
+<div class="highlight-default"><div class="highlight"><pre><span></span>${next.body(**context.kwargs)}
+</pre></div>
+</div>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.runtime.Context.lookup">
+<code class="descname">lookup</code><a class="headerlink" href="#mako.runtime.Context.lookup" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> associated
+with this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Context.pop_caller">
+<code class="descname">pop_caller</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.pop_caller" title="Permalink to this definition">¶</a></dt>
+<dd><p>Pop a <code class="docutils literal"><span class="pre">caller</span></code> callable onto the callstack for this
+<a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Context.push_caller">
+<code class="descname">push_caller</code><span class="sig-paren">(</span><em>caller</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.push_caller" title="Permalink to this definition">¶</a></dt>
+<dd><p>Push a <code class="docutils literal"><span class="pre">caller</span></code> callable onto the callstack for
+this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Context.write">
+<code class="descname">write</code><span class="sig-paren">(</span><em>string</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.write" title="Permalink to this definition">¶</a></dt>
+<dd><p>Write a string to this <a class="reference internal" href="#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object&#8217;s
+underlying output buffer.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.runtime.Context.writer">
+<code class="descname">writer</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.Context.writer" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the current writer function.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.runtime.LoopContext">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">LoopContext</code><span class="sig-paren">(</span><em>iterable</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.LoopContext" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>A magic loop variable.
+Automatically accessible in any <code class="docutils literal"><span class="pre">%</span> <span class="pre">for</span></code> block.</p>
+<p>See the section <a class="reference internal" href="#loop-context"><span class="std std-ref">The Loop Context</span></a> for usage
+notes.</p>
+<dl class="docutils">
+<dt><code class="xref py py-attr docutils literal"><span class="pre">parent</span></code> -&gt; <a class="reference internal" href="#mako.runtime.LoopContext" title="mako.runtime.LoopContext"><code class="xref py py-class docutils literal"><span class="pre">LoopContext</span></code></a> or <code class="docutils literal"><span class="pre">None</span></code></dt>
+<dd>The parent loop, if one exists.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">index</span></code> -&gt; <cite>int</cite></dt>
+<dd>The 0-based iteration count.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">reverse_index</span></code> -&gt; <cite>int</cite></dt>
+<dd>The number of iterations remaining.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">first</span></code> -&gt; <cite>bool</cite></dt>
+<dd><code class="docutils literal"><span class="pre">True</span></code> on the first iteration, <code class="docutils literal"><span class="pre">False</span></code> otherwise.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">last</span></code> -&gt; <cite>bool</cite></dt>
+<dd><code class="docutils literal"><span class="pre">True</span></code> on the last iteration, <code class="docutils literal"><span class="pre">False</span></code> otherwise.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">even</span></code> -&gt; <cite>bool</cite></dt>
+<dd><code class="docutils literal"><span class="pre">True</span></code> when <code class="docutils literal"><span class="pre">index</span></code> is even.</dd>
+<dt><code class="xref py py-attr docutils literal"><span class="pre">odd</span></code> -&gt; <cite>bool</cite></dt>
+<dd><code class="docutils literal"><span class="pre">True</span></code> when <code class="docutils literal"><span class="pre">index</span></code> is odd.</dd>
+</dl>
+<dl class="method">
+<dt id="mako.runtime.LoopContext.cycle">
+<code class="descname">cycle</code><span class="sig-paren">(</span><em>*values</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.runtime.LoopContext.cycle" title="Permalink to this definition">¶</a></dt>
+<dd><p>Cycle through values as the loop progresses.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.runtime.Undefined">
+<em class="property">class </em><code class="descclassname">mako.runtime.</code><code class="descname">Undefined</code><a class="headerlink" href="#mako.runtime.Undefined" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Represents an undefined value in a template.</p>
+<p>All template modules have a constant value
+<code class="docutils literal"><span class="pre">UNDEFINED</span></code> present which is an instance of this
+object.</p>
+</dd></dl>
+
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="defs.html" title="previous chapter">Defs and Blocks</a>
+        Next:
+        <a href="namespaces.html" title="next chapter">Namespaces</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/search.html b/doc/search.html
new file mode 100644 (file)
index 0000000..c23887e
--- /dev/null
@@ -0,0 +1,170 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+    Search
+ &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+        <script type="text/javascript" src="_static/searchtools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="#" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="#" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+    Search
+
+
+        <h2>
+            
+    Search
+
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+
+    <div id="docs-body" class="" >
+        
+
+
+
+
+
+<div id="searchform">
+<h3>Enter Search Terms:</h3>
+<form class="search" action="#" method="get">
+  <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+  <input type="hidden" name="check_keywords" value="yes" />
+  <input type="hidden" name="area" value="default" />
+</form>
+</div>
+
+<div id="search-results"></div>
+
+
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+    
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+    <script type="text/javascript" src="searchindex.js"></script>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/searchindex.js b/doc/searchindex.js
new file mode 100644 (file)
index 0000000..1fa8631
--- /dev/null
@@ -0,0 +1 @@
+Search.setIndex({envversion:49,filenames:["caching","changelog","defs","filtering","index","inheritance","namespaces","runtime","syntax","unicode","usage"],objects:{"mako.cache":{Cache:[0,1,1,""],CacheImpl:[0,1,1,""],register_plugin:[0,4,1,""]},"mako.cache.Cache":{get:[0,2,1,""],get_or_create:[0,2,1,""],id:[0,0,1,""],impl:[0,0,1,""],invalidate:[0,2,1,""],invalidate_body:[0,2,1,""],invalidate_closure:[0,2,1,""],invalidate_def:[0,2,1,""],put:[0,2,1,""],set:[0,2,1,""],starttime:[0,0,1,""]},"mako.cache.Cache.get.params":{"**kw":[0,3,1,""],key:[0,3,1,""]},"mako.cache.Cache.invalidate.params":{"**kw":[0,3,1,""],key:[0,3,1,""]},"mako.cache.Cache.set.params":{"**kw":[0,3,1,""],key:[0,3,1,""],value:[0,3,1,""]},"mako.cache.CacheImpl":{get:[0,2,1,""],get_or_create:[0,2,1,""],invalidate:[0,2,1,""],pass_context:[0,0,1,""],set:[0,2,1,""]},"mako.cache.CacheImpl.get.params":{"**kw":[0,3,1,""],key:[0,3,1,""]},"mako.cache.CacheImpl.get_or_create.params":{"**kw":[0,3,1,""],creation_function:[0,3,1,""],key:[0,3,1,""]},"mako.cache.CacheImpl.invalidate.params":{"**kw":[0,3,1,""],key:[0,3,1,""]},"mako.cache.CacheImpl.set.params":{"**kw":[0,3,1,""],key:[0,3,1,""],value:[0,3,1,""]},"mako.exceptions":{RichTraceback:[10,1,1,""],html_error_template:[10,4,1,""],text_error_template:[10,4,1,""]},"mako.ext.beaker_cache":{BeakerCacheImpl:[0,1,1,""]},"mako.lookup":{TemplateCollection:[10,1,1,""],TemplateLookup:[10,1,1,""]},"mako.lookup.TemplateCollection":{adjust_uri:[10,2,1,""],filename_to_uri:[10,2,1,""],get_template:[10,2,1,""],has_template:[10,2,1,""]},"mako.lookup.TemplateCollection.get_template.params":{relativeto:[10,3,1,""],uri:[10,3,1,""]},"mako.lookup.TemplateCollection.has_template.params":{uri:[10,3,1,""]},"mako.lookup.TemplateLookup":{adjust_uri:[10,2,1,""],filename_to_uri:[10,2,1,""],get_template:[10,2,1,""],put_string:[10,2,1,""],put_template:[10,2,1,""]},"mako.lookup.TemplateLookup.params":{collection_size:[10,3,1,""],directories:[10,3,1,""],filesystem_checks:[10,3,1,""],modulename_callable:[10,3,1,""]},"mako.runtime":{Context:[7,1,1,""],LoopContext:[7,1,1,""],ModuleNamespace:[6,1,1,""],Namespace:[6,1,1,""],TemplateNamespace:[6,1,1,""],Undefined:[7,1,1,""],capture:[6,4,1,""],supports_caller:[6,4,1,""]},"mako.runtime.Context":{get:[7,2,1,""],keys:[7,2,1,""],kwargs:[7,0,1,""],lookup:[7,0,1,""],pop_caller:[7,2,1,""],push_caller:[7,2,1,""],write:[7,2,1,""],writer:[7,2,1,""]},"mako.runtime.LoopContext":{cycle:[7,2,1,""]},"mako.runtime.ModuleNamespace":{filename:[6,0,1,""]},"mako.runtime.Namespace":{attr:[6,0,1,""],cache:[6,0,1,""],context:[6,0,1,""],filename:[6,0,1,""],get_cached:[6,2,1,""],get_namespace:[6,2,1,""],get_template:[6,2,1,""],include_file:[6,2,1,""],module:[6,0,1,""],template:[6,0,1,""],uri:[6,0,1,""]},"mako.runtime.TemplateNamespace":{filename:[6,0,1,""],module:[6,0,1,""],uri:[6,0,1,""]},"mako.template":{DefTemplate:[10,1,1,""],Template:[10,1,1,""]},"mako.template.Template":{code:[10,0,1,""],get_def:[10,2,1,""],list_defs:[10,2,1,""],render:[10,2,1,""],render_context:[10,2,1,""],render_unicode:[10,2,1,""],source:[10,0,1,""]},"mako.template.Template.params":{buffer_filters:[10,3,1,""],bytestring_passthrough:[10,3,1,""],cache_args:[10,3,1,""],cache_dir:[10,3,1,""],cache_enabled:[10,3,1,""],cache_impl:[10,3,1,""],cache_type:[10,3,1,""],cache_url:[10,3,1,""],default_filters:[10,3,1,""],disable_unicode:[10,3,1,""],enable_loop:[10,3,1,""],encoding_errors:[10,3,1,""],error_handler:[10,3,1,""],filename:[10,3,1,""],format_exceptions:[10,3,1,""],future_imports:[10,3,1,""],imports:[10,3,1,""],include_error_handler:[10,3,1,""],input_encoding:[10,3,1,""],lexer_cls:[10,3,1,""],lookup:[10,3,1,""],module_directory:[10,3,1,""],module_filename:[10,3,1,""],module_writer:[10,3,1,""],output_encoding:[10,3,1,""],preprocessor:[10,3,1,""],strict_undefined:[10,3,1,""],text:[10,3,1,""],uri:[10,3,1,""]},RichTraceback:{error:[10,0,1,""],lineno:[10,0,1,""],message:[10,0,1,""],records:[10,0,1,""],reverse_records:[10,0,1,""],reverse_traceback:[10,0,1,""],source:[10,0,1,""]}},objnames:{"0":["py","attribute","Python attribute"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","parameter","Python parameter"],"4":["py","function","Python function"]},objtypes:{"0":"py:attribute","1":"py:class","2":"py:method","3":"py:parameter","4":"py:function"},terms:{"2to3":1,"5b1":1,"abstract":10,"boolean":10,"break":1,"byte":[1,9,10],"case":[0,1,2,3,5,6,7,8,9,10],"catch":1,"class":[0,1,2,5,6,7,9,10],"default":[0,1,2,3,5,6,7,8,9,10],"dr\u00f4le":9,"export":[2,5,8],"f\u00e9rotin":1,"final":[1,3,5,9],"function":[0,1,2,3,5,6,7,8,9,10],"import":[0,1,2,3,6,7,8,9,10],"int":7,"long":[1,7,8],"new":[0,1,2,3,5,7,8,10],"pla\u00eet":9,"r\u00e9veill\u00e9":9,"return":[0,1,2,3,6,7,8,9,10],"short":0,"static":[4,5],"super":[0,5,6,9],"switch":7,"throw":[0,7],"true":[0,1,2,3,6,7,8],"try":[1,3,7,8,9,10],"var":1,"while":[1,2,3,5,8,10],__builtin__:1,__builtins__:1,__class__:[1,10],__file__:6,__future__:[1,10],__getattr__:1,__html__:1,__init__:0,__len__:7,__m_:1,__m_local:9,__name__:[0,1,10],__nonzero__:1,__str:9,__str__:7,__version__:1,_cach:0,_data:1,_my_cache_work:0,_pop_buff:1,_pop_fram:1,_push_buff:1,_push_fram:1,abil:[0,6,8,9,10],abl:7,about:[1,4],abov:[0,2,3,5,6,7,8,9,10],above:[0,5,6,8,10],absolut:[1,2,9],accept:[0,1,3,6,7,8,9,10],accessor:[0,1,5,6],accommod:1,accompani:10,accomplish:[0,8,10],accord:1,accordingli:10,account:2,accountdata:2,accountnam:2,accumul:8,achiev:[2,5,7],acquir:[0,9],across:[0,7],act:[7,10],actual:[0,1,2,3,5,6,7,8,10],add:[2,3,5,10],added:[1,10],addit:[0,1,2,3,5,6,8,10],addition:[1,5,9,10],address:[0,10],adjust:[1,6,8,10],adjust_uri:10,advanc:10,advantag:[5,6,9,10],affect:[1,7],afford:[1,10],after:[0,1,3,6,7,10],again:[2,7],against:[1,8,10],agre:5,akkerman:1,algorithm:1,all:[0,1,2,3,4,5,6],allow:[0,1,2,3,5,6,7,8,9,10],almost:[5,8],alon:1,along:[0,5,6],alor:9,alpha:1,alreadi:[1,5,7,10],also:[0,1,2,3,5,6,7,8,9,10],altern:[1,7,9,10],although:8,altogeth:1,alwai:[1,2,5,7,9],ani:[0,1,2,3,5,6,7,8,9,10],anonym:[0,1,2,8],anoth:[1,2,6,8,9,10],another:[5,7,10],answer:1,any:[0,3,8,9],anyth:[2,5,9],anywai:[1,10],anywher:[2,6,8],appar:[1,3,6],appear:[1,3,7,8,10],append:10,appli:[1,2,3,7,8,9,10],applic:[1,3,7,8,10],apply:6,approach:[5,7,9],appropri:1,approxim:10,apr:1,aptli:10,arbitrari:[0,8],arbitrarili:[1,2],area:[2,5,7,8,9],aren:[1,2,9],arg1:6,arg2:6,arg3:6,arg4:6,arg:[0,1,2,3,6,8,10],argpars:1,arguabl:9,around:[1,3,7,10],arrai:3,arrang:8,ascii:[1,9],ask:7,aspect:[8,9],assign:[1,2,7,8,10],associ:[0,1,7],assum:[9,10],ast:[1,9],atom:10,attach:6,attempt:[0,1,9],attr:[1,5],attribut:[0,1,2,3,4],attributeerror:1,aug:1,augment:[2,4],author:7,automat:[0,2,3,5,7,8,10],avail:[0,1,2,3,5,6,7,8,9,10],availabl:0,avoid:1,awai:5,awar:[1,7,9,10],babel:1,babelplugin:10,back:[1,5,7,9,10],background:9,backslash:[1,8],backward:[0,1],bar:[1,2,3,6,7,8,10],bare:1,base:[0,1,3,4,5,6,7,8],basemost:5,basestr:1,basi:[0,5,7],basic:[1,2,4,6,8,9],batch:3,batcheld:1,beaker_cach:0,beakercacheimpl:0,bean:10,becam:1,becaus:[1,2,3,5,9],becom:[1,6,9,10],been:[0,1,3,6,9,10],befor:[0,1,3,5,6,8,9,10],began:7,begin:10,behav:2,behavior:[1,3,5,7,10],bell:9,below:[1,2,5,9],ben:1,benchmark:1,best:8,better:[0,1,7],between:[1,2,5,6,7],beyond:[0,2],binari:9,bit:[1,2,7,10],bitbucket:1,bitwis:1,black:7,blank:[1,7],block:[0,1],blunt:0,board:7,bodi:[0,1,2,4,5],bold:3,bom:1,bool:7,bot:7,both:[1,2,3,5,7,9,10],bottom:1,bottommost:5,bound:1,bracket:1,breakag:1,breakdown:5,brief:10,broke:1,broken:1,buf:[3,10],buffer:1,buffer_filt:[1,10],buffet:1,bug:1,bugfix:1,build:[2,5,6],builder:1,buildtabl:2,built:[1,2,3,4,5],builtin:[1,9],bump:1,bunch:6,burden:9,bye:2,bytestr:[1,10],bytestring_passthrough:[1,10],cache_:[0,1],cache_arg:[0,1,10],cache_dir:[0,1,10],cache_en:[0,1,10],cache_impl:[0,1,10],cache_kei:[0,1],cache_region:0,cache_timeout:[0,1,2],cache_typ:[0,1,8,10],cache_url:[0,1,10],cache_xyz:0,cacheabl:1,cacheimpl:[0,1,10],cachemanag:[0,1],calcul:10,call:[0,1],call_my_object:9,callabl:[0,1,2,3,6,7,8,10],callable_:[6,10],caller:[1,2,3,6,7],caller_stack:[1,6,9],calling_uri:6,callstack:7,came:1,camp:1,can:[0,1,2,3,5,6,7,8,9,10],cannot:[1,2,9,10],cant:1,capabl:[0,1,10],captur:[1,3,6,7,10],care:[0,6,7,9],catalog:10,categori:6,caught:10,caus:[1,3,6,7,10],cazabon:1,central:[2,3,7,8],certain:[1,3,6,9,10],cfg:[1,10],cgi:[1,3,9],chain:[1,5,6,7,8],chang:[0,1,5,7,9],chapter:[2,3,4,5],charact:[1,8,9,10],characterist:8,charl:1,check:[1,5,7,8,9],checker:7,cheetah:9,child:5,choos:9,chosen:0,clarifi:1,class_:5,classic:[6,8],clean:[0,1,10],cleaner:7,close:[1,2,6,8,10],closur:2,cmd:1,cmdline:1,code:[1,2,3,6,7,8,9,10],codebas:1,codec:[9,10],codegen:1,codi:1,coerc:9,col:2,collect:[0,1,6,7,9],collection_s:10,collis:1,colomiet:1,colon:[0,8],column:2,combin:[1,7],come:[0,2,5,8,9,10],comma:[2,3,10],command:[1,10],comment:[1,4],common:[1,4,5,6,9],commonli:[0,5,9],commun:[2,7],comp1:6,comp2:6,comp:6,compar:[9,10],compat:[0,1,6,10],compil:[0,1,7,8,10],compileexcept:1,complet:[1,5,6,10],complex:1,compliant:9,compon:[0,6,7],comprehens:1,concaten:[3,10],conceiv:7,concept:[2,8,10],condit:[1,2,5,8],condition:[1,6],configur:[0,1,5,6,10],conflict:0,conform:1,confus:[5,9],conjunct:[1,5,10],consid:[1,7,10],consist:8,consol:9,conson:7,constant:7,construct:[0,1,2,5,6,8,9,10],constructor:1,consum:[0,1,8],contain:[0,1,2,6,8,9,10],content:[0,1],context:[0,1,2,3,4,5,6],contextu:2,contigu:8,continu:[1,8,9,10],contrast:[2,5,9],contrib:1,contribut:1,contriv:10,control:[1,2,3,4,5,7],convei:10,conveni:0,convent:[2,6],convers:[1,9],convert:[0,1,9,10],convert_com:1,copi:[1,6,7],core:1,correct:[1,6],correctli:[1,7],correspond:[0,5,6,7,10],corrupt:1,could:[1,5],couldn:1,count:[2,7,10],coupl:1,cours:[1,7],courtesi:1,cover:1,coverag:1,creat:[0,1,2,6,7,8,9,10],creation:[0,1,2,3,10],creation_funct:0,critic:1,crlf:1,cross:1,css:[1,6,10],cstringio:[1,9,10],ctx:10,current:[1,2,5,6,7,8,10],current_sect:8,custom:[1,2,3,5,6,8,9,10],dairiki:1,daniel:1,data:[0,1,2,6,7,9,10],databas:2,date:1,daverio:1,dbm:0,deal:[7,8,9],dealt:10,dec:1,decid:[7,8],decis:[5,7,9],declar:[1,2,3,4,5],decod:[1,3,9],decor:1,decreas:6,deepli:2,def:[0,1],default_filt:1,defin:[1,2,3,4,5,6,7,8],definit:[2,3,5,6],defnam:[1,2],deftempl:[2,10],delai:1,deliv:[1,3,6],delta:6,demarc:2,denot:8,depend:[1,4],deploy:1,deprec:[1,10],depth:7,derek:1,deriv:[0,1,3,9],describ:[1,2,3,5,6,7,8,9,10],descript:10,descriptor:1,design:3,desir:[1,6,9,10],despit:1,dessin:9,dest:10,destin:10,detail:[2,5,7,8,9,10],detect:1,determin:[0,1,9],determinist:3,develop:9,dict:[1,9],dictionari:[0,1,6,7,10],did:[1,5],differ:[0,1,2,5,6,7,10],differenti:7,dir:[0,1,10],direct:[0,2,6,8,10],directli:[0,1,2,3,6,8,10],directori:[0,1,3,7,9,10],dirnam:10,disabl:[0,1,3,4,7],disable_unicod:[1,3],disait:9,disallow:1,discard:3,discuss:1,disgard:9,displai:[1,10],disregard:10,distinct:[1,10],distinctli:5,distribut:10,distutil:10,div:[2,5,6,10],divis:10,do_something_speci:0,doc:[1,2,7],document:[0,1,5,8,9,10],doe:[1,2,5,6,7,8,9],doesn:[1,2,5,6,7],don:[0,1,2,5,7,9],done:[9,10],dot:1,doubli:1,down:[0,1,9],dragon:1,draw:3,drive:1,drop:[1,8],due:1,dumb:9,dump:[6,9],dure:[1,5,10],dyn:6,dynam:[1,5,8],each:[0,1,2,5,6,7,8,9,10],earli:[1,4],earlier:[0,9],eas:[3,7],easi:[3,7],easier:0,edgewal:1,eeve:1,effect:[0,1,2,3,6,10],egg:7,either:[0,1,5,7,8,9,10],elabor:1,elem:8,element:[1,2,5,7,8,9,10],elif:8,elimin:9,elle:9,els:[0,1,7,8,10],emac:1,email:8,emb:[6,8,9],embed:1,emit:[1,8],empti:[1,3,8,9],enabl:[0,1,7,8,10],enable_loop:[1,7,10],enclos:[1,2,7],encod:[1,3,9,10],encode:4,encoding_error:[1,9,10],encount:[1,5],end:[1,3,5,8],endfor:[2,6,7,8],endif:[1,2,6,7,8],endless:1,endwith:1,enforc:1,enorm:2,ensur:[0,1,6,9],entir:[2,3,5,6,8,9,10],entire:4,entiti:[1,3],entri:[0,1,10],entrypoint:[0,1],enumer:7,environ:[1,3,4],epochal:0,equival:[0,2,3,6,8,9],eric:1,errant:1,error:[1,2,7,9,10],error_handl:[1,10],escap:[1,2,3,8,9],escape:[3,4],essenti:[0,6,9],establish:[1,7,10],etc:[0,1,2,6,7,8,10],eval:1,evalu:[1,2,6,8],evaul:1,even:[1,5,7,8,9],ever:[6,9],everi:[1,6,8],everyon:7,everyth:[1,7],exactli:[2,5],examin:6,exampl:[0,1,2,3,4,5],exc:1,exc_info:[1,10],exceed:7,except:[0,1,2,3,6,7,8,10],exception:4,excerpt:10,exclus:10,exec:1,execut:[0,1,2,3,5,6,7,8,10],exist:[0,1,2,6,7,8,9,10],exit:1,exite:[1,4],expand:1,expect:[1,2,5,7,8,9],experienc:7,expir:[0,1],expiri:1,explcitli:1,explicit:[0,1,2,6,7,8,9],explicitli:[1,5,6,7,9,10],expr:[1,2,6],express:[1,2,3,5,6,7,8,9,10],expression_filt:[1,3],ext:[0,1,10],extens:1,extern:[0,2,5],extra:[1,5,8],extract:[1,10],extraction:10,extractor:[1,10],facad:0,facet:7,facil:5,fact:[2,5,9],fail:1,failur:7,fake:8,fall:0,fals:[0,1,7,10],familiar:[2,8],far:[1,5,8,9,10],fashion:0,fast:10,fastencodingbuff:[1,9],faster:[1,9],featur:[0,1,5,7,8,10],feb:1,few:[1,7],field:10,file:[0,1],filehandl:[1,9],filenam:[0,1,6,10],filename_to_uri:10,filesystem:[0,1,6],filesystem_check:10,filter:[1,2],find:[7,8,10],finish:5,first:[0,1,3,5,6,7,8,9,10],five:[0,8],fix:[0,1,6,10],flag:[0,1,3,6,7,8,9,10],flexibl:[3,5,8],flip:2,flow:8,fly:9,follow:[1,2,5,6,7,8,10],foo:[1,2,3,6,7,8,9,10],footer:[5,8],forc:[1,10],form:[1,2,6,8],format:[1,2,6,8,9,10],format_except:[1,10],formatt:1,former:1,forward:1,found:[1,2,7,8],four:[6,8],fragment:1,frame:1,framework:4,francoi:10,free:[1,6],freeli:7,fri:1,frobnizzl:8,from:[0,1],frozenset:1,full:[1,8,10],fulli:[1,3,5,10],func:6,further:[1,8],futur:[6,8],future_import:[1,10],futures_import:10,fyi:1,gae:1,game:9,garbag:0,gather:9,gave:10,geisler:1,gener:[0,1,2,3,5,6,7,8,9,10],genshi:8,georg:1,get:[0,1,3,5,6,7,8,9,10],get_cach:6,get_def:[1,2,3,10],get_namespac:[1,6],get_or_cr:[0,1],get_resourc:8,get_templ:[0,6,9,10],getargspec:1,getattr:6,getdefaultencod:1,gettext:[1,10],getvalu:[3,10],github:1,give:[2,6],given:[0,1,2,3,5,6,7,10],global:[0,2,5,6,7],glyph:1,goal:[1,3],goe:8,good:[0,1,8],got:1,graphic:9,great:[6,9],grei:5,group:[0,1,6],guess:[1,9],guest:1,guid:10,hack:[1,7],had:[1,9],hadn:1,haltner:1,ham:7,hand:5,handi:6,handl:[0,1,2,4,7,8],handler:[1,10],happen:[6,7,9],hard:[5,7,8,9],harland:1,has_templ:10,hasattr:6,hash:1,have:[0,1,2,3,5,6,7,8,9,10],head:[2,5,6,10],header:[0,1,2,5,8,10],heavili:9,heck:4,hello:[2,6,8,9,10],help:[0,1,9,10],helper:10,her:9,here:[0,1,3,5,6,7,8,9,10],highlight:[1,10],hit:[3,9],hold:6,home:1,honor:1,hopefulli:1,how:[1,2,6,7,8,10],howev:[1,2,5,6,9],href:[2,6],htdoc:10,html:[0,1,2,3,5,6,8,9,10],html_error_templ:[1,10],html_escap:1,htmlentitydef:3,htmlentityreplac:[1,10],http:1,huayi:1,hypothet:5,idea:[1,5,8],ideal:1,ident:[1,6,10],identifi:[0,1,8,10],ignor:[7,8],illus:9,illustr:[3,5,10],imag:[9,10],imaginez:9,imankulov:1,immedi:[1,5,7,8,9,10],immut:7,impl:0,implement:[0,1,2,5,10],impli:10,implic:9,implicit:[0,7],implicitli:1,improv:[1,8,9,10],improve:1,incl:6,includ:[0,1,2,4],include:[0,6,8],include_error_handl:[1,10],include_fil:[1,6],incom:9,incompat:1,incorrect:1,increas:10,indent:[1,8],index:[1,4,5,6,7,8,10],indic:[0,1,7,8],individu:[0,1,2,7,10],info:[1,10],inform:[1,6,8,9,10],inher:3,inherit:[0,1,2,4],initi:[1,2],inject:10,inlin:[1,5,7,8],inner:[1,2],input:[1,2,3,9],input_encod:[1,9,10],insensit:1,insert:[5,10],insid:[0,1,2,5,6,8,10],inspect:1,inspir:8,inspire:8,instal:[0,1],install_requir:1,instanc:[6,7,8,10],instead:[1,2,3,5,6,9,10],insur:1,integ:[0,2,9],integr:[0,1,5,10],integrat:4,intellig:9,intend:[1,3,6],intent:3,interact:[5,6,9],interchang:5,interest:10,interfac:0,intermedi:5,intermix:5,intern:[0,1,3,7,9,10],interpret:[1,2,9,10],interven:1,intric:1,intro:2,introduc:[2,5,6,7,8],invalid:[0,1],invalidate_bodi:[0,1],invalidate_closur:[0,1],invalidate_def:[0,1],invoc:5,invok:[2,5,8,10],invoke:10,involv:[1,5],ioerror:1,iou:7,isn:[1,7],issu:[1,2,9,10],item:[2,7,8],iter:[2,6,7],iterat:6,itself:[0,1,2,3,5,6,7,8,9,10],jack:10,jan:1,javascript:6,jeff:1,jinja2:[1,2,8],jinja:1,jit:7,job:3,joe:8,john:2,join:9,jonathan:1,jot:7,jour:9,json:1,jsp:8,jul:1,jun:1,just:[1,2,3,5,6,7,8,9,10],jut:7,jython:1,keep:2,kei:[0,1,5,6,7,9,10],keyerror:7,keyword:[1,2,5,6,7,8,9,10],kind:[0,3,5,6,7,8,9,10],know:[5,9],known:[1,2,6],kwarg:[0,1,6,7,10],lack:1,lai:2,lambda:1,languag:[2,8,9],larg:[1,5],last:[1,7,10],last_modifi:1,later:[0,8],latest:1,latter:[1,9],laurent:1,layout:[1,2,5,6,10],layoutdata:2,lead:[1,3,6,7],learn:9,least:[6,10],left:[3,10],leftmost:3,legaci:1,legacy_html_escap:1,legendari:1,len:8,less:[1,5,7,9],let:[1,2,5,7,10],level:[0,1,2,3,4,5,6,7],lever:9,leverag:8,lex:1,lexer:[1,8,9,10],lexer_cl:[1,10],lib:1,librari:[0,2,3,6,9,10],lieu:10,lift:5,lighter:1,like:[0,1,2,3,5,6,7,8,9,10],line:[1,5,8,9,10],lineno:10,lingua:1,link:[6,10],linkag:5,list:[0,1,2,3,5,7,8,9,10],list_def:[1,10],lister:2,liter:[1,6,9,10],littl:[1,2,7,10],live:0,load:[6,8,10],load_templ:1,loader:1,local:[0,1,2,3],locals_:1,locat:[1,6,7,9,10],lock:0,logic:[1,3],long_term:0,longer:1,look:[0,1,2,5,6,7,9,10],lookup:[0,1,7,9,10],loop:[1,2,4],loopcontext:7,lopez:1,lost:1,lot:[1,8],lower:1,made:[0,1,7],magamedov:1,magic:[1,7,9],mai:[0,1,3,6,7,8,9,10],main:[1,2,3,5,6,7,9,10],mainlayout:[2,5],mainli:[1,6],maintain:[0,1,10],major:[1,7,9],mak:1,make:[0,1,2,3,5,6,7,8,9,10],mako:[0,1,2,3,4,5,6],mako_cach:0,mako_modul:10,manag:[0,1,7],manfr:1,mani:[1,7,8],manner:3,manual:10,map:[1,10],mar:1,markedli:9,marker:[1,8],markupsaf:[1,3,9],martin:1,matter:5,maxim:[0,9],maximum:1,mayb:5,mean:[0,1,2,3,5,6,7,8,9,10],meant:5,mechan:[0,5,8],member:[7,8,10],memcach:[0,1],memori:[0,1,8,10],mention:9,merg:1,mess:1,messag:[1,7,10],met:2,metadata:[1,8],metaphor:5,method:[0,1,2,3,4,5],middl:[3,5,8],might:[5,6,7,8],migrat:1,mimic:10,mini:7,minim:0,minor:10,minu:[0,1],minut:0,mirror:10,miss:[1,3,7,10],mistak:5,mix:1,mkstemp:10,mode:[1,9],model:2,moder:10,modern:[0,1],modifi:[1,2,5,9,10],modul:[0,1,2,3,4,5],module_directori:[0,1,10],module_filenam:[1,10],module_writ:[1,10],modulenam:0,modulename_cal:[1,10],modulenamespac:6,modulepath:0,moduletempl:1,moi:9,moment:10,mon:1,more:[0,1,2,3,5,6,7,8,9,10],most:[0,1,2,5,6,7,8,9,10],mostli:[0,1,6,7,10],mouton:9,move:10,msgid:10,msgstr:10,much:[1,2,5,8,9],multi:1,multibyt:[1,10],multilin:[1,8],multipl:[0,1,2,4],multithread:0,must:[0,1,2,5,6,9,10],mutual:10,my_tag:6,mycomp:0,mydef:2,myescap:3,myexpress:3,myfil:8,myfilt:[1,3],myfunc:8,myghti:9,myghtyutil:1,mylib:8,mylookup:[9,10],myn:1,mynamespac:[6,8],mypackag:3,myproj:10,mystuff:2,mystyl:6,mytag:6,mytempl:[0,1,9,10],mytmpl:10,name:[0,1],nameerror:[1,7,10],namespac:[0,1,2,3,4],namespace_nam:6,namespacenam:[1,2,8],nari:9,nativ:9,natur:3,necessarili:7,ned:1,need:[0,1,2,5,6,7,9,10],neither:0,nest:[0,1,2,3,4],nestabl:2,never:1,newer:[2,10],newli:0,newlin:[1,4],next:[0,2,3,4],nightmar:9,ninja:5,node:1,non:[1,7,8,9,10],none:[0,1,3,6,7,8,10],normal:[1,2,3,7,8,9,10],nose:1,note:[0,1,2,3,5,6,7,9,10],noth:5,notic:2,notimplementederror:10,notion:7,nov:1,now:[1,5,7,8,9],number:[0,1,2,7,8,10],numer:8,nutshel:5,object:[0,1,2,3,5,6,7,8,9,10],objnam:0,observ:1,obsolet:1,obvious:5,occlud:1,occur:[0,1,2,10],oct:1,odd:[1,7],off:[0,1,2],offer:[8,9],often:[5,6],old:[1,7],onc:[2,5,8],once:7,one:[0,3,5],ongo:1,onli:[0,1,2,3,5,7,8,9,10],only:[1,2],onto:[7,8],open:[5,8,9],oper:[1,2,3,6,7,8,9,10],opposit:5,opt:[0,1,10],optim:1,option:[0,1,6,7,8,9,10],optpars:1,order:[0,1,5,8,9,10],ordinari:6,org:1,organ:[5,6],orient:[2,5],origin:[0,1,3,6,7,9,10],other:[0,1],otherwis:[1,7,8,9,10],our:[0,1,2,5,10],out:[0,1,2,5,8,9,10],outer:2,output:[1,2,3,4,5,6,7,8],output_encod:[1,9,10],outputpath:10,outsid:[1,2,5,6,7,9],outward:10,over:[1,3,6,7],overhead:[1,9],overrid:[0,1,5,6,7,9,10],overridden:[0,2,5,6],overrod:5,overwritten:0,own:[0,1,2,3,5,6,7,8,9,10],pack:1,packag:[0,1,8],page:[0,1],pagearg:[1,2,6,7,9],pagecontrol:2,paradigm:5,param:8,paramet:[0,1,6,9,10],parent:[0,1,2,4],parenthes:1,pariti:7,pars:[1,8,9,10],parseabl:1,part:[0,1,5,6,7],parti:0,partial:[1,5],particip:5,particular:[0,1,5,6,7,10],particularli:[1,6],pass:[0,1,2,5,6,7,8,9,10],pass_context:[0,1],passthru:1,patch:1,path:[0,1,6,10],pathnam:1,pattern:10,paul:1,pbj:7,penalti:1,peopl:1,pep:[1,9],per:[0,1,5,7,8,9],percent:[1,8],percentag:10,perform:[1,3,6,9,10],perhap:[2,7,8],perl:8,perm:1,perman:1,permiss:[1,10],persist:[0,1],petit:9,phase:10,philosophi:7,picki:9,pinard:10,pipe:[1,3],pit:7,pkg_resourc:[0,1],place:[0,1,2,5,8,10],plai:[6,9],plain:[1,2,6,8,9,10],platform:10,pleas:8,plu:[1,10],plug:0,point:[0,1,2,5,6,8,9,10],polymorph:8,pop:[0,3,7],pop_buff:3,pop_cal:7,pop_fram:9,popul:0,popular:10,populate_self:6,portabl:2,portion:[1,2],posit:6,possibl:[0,2,3,7],post:[2,10],post_pros:2,pot:7,potenti:5,pow:8,power:8,practic:[1,5],pre:[1,10],preambl:10,preced:[5,6,8,9,10],precompil:1,predefin:1,prefer:[1,9],prefix:[0,1,7],prep:7,prepend:1,preprocessor:[1,10],presenc:1,present:[0,1,2,5,6,7,9,10],preserv:1,pretti:[8,9],prevent:[1,8],previou:[1,2,5,6,7,10],previous:[1,6,10],primari:10,primarili:7,print:[2,9,10],printabl:9,prior:[3,7,9],privat:1,probabl:[0,1,2,7,10],procedur:0,process:[0,1,5,8,9],produc:[1,2,3,4],product:10,program:[8,9],programat:10,programm:9,progress:7,project:10,propag:[1,7,8,10],proper:10,properli:[1,9],properti:[1,6,10],propig:1,provid:[0,1,2,3,5,6,7,8,10],proxi:6,prune:1,pull:[1,2,6,7,10],pullreq:1,pure:[1,6,8,9],purpos:[1,7,8,9,10],push:7,push_buff:3,push_cal:7,push_fram:9,put:[0,1,5,6,7],put_str:10,put_templ:10,py2:1,py2k:1,py3k:1,pybabel:10,pygment:1,pygmentplugin:10,pylon:[1,10],pypars:1,pyramid:1,pythagorean:8,python3:1,python:[1,2,3,4,5],quand:9,quick:[1,2,8],quickli:9,quot:[1,9],quote_plu:3,rais:[1,2,7,9,10],rang:[1,2,8],rather:[1,7],raw:[1,9,10],reach:[7,10],read:[7,8,9],readme:1,real:[1,8,10],realli:[1,9],ream:9,reason:[7,9],recal:5,receiv:[1,2,3,6,8],recent:[1,10],recogn:[5,6],recommend:[1,6],recompil:[0,1,10],record:[6,8,10],recurs:1,red:7,reduc:3,reduct:1,referenc:[1,2,5,6,7],refresh:1,regard:[1,9],regardless:[1,2,5,7],regener:[1,10],regexp:1,region:[0,1],regist:[0,1],register_plugin:[0,1],regress:1,regular:[1,2,3,4,5],rel:[1,6,10],relat:[0,1,9,10],relationship:6,relativeto:10,releas:[0,1,6,8],reli:1,reload:10,remain:[1,2,7],remot:[2,6],remov:[1,6,9],render:[0,1,2,3,4],render_:7,render_bodi:[3,7,9,10],render_context:10,render_mydef:7,render_unicod:[1,9,10],reopen:1,repair:1,replac:[0,1,3,9,10],repons:6,report:[1,10],repres:[0,1,2,7,8,9,10],represent:[1,8,10],request:[0,1,6,7,10],requir:[0,1,2,6,8,9],requset:1,reserv:1,reserved_nam:1,reset:1,resolut:[5,6,10],resolv:[1,10],resourc:[1,5,10],respect:8,respons:[0,5,7],rest:[0,5,8],restrict:[1,2,5],result:[1,2,3,5,7,8,10],retriev:0,revers:10,reverse_index:7,reverse_record:10,reverse_traceback:10,revis:10,rework:1,rewrot:1,richtraceback:[1,10],right:[1,2,3,7,8,9],role:6,roman:1,root:[1,10],roughli:8,routin:10,row:2,rudiment:[0,10],rule:[1,2,5],run:[1,5,6,7,9,10],run_wsgi:[1,10],runner:[1,10],runtim:[0,1,3,4,5,6],runtimeerror:1,safe:[7,9],sai:[1,2,4,5,7],sake:3,same:[0,1,2,5,6,7,8,9,10],sampl:10,sane:2,sat:1,scaffold:6,scalar:[1,6],scenario:[1,2,5,6,7,10],scheme:[1,2,6,7,9,10],scope:[0,1,2,5,6,7,8],scott:1,script:[1,6],search:[4,10],second:[0,2,3],section:[0,1,2,5,6,7,10],sectiona:5,secur:1,see:[0,1,2,6,7,8,9,10],seem:1,segment:9,select:5,selector:1,self:[0,1,2,5],semant:[1,2,5,8],semi:0,send:[1,3,5,6,7,9,10],sens:7,sent:[1,3,6,7,8],sep:1,separ:[0,1,2,3,5,10],sequenc:1,seri:[0,1,9,10],serious:5,serv:[8,9,10],serve_templ:10,server:[0,8,10],servic:[0,8,9],set:[0,1,3,6,7,8,9],setup:[0,1,5,10],setuptool:[0,1,10],sever:[1,6],shall:5,share:[1,2,7],sharp:2,shell:1,shop:7,short_term:0,should:[0,1,6,7,10],shouldn:7,shutil:10,side:[1,2,3,8],sidebar:2,sign:[1,8],signatur:[1,2,6],signific:[7,8],silent:[1,7],similar:[2,3,5,6,7,8,9,10],similarli:[2,9],simpl:[0,2,7,8,10],simplecacheimpl:0,simpler:1,simplest:8,simpli:[3,5],simplic:3,simplifi:1,sinc:[1,2,5,6,7,9,10],singl:[0,1,2,3,5,8,9,10],singleton:7,skip:[1,10],slain:1,slash:[1,6,8],slight:1,slightli:[6,9],slim:0,slowdown:1,slower:9,small:[1,10],smoothli:5,some:[0,1,2,3,5,6,7,8,9,10],some_cal:1,some_condit:2,some_namespac:6,some_other_directori:1,some_tag:1,some_templ:[1,10],somedata:2,somedef:[0,1,2,3,6,8],someencod:1,somefil:[1,6],somefunct:6,somekei:[0,1],somemodul:1,someobject:6,sometempl:0,someth:[2,3,9],sometim:[1,5,8],somev:[6,7],somevalu:0,somewhat:[2,3],somewher:[7,9,10],sophist:5,sound:[5,8],sourc:[1,5,8,9,10],source:[1,9],space:[0,1,2,8],spam:7,span:[2,5],special:[0,1,3,7,8,10],specifi:[0,1,3,4,5,7],speed:[1,3,9],speedup:1,sphinx:1,src:6,stack:[1,3,7,10],stacktrac:1,stage:10,stai:[0,7],standalon:[1,10],standard:[0,1,9],start:[0,2],starttim:0,startup:1,state:[1,2,5,7,9],statement:[1,2,8,10],stdout:[1,10],step:[1,2,9,10],stick:[1,2,7,8,9],still:[1,2,5,9],stop:[7,8],stop_rendering:[1,8],storag:[1,9],store:[0,1,3,7,9,10],str:[1,3,7,9,10],straight:[1,9,10],strategi:0,stream:[1,6,7,8,9,10],streamlin:5,strict:10,strict_undefin:[1,7,10],strictli:[1,9],string:[0,1,3,6,7,8,9,10],stringifi:1,stringio:[1,7,9,10],strip:[1,3],stripe:7,structur:[1,4,5,7],stuff:[6,8],style:[1,2,9],stylesheet:[6,10],sub:[2,8],subclass:[0,2,10],subcompon:2,subdef:2,subdirectori:1,subject:1,subsequ:0,substitut:[3,4,7],succe:1,success:10,suggest:1,suit:[1,5],summari:8,sun:1,supersed:[0,1],suppli:[1,6,8],support:[0,1,2,6,8,9,10],supports_cal:[1,6],suppos:[0,2],sure:[1,8],surpris:9,surround:[1,8],suspend:8,svn:1,swap:0,symbol:[1,8],synchron:1,synonym:[0,1,6],syntact:8,syntax:[1,2,3,4],system:[0,1,2,5,7,10],tabl:[1,2],tack:6,tag:[0,1,2,3,4,5,6,7],tagfilt:3,tailor:2,take:[1,2,3,5,6,8,9],taken:[0,1,6,10],target:[1,2,3],task:0,taylor:1,techniqu:7,techspot:1,tell:8,tempfil:[1,10],templat:[0,1,2,3,4],templatecollect:10,templatelookup:[0,1,3,4,6,7,9],templatelookupexcept:10,templatenam:10,templatenamespac:6,templatetext:[3,9],templateuri:6,temporari:1,temporarili:1,term:0,test:1,text:[0,1,2,3,6,7],text_error_templ:[1,10],textmat:1,textual:[3,5,10],tgplugin:1,than:[0,1,3,5,7,8,9],thank:1,thei:[1,2,3,5,7,8,9,10],them:[1,2,3,5,6,7,10],themselv:[0,2,5,6,7,8],theorem:8,therebi:6,therefor:[5,6,8,10],thereof:1,thi:[0,1,2,3,5,6,7,8,9,10],thing:[1,2,5,7,8,9],think:7,third:0,those:[0,1,2,6,7,8,10],though:[0,1,5,7,9],thread:0,threadsaf:0,three:[7,8],through:[1,6,7,9,10],throughout:[1,6],thrown:[0,10],thu:[1,10],time:[0,1,2,3,4],timeout:[0,1],timestamp:0,tinker:1,titl:[2,5,8],tmbundl:1,tmp:[3,10],togeth:[5,6],token:1,too:[1,3,5],tool:[0,1],toolbar:[5,8],top:[0,1,2,3,5,6,7,10],toplevellookupexcept:1,toplevelnotfound:10,topmost:[5,6,7,8],torborg:1,toscawidget:1,touch:1,toward:[2,5],trace:[1,10],traceback:[1,10],tracelin:10,track:[1,7],trail:3,transform:3,transit:7,translat:[1,10],translators:10,transpar:7,travers:6,treat:[1,9],treatment:9,tri:[2,7,10],trim:[1,3,8],trofatt:1,tryexcept:1,tue:1,tupl:[1,10],turbogear:1,turn:1,twist:2,two:[0,1,2,3,5],txt:[8,9,10],type:[0,1,2,6,7,8,9,10],typeerror:[1,7],typic:[0,10],ultim:[1,5,6],umask:1,unbound:10,unbuff:3,unclos:1,uncommon:1,uncondition:9,undeclar:[1,10],undefin:[1,7],undefined:[1,2,7,8,10],under:[0,1,9,10],underli:[0,2,3,5,6,7,8,10],underneath:0,underscor:1,understand:[5,9],understood:0,unescap:1,unexplain:1,unicod:[1,3,4],uniniti:7,uniqu:[0,5,7],unit:1,univers:1,unknown:1,unless:[7,9],unlik:9,unreach:2,until:[1,10],unusu:10,updat:10,update:1,upon:[0,1,2,3,5,10],uri:[1,6,8,10],url:[0,1,3,8,10],urllib:3,usabl:2,usag:[0,1,2,3,5,6,7,9,10],usage:[1,4],use:5,use_pag:3,user:[1,7,8,9,10],userbas:9,usernam:[2,8],usual:[1,3,7,8,10],usualli:[0,10],utf8:[3,9],utf:[1,3,9,10],util:10,valid:8,valu:[0,1,2,3,6,7,8,9,10],vanasco:1,variabl:[1,2,5,6],variant:[1,8],varieti:[0,6,8],variou:[1,3,6,7,8,9,10],vast:9,veri:[0,1,2,5,10],version:0,versu:[1,6,10],via:[0,1,2,5,6,7,8,9,10],view:10,vincent:1,vladimir:1,voix:9,vou:9,vowel:7,wai:[0,1,2,3,4,5],walkthrough:2,want:[0,2,3,5,6,7,8,9],warn:1,wasn:[1,5,7],web:10,wed:1,weight:1,welcom:1,well:[0,1,2,3,5,6,7,8,9,10],were:[1,5,6,7,9],what:[1,2,4],whatev:[1,6,7,9,10],whatsoev:[1,9],wheel:1,when:[0,1,2,3,5,6,7,8,9,10],whenev:[5,9,10],where:[0,1,2,3,5,6,7,8,9,10],wherea:[2,7,8,9],wherebi:1,wherev:9,whether:[1,3,7,8],which:[0,1,2,3,5,6,7,8,9,10],white:[1,5],whitespac:[1,2,3,8],who:[1,9],whole:[2,3,5,6],whoop:1,why:7,wichert:1,widget:2,window:1,wise:1,wish:[0,3,7],within:[0,1],without:[0,1,5,6,7],won:[5,7,10],wonder:8,word:5,work:[0,1,2,3,5,6,7,9,10],world:[2,6,7,8,9,10],woroshow:1,would:[0,1,2,3,5,7,9,10],wouldn:[6,8],wrap:[1,2,4],wrapper:3,writer:7,written:[1,5,8,10],wsgi:1,wsgiutil:10,x80:9,x99a:9,xa9:9,xa9veil:9,xb4le:9,xc3:9,xe2:9,xie:1,xml:[1,3,8,10],year:1,yet:[0,1,6],ymmv:1,you:[0,1,2,3,5,6,7,8,9,10],your:[1,2,3,5,6,7,8],yourself:[9,10],zebra:7,zer0:1,zero:1,zhang:1,zzzeek:1},titles:["Caching","Changelog","Defs and Blocks","Filtering and Buffering","Table of Contents","Inheritance","Namespaces","The Mako Runtime Environment","Syntax","The Unicode Chapter","Usage"],titleterms:{"static":6,"true":9,about:5,access:0,accessor:7,all:7,api:[0,6,7,10],argument:[0,2,3],attr:6,attribut:5,augment:5,babel:10,backend:0,base:10,basic:10,beaker:0,block:[2,3,5,8],bodi:6,buffer:[3,7,9],built:[6,7],cach:0,call:[2,6,8],changelog:1,chapter:9,check:10,collect:10,comment:8,common:10,content:[2,4,5],context:[7,8],control:8,cycl:7,declar:6,decor:3,def:[2,3,5,6,8],default_filt:3,defin:9,defnam:8,depend:6,disabl:9,disable_unicod:9,doc:8,dogpil:0,earli:8,embed:2,encode:[9,10],entire:9,environ:7,escape:8,exampl:6,exception:10,exite:8,expression:[3,8,9],file:[2,9,10],filesystem:10,filter:[3,8],framework:10,from:[2,6,8],guidelin:0,handl:[9,10],heck:9,includ:[5,8],indice:4,inherit:[5,6,8],integrat:10,iterat:7,legaci:7,level:8,local:6,loop:[7,8],mako:7,method:[6,7],migrat:7,modul:[6,8],multipl:5,name:[2,5,6,7],namespac:[5,6,8],nest:5,newlin:8,next:5,nsname:8,off:3,older:1,one:6,other:2,output:9,page:[2,8],parent:[5,7],plugin:0,produc:5,programmat:[0,2],pygment:10,python:[6,8],refer:[0,6,7,10],regular:6,render:5,reserv:7,rule:9,runtim:7,sai:9,select:9,self:6,set:10,size:10,specif:[0,6],specifi:9,structur:8,substitut:8,syntax:8,tabl:4,tag:8,templat:[5,7,8,9,10],templatelookup:10,text:8,time:5,turn:3,two:6,unicod:[9,10],usage:[6,9,10],use:[6,7],using:[0,2,5,10],variabl:7,version:[1,6],wai:6,what:5,within:2,word:7,wrap:5,write:0,wsgi:10}})
\ No newline at end of file
diff --git a/doc/syntax.html b/doc/syntax.html
new file mode 100644 (file)
index 0000000..9dab0a6
--- /dev/null
@@ -0,0 +1,621 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Syntax
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Defs and Blocks" href="defs.html" />
+        <link rel="prev" title="Usage" href="usage.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="usage.html" title="previous chapter">Usage</a>
+            </li>
+            <li>Next:
+            <a href="defs.html" title="next chapter">Defs and Blocks</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/syntax.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Syntax
+            
+
+        <h2>
+            
+                Syntax
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Syntax</a><ul>
+<li><a class="reference internal" href="#expression-substitution">Expression Substitution</a></li>
+<li><a class="reference internal" href="#expression-escaping">Expression Escaping</a></li>
+<li><a class="reference internal" href="#control-structures">Control Structures</a><ul>
+<li><a class="reference internal" href="#the-loop-context">The Loop Context</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#comments">Comments</a></li>
+<li><a class="reference internal" href="#newline-filters">Newline Filters</a></li>
+<li><a class="reference internal" href="#python-blocks">Python Blocks</a></li>
+<li><a class="reference internal" href="#module-level-blocks">Module-level Blocks</a></li>
+<li><a class="reference internal" href="#tags">Tags</a><ul>
+<li><a class="reference internal" href="#page"><code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code></a></li>
+<li><a class="reference internal" href="#include"><code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code></a></li>
+<li><a class="reference internal" href="#def"><code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code></a></li>
+<li><a class="reference internal" href="#block"><code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code></a></li>
+<li><a class="reference internal" href="#namespace"><code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code></a></li>
+<li><a class="reference internal" href="#inherit"><code class="docutils literal"><span class="pre">&lt;%inherit&gt;</span></code></a></li>
+<li><a class="reference internal" href="#nsname-defname"><code class="docutils literal"><span class="pre">&lt;%</span></code>nsname<code class="docutils literal"><span class="pre">:</span></code>defname<code class="docutils literal"><span class="pre">&gt;</span></code></a></li>
+<li><a class="reference internal" href="#call"><code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code></a></li>
+<li><a class="reference internal" href="#doc"><code class="docutils literal"><span class="pre">&lt;%doc&gt;</span></code></a></li>
+<li><a class="reference internal" href="#text"><code class="docutils literal"><span class="pre">&lt;%text&gt;</span></code></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#exiting-early-from-a-template">Exiting Early from a Template</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="usage.html" title="previous chapter">Usage</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="defs.html" title="next chapter">Defs and Blocks</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="syntax">
+<span id="syntax-toplevel"></span><h1>Syntax<a class="headerlink" href="#syntax" title="Permalink to this headline">¶</a></h1>
+<p>A Mako template is parsed from a text stream containing any kind
+of content, XML, HTML, email text, etc. The template can further
+contain Mako-specific directives which represent variable and/or
+expression substitutions, control structures (i.e. conditionals
+and loops), server-side comments, full blocks of Python code, as
+well as various tags that offer additional functionality. All of
+these constructs compile into real Python code. This means that
+you can leverage the full power of Python in almost every aspect
+of a Mako template.</p>
+<div class="section" id="expression-substitution">
+<h2>Expression Substitution<a class="headerlink" href="#expression-substitution" title="Permalink to this headline">¶</a></h2>
+<p>The simplest expression is just a variable substitution. The
+syntax for this is the <code class="docutils literal"><span class="pre">${}</span></code> construct, which is inspired by
+Perl, Genshi, JSP EL, and others:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">this is x: </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Above, the string representation of <code class="docutils literal"><span class="pre">x</span></code> is applied to the
+template&#8217;s output stream. If you&#8217;re wondering where <code class="docutils literal"><span class="pre">x</span></code> comes
+from, it&#8217;s usually from the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> supplied to the
+template&#8217;s rendering function. If <code class="docutils literal"><span class="pre">x</span></code> was not supplied to the
+template and was not otherwise assigned locally, it evaluates to
+a special value <code class="docutils literal"><span class="pre">UNDEFINED</span></code>. More on that later.</p>
+<p>The contents within the <code class="docutils literal"><span class="pre">${}</span></code> tag are evaluated by Python
+directly, so full expressions are OK:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">pythagorean theorem:  </span><span class="cp">${</span><span class="nb">pow</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="nb">pow</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The results of the expression are evaluated into a string result
+in all cases before being rendered to the output stream, such as
+the above example where the expression produces a numeric
+result.</p>
+</div>
+<div class="section" id="expression-escaping">
+<h2>Expression Escaping<a class="headerlink" href="#expression-escaping" title="Permalink to this headline">¶</a></h2>
+<p>Mako includes a number of built-in escaping mechanisms,
+including HTML, URI and XML escaping, as well as a &#8220;trim&#8221;
+function. These escapes can be added to an expression
+substitution using the <code class="docutils literal"><span class="pre">|</span></code> operator:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot;this is some text&quot;</span> <span class="o">|</span> <span class="n">u</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The above expression applies URL escaping to the expression, and
+produces <code class="docutils literal"><span class="pre">this+is+some+text</span></code>. The <code class="docutils literal"><span class="pre">u</span></code> name indicates URL
+escaping, whereas <code class="docutils literal"><span class="pre">h</span></code> represents HTML escaping, <code class="docutils literal"><span class="pre">x</span></code>
+represents XML escaping, and <code class="docutils literal"><span class="pre">trim</span></code> applies a trim function.</p>
+<p>Read more about built-in filtering functions, including how to
+make your own filter functions, in <a class="reference internal" href="filtering.html"><span class="std std-ref">Filtering and Buffering</span></a>.</p>
+</div>
+<div class="section" id="control-structures">
+<h2>Control Structures<a class="headerlink" href="#control-structures" title="Permalink to this headline">¶</a></h2>
+<p>A control structure refers to all those things that control the
+flow of a program &#8211; conditionals (i.e. <code class="docutils literal"><span class="pre">if</span></code>/<code class="docutils literal"><span class="pre">else</span></code>), loops (like
+<code class="docutils literal"><span class="pre">while</span></code> and <code class="docutils literal"><span class="pre">for</span></code>), as well as things like <code class="docutils literal"><span class="pre">try</span></code>/<code class="docutils literal"><span class="pre">except</span></code>. In Mako,
+control structures are written using the <code class="docutils literal"><span class="pre">%</span></code> marker followed
+by a regular Python control expression, and are &#8220;closed&#8221; by
+using another <code class="docutils literal"><span class="pre">%</span></code> marker with the tag &#8220;<code class="docutils literal"><span class="pre">end&lt;name&gt;</span></code>&#8221;, where
+&#8220;<code class="docutils literal"><span class="pre">&lt;name&gt;</span></code>&#8221; is the keyword of the expression:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">if</span> <span class="n">x</span><span class="o">==</span><span class="mi">5</span><span class="p">:</span><span class="x"></span>
+<span class="x">    this is some output</span>
+<span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">%</span></code> can appear anywhere on the line as long as no text
+precedes it; indentation is not significant. The full range of
+Python &#8220;colon&#8221; expressions are allowed here, including
+<code class="docutils literal"><span class="pre">if</span></code>/<code class="docutils literal"><span class="pre">elif</span></code>/<code class="docutils literal"><span class="pre">else</span></code>, <code class="docutils literal"><span class="pre">while</span></code>, <code class="docutils literal"><span class="pre">for</span></code>, and even <code class="docutils literal"><span class="pre">def</span></code>, although
+Mako has a built-in tag for defs which is more full-featured.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;one&#39;</span><span class="p">,</span> <span class="s1">&#39;two&#39;</span><span class="p">,</span> <span class="s1">&#39;three&#39;</span><span class="p">,</span> <span class="s1">&#39;four&#39;</span><span class="p">,</span> <span class="s1">&#39;five&#39;</span><span class="p">]:</span><span class="x"></span>
+    <span class="cp">%</span> <span class="k">if</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;t&#39;</span><span class="p">:</span><span class="x"></span>
+<span class="x">    its two or three</span>
+    <span class="cp">%</span> <span class="k">elif</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;f&#39;</span><span class="p">:</span><span class="x"></span>
+<span class="x">    four/five</span>
+    <span class="cp">%</span> <span class="k">else</span><span class="p">:</span><span class="x"></span>
+<span class="x">    one</span>
+    <span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">%</span></code> sign can also be &#8220;escaped&#8221;, if you actually want to
+emit a percent sign as the first non whitespace character on a
+line, by escaping it as in <code class="docutils literal"><span class="pre">%%</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">%% some text</span>
+
+<span class="x">    %% some more text</span>
+</pre></div>
+</div>
+<div class="section" id="the-loop-context">
+<h3>The Loop Context<a class="headerlink" href="#the-loop-context" title="Permalink to this headline">¶</a></h3>
+<p>The <strong>loop context</strong> provides additional information about a loop
+while inside of a <code class="docutils literal"><span class="pre">%</span> <span class="pre">for</span></code> structure:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;ul&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;one&quot;</span><span class="p">,</span> <span class="s2">&quot;two&quot;</span><span class="p">,</span> <span class="s2">&quot;three&quot;</span><span class="p">):</span><span class="x"></span>
+<span class="x">    &lt;li&gt;Item </span><span class="cp">${</span><span class="n">loop</span><span class="o">.</span><span class="n">index</span><span class="cp">}</span><span class="x">: </span><span class="cp">${</span><span class="n">a</span><span class="cp">}</span><span class="x">&lt;/li&gt;</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+<span class="x">&lt;/ul&gt;</span>
+</pre></div>
+</div>
+<p>See <a class="reference internal" href="runtime.html#loop-context"><span class="std std-ref">The Loop Context</span></a> for more information on this feature.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.7.</span></p>
+</div>
+</div>
+</div>
+<div class="section" id="comments">
+<h2>Comments<a class="headerlink" href="#comments" title="Permalink to this headline">¶</a></h2>
+<p>Comments come in two varieties. The single line comment uses
+<code class="docutils literal"><span class="pre">##</span></code> as the first non-space characters on a line:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## this is a comment.</span><span class="x"></span>
+<span class="x">...text ...</span>
+</pre></div>
+</div>
+<p>A multiline version exists using <code class="docutils literal"><span class="pre">&lt;%doc&gt;</span> <span class="pre">...text...</span> <span class="pre">&lt;/%doc&gt;</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%doc&gt;</span>
+<span class="cp">    these are comments</span>
+<span class="cp">    more comments</span>
+<span class="cp">&lt;/%doc&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="newline-filters">
+<h2>Newline Filters<a class="headerlink" href="#newline-filters" title="Permalink to this headline">¶</a></h2>
+<p>The backslash (&#8220;<code class="docutils literal"><span class="pre">\</span></code>&#8221;) character, placed at the end of any
+line, will consume the newline character before continuing to
+the next line:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">here is a line that goes onto </span><span class="o">\</span>
+<span class="x">another line.</span>
+</pre></div>
+</div>
+<p>The above text evaluates to:</p>
+<div class="highlight-text"><div class="highlight"><pre><span></span>here is a line that goes onto another line.
+</pre></div>
+</div>
+</div>
+<div class="section" id="python-blocks">
+<h2>Python Blocks<a class="headerlink" href="#python-blocks" title="Permalink to this headline">¶</a></h2>
+<p>Any arbitrary block of python can be dropped in using the <code class="docutils literal"><span class="pre">&lt;%</span>
+<span class="pre">%&gt;</span></code> tags:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">this is a template</span>
+<span class="cp">&lt;%</span>
+    <span class="n">x</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">get_resource</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">)</span>
+    <span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="n">z</span><span class="o">.</span><span class="n">element</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">x</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">frobnizzle</span><span class="o">==</span><span class="mi">5</span><span class="p">]</span>
+<span class="cp">%&gt;</span>
+<span class="cp">%</span> <span class="k">for</span> <span class="n">elem</span> <span class="ow">in</span> <span class="n">y</span><span class="p">:</span><span class="x"></span>
+<span class="x">    element: </span><span class="cp">${</span><span class="n">elem</span><span class="cp">}</span>
+<span class="cp">%</span><span class="k"> endfor</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Within <code class="docutils literal"><span class="pre">&lt;%</span> <span class="pre">%&gt;</span></code>, you&#8217;re writing a regular block of Python code.
+While the code can appear with an arbitrary level of preceding
+whitespace, it has to be consistently formatted with itself.
+Mako&#8217;s compiler will adjust the block of Python to be consistent
+with the surrounding generated Python code.</p>
+</div>
+<div class="section" id="module-level-blocks">
+<h2>Module-level Blocks<a class="headerlink" href="#module-level-blocks" title="Permalink to this headline">¶</a></h2>
+<p>A variant on <code class="docutils literal"><span class="pre">&lt;%</span> <span class="pre">%&gt;</span></code> is the module-level code block, denoted
+by <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code>. Code within these tags is executed at the module
+level of the template, and not within the rendering function of
+the template. Therefore, this code does not have access to the
+template&#8217;s context and is only executed when the template is
+loaded into memory (which can be only once per application, or
+more, depending on the runtime environment). Use the <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code>
+tags to declare your template&#8217;s imports, as well as any
+pure-Python functions you might want to declare:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%!</span>
+    <span class="kn">import</span> <span class="nn">mylib</span>
+    <span class="kn">import</span> <span class="nn">re</span>
+
+    <span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
+        <span class="k">return</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s1">r&#39;^@&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Any number of <code class="docutils literal"><span class="pre">&lt;%!</span> <span class="pre">%&gt;</span></code> blocks can be declared anywhere in a
+template; they will be rendered in the resulting module
+in a single contiguous block above all render callables,
+in the order in which they appear in the source template.</p>
+</div>
+<div class="section" id="tags">
+<h2>Tags<a class="headerlink" href="#tags" title="Permalink to this headline">¶</a></h2>
+<p>The rest of what Mako offers takes place in the form of tags.
+All tags use the same syntax, which is similar to an XML tag
+except that the first character of the tag name is a <code class="docutils literal"><span class="pre">%</span></code>
+character. The tag is closed either by a contained slash
+character, or an explicit closing tag:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;foo.txt&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;foo&quot;</span> <span class="na">buffered=</span><span class="s">&quot;True&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is a def</span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>All tags have a set of attributes which are defined for each
+tag. Some of these attributes are required. Also, many
+attributes support <strong>evaluation</strong>, meaning you can embed an
+expression (using <code class="docutils literal"><span class="pre">${}</span></code>) inside the attribute text:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;/foo/bar/${myfile}.txt&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Whether or not an attribute accepts runtime evaluation depends
+on the type of tag and how that tag is compiled into the
+template. The best way to find out if you can stick an
+expression in is to try it! The lexer will tell you if it&#8217;s not
+valid.</p>
+<p>Heres a quick summary of all the tags:</p>
+<div class="section" id="page">
+<h3><code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code><a class="headerlink" href="#page" title="Permalink to this headline">¶</a></h3>
+<p>This tag defines general characteristics of the template,
+including caching arguments, and optional lists of arguments
+which the template expects when invoked.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">args=</span><span class="s">&quot;x, y, z=&#39;default&#39;&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Or a page tag that defines caching characteristics:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">page</span> <span class="na">cached=</span><span class="s">&quot;True&quot;</span> <span class="na">cache_type=</span><span class="s">&quot;memory&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Currently, only one <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag gets used per template, the
+rest get ignored. While this will be improved in a future
+release, for now make sure you have only one <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag
+defined in your template, else you may not get the results you
+want. The details of what <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> is used for are described
+further in <a class="reference internal" href="namespaces.html#namespaces-body"><span class="std std-ref">The body() Method</span></a> as well as <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</p>
+</div>
+<div class="section" id="include">
+<h3><code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code><a class="headerlink" href="#include" title="Permalink to this headline">¶</a></h3>
+<p>A tag that is familiar from other template languages, <code class="docutils literal"><span class="pre">%include</span></code>
+is a regular joe that just accepts a file argument and calls in
+the rendered result of that file:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;header.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+
+<span class="x">    hello world</span>
+
+<span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;footer.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Include also accepts arguments which are available as <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> arguments in the receiving template:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">include</span> <span class="na">file=</span><span class="s">&quot;toolbar.html&quot;</span> <span class="na">args=</span><span class="s">&quot;current_section=&#39;members&#39;, username=&#39;ed&#39;&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="def">
+<h3><code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code><a class="headerlink" href="#def" title="Permalink to this headline">¶</a></h3>
+<p>The <code class="docutils literal"><span class="pre">%def</span></code> tag defines a Python function which contains a set
+of content, that can be called at some other point in the
+template. The basic idea is simple:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;myfunc(x)&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is myfunc, x is </span><span class="cp">${</span><span class="n">x</span><span class="cp">}</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+
+<span class="cp">${</span><span class="n">myfunc</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">%def</span></code> tag is a lot more powerful than a plain Python <code class="docutils literal"><span class="pre">def</span></code>, as
+the Mako compiler provides many extra services with <code class="docutils literal"><span class="pre">%def</span></code> that
+you wouldn&#8217;t normally have, such as the ability to export defs
+as template &#8220;methods&#8221;, automatic propagation of the current
+<a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>, buffering/filtering/caching flags, and def calls
+with content, which enable packages of defs to be sent as
+arguments to other def calls (not as hard as it sounds). Get the
+full deal on what <code class="docutils literal"><span class="pre">%def</span></code> can do in <a class="reference internal" href="defs.html"><span class="std std-ref">Defs and Blocks</span></a>.</p>
+</div>
+<div class="section" id="block">
+<h3><code class="docutils literal"><span class="pre">&lt;%block&gt;</span></code><a class="headerlink" href="#block" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal"><span class="pre">%block</span></code> is a tag that is close to a <code class="docutils literal"><span class="pre">%def</span></code>,
+except executes itself immediately in its base-most scope,
+and can also be anonymous (i.e. with no name):</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">filter=</span><span class="s">&quot;h&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    some &lt;html&gt; stuff.</span>
+<span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Inspired by Jinja2 blocks, named blocks offer a syntactically pleasing way
+to do inheritance:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;html&gt;</span>
+<span class="x">    &lt;body&gt;</span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;header&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">        &lt;h2&gt;</span><span class="cp">&lt;%</span><span class="nb">block</span> <span class="na">name=</span><span class="s">&quot;title&quot;</span><span class="cp">/&gt;</span><span class="x">&lt;/h2&gt;</span>
+<span class="x">    </span><span class="cp">&lt;/%</span><span class="nb">block</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    </span><span class="cp">${</span><span class="bp">self</span><span class="o">.</span><span class="n">body</span><span class="p">()</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    &lt;/body&gt;</span>
+<span class="x">&lt;/html&gt;</span>
+</pre></div>
+</div>
+<p>Blocks are introduced in <a class="reference internal" href="defs.html#blocks"><span class="std std-ref">Using Blocks</span></a> and further described in <a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.4.1.</span></p>
+</div>
+</div>
+<div class="section" id="namespace">
+<h3><code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code><a class="headerlink" href="#namespace" title="Permalink to this headline">¶</a></h3>
+<p><code class="docutils literal"><span class="pre">%namespace</span></code> is Mako&#8217;s equivalent of Python&#8217;s <code class="docutils literal"><span class="pre">import</span></code>
+statement. It allows access to all the rendering functions and
+metadata of other template files, plain Python modules, as well
+as locally defined &#8220;packages&#8221; of functions.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">namespace</span> <span class="na">file=</span><span class="s">&quot;functions.html&quot;</span> <span class="na">import=</span><span class="s">&quot;*&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>The underlying object generated by <code class="docutils literal"><span class="pre">%namespace</span></code>, an instance of
+<a class="reference internal" href="namespaces.html#mako.runtime.Namespace" title="mako.runtime.Namespace"><code class="xref py py-class docutils literal"><span class="pre">mako.runtime.Namespace</span></code></a>, is a central construct used in
+templates to reference template-specific information such as the
+current URI, inheritance structures, and other things that are
+not as hard as they sound right here. Namespaces are described
+in <a class="reference internal" href="namespaces.html"><span class="std std-ref">Namespaces</span></a>.</p>
+</div>
+<div class="section" id="inherit">
+<h3><code class="docutils literal"><span class="pre">&lt;%inherit&gt;</span></code><a class="headerlink" href="#inherit" title="Permalink to this headline">¶</a></h3>
+<p>Inherit allows templates to arrange themselves in <strong>inheritance
+chains</strong>. This is a concept familiar in many other template
+languages.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">inherit</span> <span class="na">file=</span><span class="s">&quot;base.html&quot;</span><span class="cp">/&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>When using the <code class="docutils literal"><span class="pre">%inherit</span></code> tag, control is passed to the topmost
+inherited template first, which then decides how to handle
+calling areas of content from its inheriting templates. Mako
+offers a lot of flexibility in this area, including dynamic
+inheritance, content wrapping, and polymorphic method calls.
+Check it out in <a class="reference internal" href="inheritance.html"><span class="std std-ref">Inheritance</span></a>.</p>
+</div>
+<div class="section" id="nsname-defname">
+<h3><code class="docutils literal"><span class="pre">&lt;%</span></code>nsname<code class="docutils literal"><span class="pre">:</span></code>defname<code class="docutils literal"><span class="pre">&gt;</span></code><a class="headerlink" href="#nsname-defname" title="Permalink to this headline">¶</a></h3>
+<p>Any user-defined &#8220;tag&#8221; can be created against
+a namespace by using a tag with a name of the form
+<code class="docutils literal"><span class="pre">&lt;%&lt;namespacename&gt;:&lt;defname&gt;&gt;</span></code>. The closed and open formats of such a
+tag are equivalent to an inline expression and the <code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code>
+tag, respectively.</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">mynamespace:somedef</span> <span class="na">param=</span><span class="s">&quot;some value&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    this is the body</span>
+<span class="cp">&lt;/%</span><span class="nb">mynamespace:somedef</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>To create custom tags which accept a body, see
+<a class="reference internal" href="defs.html#defs-with-content"><span class="std std-ref">Calling a Def with Embedded Content and/or Other Defs</span></a>.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.2.3.</span></p>
+</div>
+</div>
+<div class="section" id="call">
+<h3><code class="docutils literal"><span class="pre">&lt;%call&gt;</span></code><a class="headerlink" href="#call" title="Permalink to this headline">¶</a></h3>
+<p>The call tag is the &#8220;classic&#8221; form of a user-defined tag, and is
+roughly equivalent to the <code class="docutils literal"><span class="pre">&lt;%namespacename:defname&gt;</span></code> syntax
+described above. This tag is also described in <a class="reference internal" href="defs.html#defs-with-content"><span class="std std-ref">Calling a Def with Embedded Content and/or Other Defs</span></a>.</p>
+</div>
+<div class="section" id="doc">
+<h3><code class="docutils literal"><span class="pre">&lt;%doc&gt;</span></code><a class="headerlink" href="#doc" title="Permalink to this headline">¶</a></h3>
+<p>The <code class="docutils literal"><span class="pre">%doc</span></code> tag handles multiline comments:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%doc&gt;</span>
+<span class="cp">    these are comments</span>
+<span class="cp">    more comments</span>
+<span class="cp">&lt;/%doc&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Also the <code class="docutils literal"><span class="pre">##</span></code> symbol as the first non-space characters on a line can be used for single line comments.</p>
+</div>
+<div class="section" id="text">
+<h3><code class="docutils literal"><span class="pre">&lt;%text&gt;</span></code><a class="headerlink" href="#text" title="Permalink to this headline">¶</a></h3>
+<p>This tag suspends the Mako lexer&#8217;s normal parsing of Mako
+template directives, and returns its entire body contents as
+plain text. It is used pretty much to write documentation about
+Mako:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span><span class="nb">text</span> <span class="na">filter=</span><span class="s">&quot;h&quot;</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="x">    heres some fake mako </span><span class="cp">${</span><span class="n">syntax</span><span class="cp">}</span><span class="x"></span>
+<span class="x">    </span><span class="cp">&lt;%</span><span class="nb">def</span> <span class="na">name=</span><span class="s">&quot;x()&quot;</span><span class="cp">&gt;${</span><span class="n">x</span><span class="cp">}&lt;/%</span><span class="nb">def</span><span class="cp">&gt;</span><span class="x"></span>
+<span class="cp">&lt;/%</span><span class="nb">text</span><span class="cp">&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="exiting-early-from-a-template">
+<span id="syntax-exiting-early"></span><h2>Exiting Early from a Template<a class="headerlink" href="#exiting-early-from-a-template" title="Permalink to this headline">¶</a></h2>
+<p>Sometimes you want to stop processing a template or <code class="docutils literal"><span class="pre">&lt;%def&gt;</span></code>
+method in the middle and just use the text you&#8217;ve accumulated so
+far.  This is accomplished by using <code class="docutils literal"><span class="pre">return</span></code> statement inside
+a Python block.   It&#8217;s a good idea for the <code class="docutils literal"><span class="pre">return</span></code> statement
+to return an empty string, which prevents the Python default return
+value of <code class="docutils literal"><span class="pre">None</span></code> from being rendered by the template.  This
+return value is for semantic purposes provided in templates via
+the <code class="docutils literal"><span class="pre">STOP_RENDERING</span></code> symbol:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">%</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">len</span><span class="p">(</span><span class="n">records</span><span class="p">):</span><span class="x"></span>
+<span class="x">    No records found.</span>
+<span class="x">    </span><span class="cp">&lt;%</span> <span class="k">return</span> <span class="n">STOP_RENDERING</span> <span class="cp">%&gt;</span>
+<span class="cp">%</span><span class="k"> endif</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Or perhaps:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span>
+    <span class="k">if</span> <span class="ow">not</span> <span class="nb">len</span><span class="p">(</span><span class="n">records</span><span class="p">):</span>
+        <span class="k">return</span> <span class="n">STOP_RENDERING</span>
+<span class="cp">%&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<p>In older versions of Mako, an empty string can be substituted for
+the <code class="docutils literal"><span class="pre">STOP_RENDERING</span></code> symbol:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">&lt;%</span> <span class="k">return</span> <span class="s1">&#39;&#39;</span> <span class="cp">%&gt;</span><span class="x"></span>
+</pre></div>
+</div>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 1.0.2: </span>- added the <code class="docutils literal"><span class="pre">STOP_RENDERING</span></code> symbol which serves
+as a semantic identifier for the empty string <code class="docutils literal"><span class="pre">&quot;&quot;</span></code> used by a
+Python <code class="docutils literal"><span class="pre">return</span></code> statement.</p>
+</div>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="usage.html" title="previous chapter">Usage</a>
+        Next:
+        <a href="defs.html" title="next chapter">Defs and Blocks</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/unicode.html b/doc/unicode.html
new file mode 100644 (file)
index 0000000..3a1b0d6
--- /dev/null
@@ -0,0 +1,485 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                The Unicode Chapter
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Caching" href="caching.html" />
+        <link rel="prev" title="Filtering and Buffering" href="filtering.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="filtering.html" title="previous chapter">Filtering and Buffering</a>
+            </li>
+            <li>Next:
+            <a href="caching.html" title="next chapter">Caching</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/unicode.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                The Unicode Chapter
+            
+
+        <h2>
+            
+                The Unicode Chapter
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">The Unicode Chapter</a><ul>
+<li><a class="reference internal" href="#specifying-the-encoding-of-a-template-file">Specifying the Encoding of a Template File</a></li>
+<li><a class="reference internal" href="#handling-expressions">Handling Expressions</a></li>
+<li><a class="reference internal" href="#defining-output-encoding">Defining Output Encoding</a><ul>
+<li><a class="reference internal" href="#buffer-selection">Buffer Selection</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#saying-to-heck-with-it-disabling-the-usage-of-unicode-entirely">Saying to Heck with It: Disabling the Usage of Unicode Entirely</a><ul>
+<li><a class="reference internal" href="#rules-for-using-disable-unicode-true">Rules for using <code class="docutils literal"><span class="pre">disable_unicode=True</span></code></a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="filtering.html" title="previous chapter">Filtering and Buffering</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="caching.html" title="next chapter">Caching</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="the-unicode-chapter">
+<span id="unicode-toplevel"></span><h1>The Unicode Chapter<a class="headerlink" href="#the-unicode-chapter" title="Permalink to this headline">¶</a></h1>
+<p>The Python language supports two ways of representing what we
+know as &#8220;strings&#8221;, i.e. series of characters. In Python 2, the
+two types are <code class="docutils literal"><span class="pre">string</span></code> and <code class="docutils literal"><span class="pre">unicode</span></code>, and in Python 3 they are
+<code class="docutils literal"><span class="pre">bytes</span></code> and <code class="docutils literal"><span class="pre">string</span></code>. A key aspect of the Python 2 <code class="docutils literal"><span class="pre">string</span></code> and
+Python 3 <code class="docutils literal"><span class="pre">bytes</span></code> types are that they contain no information
+regarding what <strong>encoding</strong> the data is stored in. For this
+reason they were commonly referred to as <strong>byte strings</strong> on
+Python 2, and Python 3 makes this name more explicit. The
+origins of this come from Python&#8217;s background of being developed
+before the Unicode standard was even available, back when
+strings were C-style strings and were just that, a series of
+bytes. Strings that had only values below 128 just happened to
+be <strong>ASCII</strong> strings and were printable on the console, whereas
+strings with values above 128 would produce all kinds of
+graphical characters and bells.</p>
+<p>Contrast the &#8220;byte-string&#8221; type with the &#8220;unicode/string&#8221; type.
+Objects of this latter type are created whenever you say something like
+<code class="docutils literal"><span class="pre">u&quot;hello</span> <span class="pre">world&quot;</span></code> (or in Python 3, just <code class="docutils literal"><span class="pre">&quot;hello</span> <span class="pre">world&quot;</span></code>). In this
+case, Python represents each character in the string internally
+using multiple bytes per character (something similar to
+UTF-16). What&#8217;s important is that when using the
+<code class="docutils literal"><span class="pre">unicode</span></code>/<code class="docutils literal"><span class="pre">string</span></code> type to store strings, Python knows the
+data&#8217;s encoding; it&#8217;s in its own internal format. Whereas when
+using the <code class="docutils literal"><span class="pre">string</span></code>/<code class="docutils literal"><span class="pre">bytes</span></code> type, it does not.</p>
+<p>When Python 2 attempts to treat a byte-string as a string, which
+means it&#8217;s attempting to compare/parse its characters, to coerce
+it into another encoding, or to decode it to a unicode object,
+it has to guess what the encoding is. In this case, it will
+pretty much always guess the encoding as <code class="docutils literal"><span class="pre">ascii</span></code>... and if the
+byte-string contains bytes above value 128, you&#8217;ll get an error.
+Python 3 eliminates much of this confusion by just raising an
+error unconditionally if a byte-string is used in a
+character-aware context.</p>
+<p>There is one operation that Python <em>can</em> do with a non-ASCII
+byte-string, and it&#8217;s a great source of confusion: it can dump the
+byte-string straight out to a stream or a file, with nary a care
+what the encoding is. To Python, this is pretty much like
+dumping any other kind of binary data (like an image) to a
+stream somewhere. In Python 2, it is common to see programs that
+embed all kinds of international characters and encodings into
+plain byte-strings (i.e. using <code class="docutils literal"><span class="pre">&quot;hello</span> <span class="pre">world&quot;</span></code> style literals)
+can fly right through their run, sending reams of strings out to
+wherever they are going, and the programmer, seeing the same
+output as was expressed in the input, is now under the illusion
+that his or her program is Unicode-compliant. In fact, their
+program has no unicode awareness whatsoever, and similarly has
+no ability to interact with libraries that <em>are</em> unicode aware.
+Python 3 makes this much less likely by defaulting to unicode as
+the storage format for strings.</p>
+<p>The &#8220;pass through encoded data&#8221; scheme is what template
+languages like Cheetah and earlier versions of Myghty do by
+default. Mako as of version 0.2 also supports this mode of
+operation when using Python 2, using the <code class="docutils literal"><span class="pre">disable_unicode=True</span></code>
+flag. However, when using Mako in its default mode of
+unicode-aware, it requires explicitness when dealing with
+non-ASCII encodings. Additionally, if you ever need to handle
+unicode strings and other kinds of encoding conversions more
+intelligently, the usage of raw byte-strings quickly becomes a
+nightmare, since you are sending the Python interpreter
+collections of bytes for which it can make no intelligent
+decisions with regards to encoding. In Python 3 Mako only allows
+usage of native, unicode strings.</p>
+<p>In normal Mako operation, all parsed template constructs and
+output streams are handled internally as Python <code class="docutils literal"><span class="pre">unicode</span></code>
+objects. It&#8217;s only at the point of <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> that this unicode
+stream may be rendered into whatever the desired output encoding
+is. The implication here is that the template developer must
+:ensure that <a class="reference internal" href="#set-template-file-encoding"><span class="std std-ref">the encoding of all non-ASCII templates is explicit</span></a> (still required in Python 3),
+that <a class="reference internal" href="#handling-non-ascii-expressions"><span class="std std-ref">all non-ASCII-encoded expressions are in one way or another
+converted to unicode</span></a>
+(not much of a burden in Python 3), and that <a class="reference internal" href="#defining-output-encoding"><span class="std std-ref">the output stream of the
+template is handled as a unicode stream being encoded to some
+encoding</span></a> (still required in Python 3).</p>
+<div class="section" id="specifying-the-encoding-of-a-template-file">
+<span id="set-template-file-encoding"></span><h2>Specifying the Encoding of a Template File<a class="headerlink" href="#specifying-the-encoding-of-a-template-file" title="Permalink to this headline">¶</a></h2>
+<p>This is the most basic encoding-related setting, and it is
+equivalent to Python&#8217;s &#8220;magic encoding comment&#8221;, as described in
+<a class="reference external" href="http://www.python.org/dev/peps/pep-0263/">pep-0263</a>. Any
+template that contains non-ASCII characters requires that this
+comment be present so that Mako can decode to unicode (and also
+make usage of Python&#8217;s AST parsing services). Mako&#8217;s lexer will
+use this encoding in order to convert the template source into a
+<code class="docutils literal"><span class="pre">unicode</span></code> object before continuing its parsing:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">## -*- coding: utf-8 -*-</span><span class="x"></span>
+
+<span class="x">Alors vous imaginez ma surprise, au lever du jour, quand</span>
+<span class="x">une drôle de petite voix m’a réveillé. Elle disait:</span>
+<span class="x"> « S’il vous plaît… dessine-moi un mouton! »</span>
+</pre></div>
+</div>
+<p>For the picky, the regular expression used is derived from that
+of the above mentioned pep:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1">#.*coding[:=]\s*([-\w.]+).*\n</span>
+</pre></div>
+</div>
+<p>The lexer will convert to unicode in all cases, so that if any
+characters exist in the template that are outside of the
+specified encoding (or the default of <code class="docutils literal"><span class="pre">ascii</span></code>), the error will
+be immediate.</p>
+<p>As an alternative, the template encoding can be specified
+programmatically to either <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> via
+the <code class="docutils literal"><span class="pre">input_encoding</span></code> parameter:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;./&#39;</span><span class="p">],</span> <span class="n">input_encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The above will assume all located templates specify <code class="docutils literal"><span class="pre">utf-8</span></code>
+encoding, unless the template itself contains its own magic
+encoding comment, which takes precedence.</p>
+</div>
+<div class="section" id="handling-expressions">
+<span id="handling-non-ascii-expressions"></span><h2>Handling Expressions<a class="headerlink" href="#handling-expressions" title="Permalink to this headline">¶</a></h2>
+<p>The next area that encoding comes into play is in expression
+constructs. By default, Mako&#8217;s treatment of an expression like
+this:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot;hello world&quot;</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>looks something like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">unicode</span><span class="p">(</span><span class="s2">&quot;hello world&quot;</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>In Python 3, it&#8217;s just:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="s2">&quot;hello world&quot;</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>That is, <strong>the output of all expressions is run through the
+``unicode`` built-in</strong>. This is the default setting, and can be
+modified to expect various encodings. The <code class="docutils literal"><span class="pre">unicode</span></code> step serves
+both the purpose of rendering non-string expressions into
+strings (such as integers or objects which contain <code class="docutils literal"><span class="pre">__str()__</span></code>
+methods), and to ensure that the final output stream is
+constructed as a unicode object. The main implication of this is
+that <strong>any raw byte-strings that contain an encoding other than
+ASCII must first be decoded to a Python unicode object</strong>. It
+means you can&#8217;t say this in Python 2:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">&quot;voix m’a réveillé.&quot;</span><span class="cp">}</span>  <span class="cp">## error in Python 2!</span><span class="x"></span>
+</pre></div>
+</div>
+<p>You must instead say this:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="s2">u&quot;voix m’a réveillé.&quot;</span><span class="cp">}</span>  <span class="cp">## OK !</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Similarly, if you are reading data from a file that is streaming
+bytes, or returning data from some object that is returning a
+Python byte-string containing a non-ASCII encoding, you have to
+explicitly decode to unicode first, such as:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="cp">${</span><span class="n">call_my_object</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+</pre></div>
+</div>
+<p>Note that filehandles acquired by <code class="docutils literal"><span class="pre">open()</span></code> in Python 3 default
+to returning &#8220;text&#8221;, that is the decoding is done for you. See
+Python 3&#8217;s documentation for the <code class="docutils literal"><span class="pre">open()</span></code> built-in for details on
+this.</p>
+<p>If you want a certain encoding applied to <em>all</em> expressions,
+override the <code class="docutils literal"><span class="pre">unicode</span></code> builtin with the <code class="docutils literal"><span class="pre">decode</span></code> built-in at the
+<a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> or <a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> level:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="n">templatetext</span><span class="p">,</span> <span class="n">default_filters</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;decode.utf8&#39;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>Note that the built-in <code class="docutils literal"><span class="pre">decode</span></code> object is slower than the
+<code class="docutils literal"><span class="pre">unicode</span></code> function, since unlike <code class="docutils literal"><span class="pre">unicode</span></code> it&#8217;s not a Python
+built-in, and it also checks the type of the incoming data to
+determine if string conversion is needed first.</p>
+<p>The <code class="docutils literal"><span class="pre">default_filters</span></code> argument can be used to entirely customize
+the filtering process of expressions. This argument is described
+in <a class="reference internal" href="filtering.html#filtering-default-filters"><span class="std std-ref">The default_filters Argument</span></a>.</p>
+</div>
+<div class="section" id="defining-output-encoding">
+<span id="id1"></span><h2>Defining Output Encoding<a class="headerlink" href="#defining-output-encoding" title="Permalink to this headline">¶</a></h2>
+<p>Now that we have a template which produces a pure unicode output
+stream, all the hard work is done. We can take the output and do
+anything with it.</p>
+<p>As stated in the <a class="reference internal" href="usage.html"><span class="doc">&#8220;Usage&#8221; chapter</span></a>, both <a class="reference internal" href="usage.html#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> and
+<a class="reference internal" href="usage.html#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> accept <code class="docutils literal"><span class="pre">output_encoding</span></code> and <code class="docutils literal"><span class="pre">encoding_errors</span></code>
+parameters which can be used to encode the output in any Python
+supported codec:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="kn">from</span> <span class="nn">mako.lookup</span> <span class="kn">import</span> <span class="n">TemplateLookup</span>
+
+<span class="n">mylookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">],</span> <span class="n">output_encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="n">encoding_errors</span><span class="o">=</span><span class="s1">&#39;replace&#39;</span><span class="p">)</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">mylookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s2">&quot;foo.txt&quot;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p><a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> will return a <code class="docutils literal"><span class="pre">bytes</span></code> object in Python 3 if an output
+encoding is specified. By default it performs no encoding and
+returns a native string.</p>
+<p><a class="reference internal" href="usage.html#mako.template.Template.render_unicode" title="mako.template.Template.render_unicode"><code class="xref py py-meth docutils literal"><span class="pre">render_unicode()</span></code></a> will return the template output as a Python
+<code class="docutils literal"><span class="pre">unicode</span></code> object (or <code class="docutils literal"><span class="pre">string</span></code> in Python 3):</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render_unicode</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>The above method disgards the output encoding keyword argument;
+you can encode yourself by saying:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render_unicode</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="s1">&#39;replace&#39;</span><span class="p">))</span>
+</pre></div>
+</div>
+<div class="section" id="buffer-selection">
+<h3>Buffer Selection<a class="headerlink" href="#buffer-selection" title="Permalink to this headline">¶</a></h3>
+<p>Mako does play some games with the style of buffering used
+internally, to maximize performance. Since the buffer is by far
+the most heavily used object in a render operation, it&#8217;s
+important!</p>
+<p>When calling <a class="reference internal" href="usage.html#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> on a template that does not specify any
+output encoding (i.e. it&#8217;s <code class="docutils literal"><span class="pre">ascii</span></code>), Python&#8217;s <code class="docutils literal"><span class="pre">cStringIO</span></code> module,
+which cannot handle encoding of non-ASCII <code class="docutils literal"><span class="pre">unicode</span></code> objects
+(even though it can send raw byte-strings through), is used for
+buffering. Otherwise, a custom Mako class called
+<code class="docutils literal"><span class="pre">FastEncodingBuffer</span></code> is used, which essentially is a super
+dumbed-down version of <code class="docutils literal"><span class="pre">StringIO</span></code> that gathers all strings into
+a list and uses <code class="docutils literal"><span class="pre">u''.join(elements)</span></code> to produce the final output
+&#8211; it&#8217;s markedly faster than <code class="docutils literal"><span class="pre">StringIO</span></code>.</p>
+</div>
+</div>
+<div class="section" id="saying-to-heck-with-it-disabling-the-usage-of-unicode-entirely">
+<span id="unicode-disabled"></span><h2>Saying to Heck with It: Disabling the Usage of Unicode Entirely<a class="headerlink" href="#saying-to-heck-with-it-disabling-the-usage-of-unicode-entirely" title="Permalink to this headline">¶</a></h2>
+<p>Some segments of Mako&#8217;s userbase choose to make no usage of
+Unicode whatsoever, and instead would prefer the &#8220;pass through&#8221;
+approach; all string expressions in their templates return
+encoded byte-strings, and they would like these strings to pass
+right through. The only advantage to this approach is that
+templates need not use <code class="docutils literal"><span class="pre">u&quot;&quot;</span></code> for literal strings; there&#8217;s an
+arguable speed improvement as well since raw byte-strings
+generally perform slightly faster than unicode objects in
+Python. For these users, assuming they&#8217;re sticking with Python
+2, they can hit the <code class="docutils literal"><span class="pre">disable_unicode=True</span></code> flag as so:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># -*- coding:utf-8 -*-</span>
+<span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">t</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;drôle de petite voix m’a réveillé.&quot;</span><span class="p">,</span> <span class="n">disable_unicode</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">input_encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">code</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The <code class="docutils literal"><span class="pre">disable_unicode</span></code> mode is strictly a Python 2 thing. It is
+not supported at all in Python 3.</p>
+<p>The generated module source code will contain elements like
+these:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># -*- coding:utf-8 -*-</span>
+<span class="c1">#  ...more generated code ...</span>
+
+<span class="k">def</span> <span class="nf">render_body</span><span class="p">(</span><span class="n">context</span><span class="p">,</span><span class="o">**</span><span class="n">pageargs</span><span class="p">):</span>
+    <span class="n">context</span><span class="o">.</span><span class="n">caller_stack</span><span class="o">.</span><span class="n">push_frame</span><span class="p">()</span>
+    <span class="k">try</span><span class="p">:</span>
+        <span class="n">__M_locals</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">pageargs</span><span class="o">=</span><span class="n">pageargs</span><span class="p">)</span>
+        <span class="c1"># SOURCE LINE 1</span>
+        <span class="n">context</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">&#39;dr</span><span class="se">\xc3\xb4</span><span class="s1">le de petite voix m</span><span class="se">\xe2\x80\x99</span><span class="s1">a r</span><span class="se">\xc3\xa9</span><span class="s1">veill</span><span class="se">\xc3\xa9</span><span class="s1">.&#39;</span><span class="p">)</span>
+        <span class="k">return</span> <span class="s1">&#39;&#39;</span>
+    <span class="k">finally</span><span class="p">:</span>
+        <span class="n">context</span><span class="o">.</span><span class="n">caller_stack</span><span class="o">.</span><span class="n">pop_frame</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>Where above that the string literal used within <a class="reference internal" href="runtime.html#mako.runtime.Context.write" title="mako.runtime.Context.write"><code class="xref py py-meth docutils literal"><span class="pre">Context.write()</span></code></a>
+is a regular byte-string.</p>
+<p>When <code class="docutils literal"><span class="pre">disable_unicode=True</span></code> is turned on, the <code class="docutils literal"><span class="pre">default_filters</span></code>
+argument which normally defaults to <code class="docutils literal"><span class="pre">[&quot;unicode&quot;]</span></code> now defaults
+to <code class="docutils literal"><span class="pre">[&quot;str&quot;]</span></code> instead. Setting <code class="docutils literal"><span class="pre">default_filters</span></code> to the empty list
+<code class="docutils literal"><span class="pre">[]</span></code> can remove the overhead of the <code class="docutils literal"><span class="pre">str</span></code> call. Also, in this
+mode you <strong>cannot</strong> safely call <a class="reference internal" href="usage.html#mako.template.Template.render_unicode" title="mako.template.Template.render_unicode"><code class="xref py py-meth docutils literal"><span class="pre">render_unicode()</span></code></a> &#8211; you&#8217;ll get
+unicode/decode errors.</p>
+<p>The <code class="docutils literal"><span class="pre">h</span></code> filter (HTML escape) uses a less performant pure Python
+escape function in non-unicode mode. This because
+MarkupSafe only supports Python unicode objects for non-ASCII
+strings.</p>
+<div class="versionchanged">
+<p><span class="versionmodified">Changed in version 0.3.4: </span>In prior versions, it used <code class="docutils literal"><span class="pre">cgi.escape()</span></code>, which has been replaced
+with a function that also escapes single quotes.</p>
+</div>
+<div class="section" id="rules-for-using-disable-unicode-true">
+<h3>Rules for using <code class="docutils literal"><span class="pre">disable_unicode=True</span></code><a class="headerlink" href="#rules-for-using-disable-unicode-true" title="Permalink to this headline">¶</a></h3>
+<ul class="simple">
+<li>Don&#8217;t use this mode unless you really, really want to and you
+absolutely understand what you&#8217;re doing.</li>
+<li>Don&#8217;t use this option just because you don&#8217;t want to learn to
+use Unicode properly; we aren&#8217;t supporting user issues in this
+mode of operation. We will however offer generous help for the
+vast majority of users who stick to the Unicode program.</li>
+<li>Python 3 is unicode by default, and the flag is not available
+when running on Python 3.</li>
+</ul>
+</div>
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="filtering.html" title="previous chapter">Filtering and Buffering</a>
+        Next:
+        <a href="caching.html" title="next chapter">Caching</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/usage.html b/doc/usage.html
new file mode 100644 (file)
index 0000000..1da7587
--- /dev/null
@@ -0,0 +1,1113 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
+<head>
+<title>
+    
+                Usage
+             &mdash;
+    Mako 1.0.6 Documentation
+</title>
+
+<!-- begin iterate through sphinx environment css_files -->
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/docs.css" type="text/css" />
+    <link rel="stylesheet" href="_static/site.css" type="text/css" />
+    <link rel="stylesheet" href="_static/changelog.css" type="text/css" />
+    <link rel="stylesheet" href="_static/sphinx_paramlinks.css" type="text/css" />
+<!-- end iterate through sphinx environment css_files -->
+
+
+    
+
+
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+          URL_ROOT:    './',
+          VERSION:     '1.0.6',
+          COLLAPSE_MODINDEX: false,
+          FILE_SUFFIX: '.html'
+      };
+    </script>
+        <script type="text/javascript" src="_static/jquery.js"></script>
+        <script type="text/javascript" src="_static/underscore.js"></script>
+        <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="index" title="Index" href="genindex.html" />
+    <link rel="search" title="Search" href="search.html" />
+    <link rel="top" title="Mako 1.0.6 Documentation" href="index.html" />
+        <link rel="next" title="Syntax" href="syntax.html" />
+        <link rel="prev" title="Table of Contents" href="index.html" />
+
+
+
+</head>
+<body>
+    <div id="wrap">
+    <div class="rightbar">
+
+    <div class="slogan">
+    Hyperfast and lightweight templating for the Python platform.
+    </div>
+
+
+    </div>
+
+    <a href="http://www.makotemplates.org/"><img src="_static/makoLogo.png" /></a>
+
+    <hr/>
+
+    
+
+
+
+
+
+
+
+
+
+
+<div id="docs-container">
+
+
+
+<div id="docs-header">
+    <h1>Mako 1.0.6 Documentation</h1>
+
+    <div id="docs-search">
+    Search:
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </div>
+
+    <div id="docs-version-header">
+        Release: <span class="version-num">1.0.6</span>
+
+    </div>
+
+</div>
+
+<div id="docs-top-navigation">
+    <div id="docs-top-page-control" class="docs-navigation-links">
+        <ul>
+            <li>Prev:
+            <a href="index.html" title="previous chapter">Table of Contents</a>
+            </li>
+            <li>Next:
+            <a href="syntax.html" title="next chapter">Syntax</a>
+            </li>
+
+        <li>
+            <a href="index.html">Table of Contents</a> |
+            <a href="genindex.html">Index</a>
+            | <a href="_sources/usage.txt">view source
+        </li>
+        </ul>
+    </div>
+
+    <div id="docs-navigation-banner">
+        <a href="index.html">Mako 1.0.6 Documentation</a>
+        » 
+                Usage
+            
+
+        <h2>
+            
+                Usage
+            
+        </h2>
+    </div>
+
+</div>
+
+<div id="docs-body-container">
+
+    <div id="docs-sidebar">
+    <h3><a href="index.html">Table of Contents</a></h3>
+    <ul>
+<li><a class="reference internal" href="#">Usage</a><ul>
+<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
+<li><a class="reference internal" href="#using-file-based-templates">Using File-Based Templates</a></li>
+<li><a class="reference internal" href="#using-templatelookup">Using <code class="docutils literal"><span class="pre">TemplateLookup</span></code></a><ul>
+<li><a class="reference internal" href="#setting-the-collection-size">Setting the Collection Size</a></li>
+<li><a class="reference internal" href="#setting-filesystem-checks">Setting Filesystem Checks</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#using-unicode-and-encoding">Using Unicode and Encoding</a></li>
+<li><a class="reference internal" href="#handling-exceptions">Handling Exceptions</a></li>
+<li><a class="reference internal" href="#common-framework-integrations">Common Framework Integrations</a><ul>
+<li><a class="reference internal" href="#wsgi">WSGI</a></li>
+<li><a class="reference internal" href="#pygments">Pygments</a></li>
+<li><a class="reference internal" href="#babel">Babel</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#api-reference">API Reference</a></li>
+</ul>
+</li>
+</ul>
+
+
+    <h4>Previous Topic</h4>
+    <p>
+    <a href="index.html" title="previous chapter">Table of Contents</a>
+    </p>
+    <h4>Next Topic</h4>
+    <p>
+    <a href="syntax.html" title="next chapter">Syntax</a>
+    </p>
+
+    <h4>Quick Search</h4>
+    <p>
+    <form class="search" action="search.html" method="get">
+      <input type="text" name="q" size="18" /> <input type="submit" value="Search" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+    </p>
+
+    </div>
+
+    <div id="docs-body" class="withsidebar" >
+        
+<div class="section" id="usage">
+<span id="usage-toplevel"></span><h1>Usage<a class="headerlink" href="#usage" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="basic-usage">
+<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline">¶</a></h2>
+<p>This section describes the Python API for Mako templates. If you
+are using Mako within a web framework such as Pylons, the work
+of integrating Mako&#8217;s API is already done for you, in which case
+you can skip to the next section, <a class="reference internal" href="syntax.html"><span class="std std-ref">Syntax</span></a>.</p>
+<p>The most basic way to create a template and render it is through
+the <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> class:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;hello world!&quot;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>Above, the text argument to <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> is <strong>compiled</strong> into a
+Python module representation. This module contains a function
+called <code class="docutils literal"><span class="pre">render_body()</span></code>, which produces the output of the
+template. When <code class="docutils literal"><span class="pre">mytemplate.render()</span></code> is called, Mako sets up a
+runtime environment for the template and calls the
+<code class="docutils literal"><span class="pre">render_body()</span></code> function, capturing the output into a buffer and
+returning its string contents.</p>
+<p>The code inside the <code class="docutils literal"><span class="pre">render_body()</span></code> function has access to a
+namespace of variables. You can specify these variables by
+sending them as additional keyword arguments to the <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a>
+method:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;hello, ${name}!&quot;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;jack&quot;</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>The <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> method calls upon Mako to create a
+<a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object, which stores all the variable names accessible
+to the template and also stores a buffer used to capture output.
+You can create this <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> yourself and have the template
+render with it, using the <a class="reference internal" href="#mako.template.Template.render_context" title="mako.template.Template.render_context"><code class="xref py py-meth docutils literal"><span class="pre">render_context()</span></code></a> method:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="kn">from</span> <span class="nn">mako.runtime</span> <span class="kn">import</span> <span class="n">Context</span>
+<span class="kn">from</span> <span class="nn">StringIO</span> <span class="kn">import</span> <span class="n">StringIO</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;hello, ${name}!&quot;</span><span class="p">)</span>
+<span class="n">buf</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">()</span>
+<span class="n">ctx</span> <span class="o">=</span> <span class="n">Context</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;jack&quot;</span><span class="p">)</span>
+<span class="n">mytemplate</span><span class="o">.</span><span class="n">render_context</span><span class="p">(</span><span class="n">ctx</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">buf</span><span class="o">.</span><span class="n">getvalue</span><span class="p">())</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="using-file-based-templates">
+<h2>Using File-Based Templates<a class="headerlink" href="#using-file-based-templates" title="Permalink to this headline">¶</a></h2>
+<p>A <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> can also load its template source code from a file,
+using the <code class="docutils literal"><span class="pre">filename</span></code> keyword argument:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;/docs/mytmpl.txt&#39;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>For improved performance, a <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> which is loaded from a
+file can also cache the source code to its generated module on
+the filesystem as a regular Python module file (i.e. a <code class="docutils literal"><span class="pre">.py</span></code>
+file). To do this, just add the <code class="docutils literal"><span class="pre">module_directory</span></code> argument to
+the template:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">&#39;/docs/mytmpl.txt&#39;</span><span class="p">,</span> <span class="n">module_directory</span><span class="o">=</span><span class="s1">&#39;/tmp/mako_modules&#39;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>When the above code is rendered, a file
+<code class="docutils literal"><span class="pre">/tmp/mako_modules/docs/mytmpl.txt.py</span></code> is created containing the
+source code for the module. The next time a <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> with the
+same arguments is created, this module file will be
+automatically re-used.</p>
+</div>
+<div class="section" id="using-templatelookup">
+<span id="usage-templatelookup"></span><h2>Using <code class="docutils literal"><span class="pre">TemplateLookup</span></code><a class="headerlink" href="#using-templatelookup" title="Permalink to this headline">¶</a></h2>
+<p>All of the examples thus far have dealt with the usage of a
+single <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object. If the code within those templates
+tries to locate another template resource, it will need some way
+to find them, using simple URI strings. For this need, the
+resolution of other templates from within a template is
+accomplished by the <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> class. This class is
+constructed given a list of directories in which to search for
+templates, as well as keyword arguments that will be passed to
+the <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> objects it creates:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="kn">from</span> <span class="nn">mako.lookup</span> <span class="kn">import</span> <span class="n">TemplateLookup</span>
+
+<span class="n">mylookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">])</span>
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;&lt;</span><span class="si">%i</span><span class="s2">nclude file=&quot;header.txt&quot;/&gt; hello world!&quot;&quot;&quot;</span><span class="p">,</span> <span class="n">lookup</span><span class="o">=</span><span class="n">mylookup</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Above, we created a textual template which includes the file
+<code class="docutils literal"><span class="pre">&quot;header.txt&quot;</span></code>. In order for it to have somewhere to look for
+<code class="docutils literal"><span class="pre">&quot;header.txt&quot;</span></code>, we passed a <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> object to it, which
+will search in the directory <code class="docutils literal"><span class="pre">/docs</span></code> for the file <code class="docutils literal"><span class="pre">&quot;header.txt&quot;</span></code>.</p>
+<p>Usually, an application will store most or all of its templates
+as text files on the filesystem. So far, all of our examples
+have been a little bit contrived in order to illustrate the
+basic concepts. But a real application would get most or all of
+its templates directly from the <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, using the
+aptly named <a class="reference internal" href="#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">get_template()</span></code></a> method, which accepts the URI of the
+desired template:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="kn">from</span> <span class="nn">mako.lookup</span> <span class="kn">import</span> <span class="n">TemplateLookup</span>
+
+<span class="n">mylookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">],</span> <span class="n">module_directory</span><span class="o">=</span><span class="s1">&#39;/tmp/mako_modules&#39;</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">serve_template</span><span class="p">(</span><span class="n">templatename</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
+    <span class="n">mytemplate</span> <span class="o">=</span> <span class="n">mylookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="n">templatename</span><span class="p">)</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>In the example above, we create a <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> which will
+look for templates in the <code class="docutils literal"><span class="pre">/docs</span></code> directory, and will store
+generated module files in the <code class="docutils literal"><span class="pre">/tmp/mako_modules</span></code> directory. The
+lookup locates templates by appending the given URI to each of
+its search directories; so if you gave it a URI of
+<code class="docutils literal"><span class="pre">/etc/beans/info.txt</span></code>, it would search for the file
+<code class="docutils literal"><span class="pre">/docs/etc/beans/info.txt</span></code>, else raise a <code class="xref py py-class docutils literal"><span class="pre">TopLevelNotFound</span></code>
+exception, which is a custom Mako exception.</p>
+<p>When the lookup locates templates, it will also assign a <code class="docutils literal"><span class="pre">uri</span></code>
+property to the <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> which is the URI passed to the
+<a class="reference internal" href="#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">get_template()</span></code></a> call. <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> uses this URI to calculate the
+name of its module file. So in the above example, a
+<code class="docutils literal"><span class="pre">templatename</span></code> argument of <code class="docutils literal"><span class="pre">/etc/beans/info.txt</span></code> will create a
+module file <code class="docutils literal"><span class="pre">/tmp/mako_modules/etc/beans/info.txt.py</span></code>.</p>
+<div class="section" id="setting-the-collection-size">
+<h3>Setting the Collection Size<a class="headerlink" href="#setting-the-collection-size" title="Permalink to this headline">¶</a></h3>
+<p>The <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> also serves the important need of caching a
+fixed set of templates in memory at a given time, so that
+successive URI lookups do not result in full template
+compilations and/or module reloads on each request. By default,
+the <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> size is unbounded. You can specify a fixed
+size using the <code class="docutils literal"><span class="pre">collection_size</span></code> argument:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">mylookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">],</span>
+                <span class="n">module_directory</span><span class="o">=</span><span class="s1">&#39;/tmp/mako_modules&#39;</span><span class="p">,</span> <span class="n">collection_size</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The above lookup will continue to load templates into memory
+until it reaches a count of around 500. At that point, it will
+clean out a certain percentage of templates using a least
+recently used scheme.</p>
+</div>
+<div class="section" id="setting-filesystem-checks">
+<h3>Setting Filesystem Checks<a class="headerlink" href="#setting-filesystem-checks" title="Permalink to this headline">¶</a></h3>
+<p>Another important flag on <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> is
+<code class="docutils literal"><span class="pre">filesystem_checks</span></code>. This defaults to <code class="docutils literal"><span class="pre">True</span></code>, and says that each
+time a template is returned by the <a class="reference internal" href="#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">get_template()</span></code></a> method, the
+revision time of the original template file is checked against
+the last time the template was loaded, and if the file is newer
+will reload its contents and recompile the template. On a
+production system, setting <code class="docutils literal"><span class="pre">filesystem_checks</span></code> to <code class="docutils literal"><span class="pre">False</span></code> can
+afford a small to moderate performance increase (depending on
+the type of filesystem used).</p>
+</div>
+</div>
+<div class="section" id="using-unicode-and-encoding">
+<span id="usage-unicode"></span><h2>Using Unicode and Encoding<a class="headerlink" href="#using-unicode-and-encoding" title="Permalink to this headline">¶</a></h2>
+<p>Both <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> and <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> accept <code class="docutils literal"><span class="pre">output_encoding</span></code>
+and <code class="docutils literal"><span class="pre">encoding_errors</span></code> parameters which can be used to encode the
+output in any Python supported codec:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="kn">from</span> <span class="nn">mako.lookup</span> <span class="kn">import</span> <span class="n">TemplateLookup</span>
+
+<span class="n">mylookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">(</span><span class="n">directories</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;/docs&#39;</span><span class="p">],</span> <span class="n">output_encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="n">encoding_errors</span><span class="o">=</span><span class="s1">&#39;replace&#39;</span><span class="p">)</span>
+
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">mylookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s2">&quot;foo.txt&quot;</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>When using Python 3, the <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> method will return a <code class="docutils literal"><span class="pre">bytes</span></code>
+object, <strong>if</strong> <code class="docutils literal"><span class="pre">output_encoding</span></code> is set. Otherwise it returns a
+<code class="docutils literal"><span class="pre">string</span></code>.</p>
+<p>Additionally, the <a class="reference internal" href="#mako.template.Template.render_unicode" title="mako.template.Template.render_unicode"><code class="xref py py-meth docutils literal"><span class="pre">render_unicode()</span></code></a> method exists which will
+return the template output as a Python <code class="docutils literal"><span class="pre">unicode</span></code> object, or in
+Python 3 a <code class="docutils literal"><span class="pre">string</span></code>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render_unicode</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>The above method disregards the output encoding keyword
+argument; you can encode yourself by saying:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">print</span><span class="p">(</span><span class="n">mytemplate</span><span class="o">.</span><span class="n">render_unicode</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="s1">&#39;replace&#39;</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>Note that Mako&#8217;s ability to return data in any encoding and/or
+<code class="docutils literal"><span class="pre">unicode</span></code> implies that the underlying output stream of the
+template is a Python unicode object. This behavior is described
+fully in <a class="reference internal" href="unicode.html"><span class="std std-ref">The Unicode Chapter</span></a>.</p>
+</div>
+<div class="section" id="handling-exceptions">
+<span id="id1"></span><h2>Handling Exceptions<a class="headerlink" href="#handling-exceptions" title="Permalink to this headline">¶</a></h2>
+<p>Template exceptions can occur in two distinct places. One is
+when you <strong>lookup, parse and compile</strong> the template, the other
+is when you <strong>run</strong> the template. Within the running of a
+template, exceptions are thrown normally from whatever Python
+code originated the issue. Mako has its own set of exception
+classes which mostly apply to the lookup and lexer/compiler
+stages of template construction. Mako provides some library
+routines that can be used to help provide Mako-specific
+information about any exception&#8217;s stack trace, as well as
+formatting the exception within textual or HTML format. In all
+cases, the main value of these handlers is that of converting
+Python filenames, line numbers, and code samples into Mako
+template filenames, line numbers, and code samples. All lines
+within a stack trace which correspond to a Mako template module
+will be converted to be against the originating template file.</p>
+<p>To format exception traces, the <a class="reference internal" href="#mako.exceptions.text_error_template" title="mako.exceptions.text_error_template"><code class="xref py py-func docutils literal"><span class="pre">text_error_template()</span></code></a> and
+<a class="reference internal" href="#mako.exceptions.html_error_template" title="mako.exceptions.html_error_template"><code class="xref py py-func docutils literal"><span class="pre">html_error_template()</span></code></a> functions are provided. They make usage of
+<code class="docutils literal"><span class="pre">sys.exc_info()</span></code> to get at the most recently thrown exception.
+Usage of these handlers usually looks like:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako</span> <span class="kn">import</span> <span class="n">exceptions</span>
+
+<span class="k">try</span><span class="p">:</span>
+    <span class="n">template</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+<span class="k">except</span><span class="p">:</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">exceptions</span><span class="o">.</span><span class="n">text_error_template</span><span class="p">()</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>Or for the HTML render function:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako</span> <span class="kn">import</span> <span class="n">exceptions</span>
+
+<span class="k">try</span><span class="p">:</span>
+    <span class="n">template</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+<span class="k">except</span><span class="p">:</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">exceptions</span><span class="o">.</span><span class="n">html_error_template</span><span class="p">()</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>The <a class="reference internal" href="#mako.exceptions.html_error_template" title="mako.exceptions.html_error_template"><code class="xref py py-func docutils literal"><span class="pre">html_error_template()</span></code></a> template accepts two options:
+specifying <code class="docutils literal"><span class="pre">full=False</span></code> causes only a section of an HTML
+document to be rendered. Specifying <code class="docutils literal"><span class="pre">css=False</span></code> will disable the
+default stylesheet from being rendered.</p>
+<p>E.g.:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="k">print</span><span class="p">(</span><span class="n">exceptions</span><span class="o">.</span><span class="n">html_error_template</span><span class="p">()</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">full</span><span class="o">=</span><span class="bp">False</span><span class="p">))</span>
+</pre></div>
+</div>
+<p>The HTML render function is also available built-in to
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> using the <code class="docutils literal"><span class="pre">format_exceptions</span></code> flag. In this case, any
+exceptions raised within the <strong>render</strong> stage of the template
+will result in the output being substituted with the output of
+<a class="reference internal" href="#mako.exceptions.html_error_template" title="mako.exceptions.html_error_template"><code class="xref py py-func docutils literal"><span class="pre">html_error_template()</span></code></a>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">template</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">&quot;/foo/bar&quot;</span><span class="p">,</span> <span class="n">format_exceptions</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
+<span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+</pre></div>
+</div>
+<p>Note that the compile stage of the above template occurs when
+you construct the <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> itself, and no output stream is
+defined. Therefore exceptions which occur within the
+lookup/parse/compile stage will not be handled and will
+propagate normally. While the pre-render traceback usually will
+not include any Mako-specific lines anyway, it will mean that
+exceptions which occur previous to rendering and those which
+occur within rendering will be handled differently... so the
+<code class="docutils literal"><span class="pre">try</span></code>/<code class="docutils literal"><span class="pre">except</span></code> patterns described previously are probably of more
+general use.</p>
+<p>The underlying object used by the error template functions is
+the <a class="reference internal" href="#mako.exceptions.RichTraceback" title="mako.exceptions.RichTraceback"><code class="xref py py-class docutils literal"><span class="pre">RichTraceback</span></code></a> object. This object can also be used
+directly to provide custom error views. Here&#8217;s an example usage
+which describes its general API:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mako.exceptions</span> <span class="kn">import</span> <span class="n">RichTraceback</span>
+
+<span class="k">try</span><span class="p">:</span>
+    <span class="n">template</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
+    <span class="k">print</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">())</span>
+<span class="k">except</span><span class="p">:</span>
+    <span class="n">traceback</span> <span class="o">=</span> <span class="n">RichTraceback</span><span class="p">()</span>
+    <span class="k">for</span> <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">lineno</span><span class="p">,</span> <span class="n">function</span><span class="p">,</span> <span class="n">line</span><span class="p">)</span> <span class="ow">in</span> <span class="n">traceback</span><span class="o">.</span><span class="n">traceback</span><span class="p">:</span>
+        <span class="k">print</span><span class="p">(</span><span class="s2">&quot;File </span><span class="si">%s</span><span class="s2">, line </span><span class="si">%s</span><span class="s2">, in </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">lineno</span><span class="p">,</span> <span class="n">function</span><span class="p">))</span>
+        <span class="k">print</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
+    <span class="k">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">traceback</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">__class__</span><span class="o">.</span><span class="n">__name__</span><span class="p">),</span> <span class="n">traceback</span><span class="o">.</span><span class="n">error</span><span class="p">))</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="common-framework-integrations">
+<h2>Common Framework Integrations<a class="headerlink" href="#common-framework-integrations" title="Permalink to this headline">¶</a></h2>
+<p>The Mako distribution includes a little bit of helper code for
+the purpose of using Mako in some popular web framework
+scenarios. This is a brief description of what&#8217;s included.</p>
+<div class="section" id="wsgi">
+<h3>WSGI<a class="headerlink" href="#wsgi" title="Permalink to this headline">¶</a></h3>
+<p>A sample WSGI application is included in the distribution in the
+file <code class="docutils literal"><span class="pre">examples/wsgi/run_wsgi.py</span></code>. This runner is set up to pull
+files from a <cite>templates</cite> as well as an <cite>htdocs</cite> directory and
+includes a rudimental two-file layout. The WSGI runner acts as a
+fully functional standalone web server, using <code class="docutils literal"><span class="pre">wsgiutils</span></code> to run
+itself, and propagates GET and POST arguments from the request
+into the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a>, can serve images, CSS files and other kinds
+of files, and also displays errors using Mako&#8217;s included
+exception-handling utilities.</p>
+</div>
+<div class="section" id="pygments">
+<h3>Pygments<a class="headerlink" href="#pygments" title="Permalink to this headline">¶</a></h3>
+<p>A <a class="reference external" href="http://pygments.pocoo.org">Pygments</a>-compatible syntax
+highlighting module is included under <code class="xref py py-mod docutils literal"><span class="pre">mako.ext.pygmentplugin</span></code>.
+This module is used in the generation of Mako documentation and
+also contains various <cite>setuptools</cite> entry points under the heading
+<code class="docutils literal"><span class="pre">pygments.lexers</span></code>, including <code class="docutils literal"><span class="pre">mako</span></code>, <code class="docutils literal"><span class="pre">html+mako</span></code>, <code class="docutils literal"><span class="pre">xml+mako</span></code>
+(see the <code class="docutils literal"><span class="pre">setup.py</span></code> file for all the entry points).</p>
+</div>
+<div class="section" id="babel">
+<h3>Babel<a class="headerlink" href="#babel" title="Permalink to this headline">¶</a></h3>
+<p>Mako provides support for extracting <cite>gettext</cite> messages from
+templates via a <a class="reference external" href="http://babel.edgewall.org/">Babel</a> extractor
+entry point under <code class="docutils literal"><span class="pre">mako.ext.babelplugin</span></code>.</p>
+<p><cite>Gettext</cite> messages are extracted from all Python code sections,
+including those of control lines and expressions embedded
+in tags.</p>
+<p><a class="reference external" href="http://babel.edgewall.org/wiki/Documentation/messages.html#comments-tags-and-translator-comments-explanation">Translator
+comments</a>
+may also be extracted from Mako templates when a comment tag is
+specified to <a class="reference external" href="http://babel.edgewall.org/">Babel</a> (such as with
+the <code class="docutils literal"><span class="pre">-c</span></code> option).</p>
+<p>For example, a project <code class="docutils literal"><span class="pre">&quot;myproj&quot;</span></code> contains the following Mako
+template at <code class="docutils literal"><span class="pre">myproj/myproj/templates/name.html</span></code>:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;div id=&quot;name&quot;&gt;</span>
+<span class="x">  Name:</span>
+<span class="x">  ## TRANSLATORS: This is a proper name. See the gettext</span>
+<span class="x">  ## manual, section Names.</span>
+<span class="x">  </span><span class="cp">${</span><span class="n">_</span><span class="p">(</span><span class="s1">&#39;Francois Pinard&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>To extract gettext messages from this template the project needs
+a Mako section in its <a class="reference external" href="http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration">Babel Extraction Method Mapping
+file</a>
+(typically located at <code class="docutils literal"><span class="pre">myproj/babel.cfg</span></code>):</p>
+<div class="highlight-cfg"><div class="highlight"><pre><span></span><span class="c1"># Extraction from Python source files</span>
+
+<span class="k">[python: myproj/**.py]</span>
+
+<span class="c1"># Extraction from Mako templates</span>
+
+<span class="k">[mako: myproj/templates/**.html]</span>
+<span class="na">input_encoding</span> <span class="o">=</span> <span class="s">utf-8</span>
+</pre></div>
+</div>
+<p>The Mako extractor supports an optional <code class="docutils literal"><span class="pre">input_encoding</span></code>
+parameter specifying the encoding of the templates (identical to
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>/<a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>&#8216;s <code class="docutils literal"><span class="pre">input_encoding</span></code> parameter).</p>
+<p>Invoking <a class="reference external" href="http://babel.edgewall.org/">Babel</a>&#8216;s extractor at the
+command line in the project&#8217;s root directory:</p>
+<div class="highlight-sh"><div class="highlight"><pre><span></span>myproj$ pybabel extract -F babel.cfg -c <span class="s2">&quot;TRANSLATORS:&quot;</span> .
+</pre></div>
+</div>
+<p>will output a <cite>gettext</cite> catalog to <cite>stdout</cite> including the following:</p>
+<div class="highlight-pot"><div class="highlight"><pre><span></span><span class="c1">#. TRANSLATORS: This is a proper name. See the gettext</span>
+<span class="c1">#. manual, section Names.</span>
+<span class="kd">#: myproj/templates/name.html:5</span>
+<span class="nv">msgid</span> <span class="s">&quot;Francois Pinard&quot;</span>
+<span class="nv">msgstr</span> <span class="s">&quot;&quot;</span>
+</pre></div>
+</div>
+<p>This is only a basic example:
+<a class="reference external" href="http://babel.edgewall.org/">Babel</a> can be invoked from <code class="docutils literal"><span class="pre">setup.py</span></code>
+and its command line options specified in the accompanying
+<code class="docutils literal"><span class="pre">setup.cfg</span></code> via <a class="reference external" href="http://babel.edgewall.org/wiki/Documentation/setup.html">Babel Distutils/Setuptools
+Integration</a>.</p>
+<p>Comments must immediately precede a <cite>gettext</cite> message to be
+extracted. In the following case the <code class="docutils literal"><span class="pre">TRANSLATORS:</span></code> comment would
+not have been extracted:</p>
+<div class="highlight-mako"><div class="highlight"><pre><span></span><span class="x">&lt;div id=&quot;name&quot;&gt;</span>
+<span class="x">  ## TRANSLATORS: This is a proper name. See the gettext</span>
+<span class="x">  ## manual, section Names.</span>
+<span class="x">  Name: </span><span class="cp">${</span><span class="n">_</span><span class="p">(</span><span class="s1">&#39;Francois Pinard&#39;</span><span class="p">)</span><span class="cp">}</span><span class="x"></span>
+<span class="x">&lt;/div&gt;</span>
+</pre></div>
+</div>
+<p>See the <a class="reference external" href="http://babel.edgewall.org/wiki/Documentation/index.html">Babel User
+Guide</a>
+for more information.</p>
+</div>
+</div>
+<div class="section" id="api-reference">
+<h2>API Reference<a class="headerlink" href="#api-reference" title="Permalink to this headline">¶</a></h2>
+<dl class="class">
+<dt id="mako.template.Template">
+<em class="property">class </em><code class="descclassname">mako.template.</code><code class="descname">Template</code><span class="sig-paren">(</span><em>text=None</em>, <em>filename=None</em>, <em>uri=None</em>, <em>format_exceptions=False</em>, <em>error_handler=None</em>, <em>lookup=None</em>, <em>output_encoding=None</em>, <em>encoding_errors='strict'</em>, <em>module_directory=None</em>, <em>cache_args=None</em>, <em>cache_impl='beaker'</em>, <em>cache_enabled=True</em>, <em>cache_type=None</em>, <em>cache_dir=None</em>, <em>cache_url=None</em>, <em>module_filename=None</em>, <em>input_encoding=None</em>, <em>disable_unicode=False</em>, <em>module_writer=None</em>, <em>bytestring_passthrough=False</em>, <em>default_filters=None</em>, <em>buffer_filters=()</em>, <em>strict_undefined=False</em>, <em>imports=None</em>, <em>future_imports=None</em>, <em>enable_loop=True</em>, <em>preprocessor=None</em>, <em>lexer_cls=None</em>, <em>include_error_handler=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Represents a compiled template.</p>
+<p><a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> includes a reference to the original
+template source (via the <a class="reference internal" href="#RichTraceback.source" title="RichTraceback.source"><code class="xref py py-attr docutils literal"><span class="pre">source</span></code></a> attribute)
+as well as the source code of the
+generated Python module (i.e. the <a class="reference internal" href="#mako.template.Template.code" title="mako.template.Template.code"><code class="xref py py-attr docutils literal"><span class="pre">code</span></code></a> attribute),
+as well as a reference to an actual Python module.</p>
+<p><a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> is constructed using either a literal string
+representing the template text, or a filename representing a filesystem
+path to a source file.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.template.Template.params.text"></span><strong>text</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.text">¶</a> &#8211; textual template source.  This argument is mutually
+exclusive versus the <code class="docutils literal"><span class="pre">filename</span></code> parameter.</li>
+<li><span class="target" id="mako.template.Template.params.filename"></span><strong>filename</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.filename">¶</a> &#8211; filename of the source template.  This argument is
+mutually exclusive versus the <code class="docutils literal"><span class="pre">text</span></code> parameter.</li>
+<li><span class="target" id="mako.template.Template.params.buffer_filters"></span><strong>buffer_filters</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.buffer_filters">¶</a> &#8211; string list of filters to be applied
+to the output of <code class="docutils literal"><span class="pre">%def</span></code>s which are buffered, cached, or otherwise
+filtered, after all filters
+defined with the <code class="docutils literal"><span class="pre">%def</span></code> itself have been applied. Allows the
+creation of default expression filters that let the output
+of return-valued <code class="docutils literal"><span class="pre">%def</span></code>s &#8220;opt out&#8221; of that filtering via
+passing special attributes or objects.</li>
+<li><span class="target" id="mako.template.Template.params.bytestring_passthrough"></span><strong>bytestring_passthrough</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.bytestring_passthrough">¶</a> &#8211; <p>When <code class="docutils literal"><span class="pre">True</span></code>, and <code class="docutils literal"><span class="pre">output_encoding</span></code> is
+set to <code class="docutils literal"><span class="pre">None</span></code>, and <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">Template.render()</span></code></a> is used to render,
+the <cite>StringIO</cite> or <cite>cStringIO</cite> buffer will be used instead of the
+default &#8220;fast&#8221; buffer.   This allows raw bytestrings in the
+output stream, such as in expressions, to pass straight
+through to the buffer.  This flag is forced
+to <code class="docutils literal"><span class="pre">True</span></code> if <code class="docutils literal"><span class="pre">disable_unicode</span></code> is also configured.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.4: </span>Added to provide the same behavior as that of the previous series.</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.cache_args"></span><strong>cache_args</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_args">¶</a> &#8211; Dictionary of cache configuration arguments that
+will be passed to the <a class="reference internal" href="caching.html#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a>.   See <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.cache_dir"></span><strong>cache_dir</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_dir">¶</a> &#8211; <div class="deprecated">
+<p><span class="versionmodified">Deprecated since version 0.6: </span>Use the <code class="docutils literal"><span class="pre">'dir'</span></code> argument in the <code class="docutils literal"><span class="pre">cache_args</span></code> dictionary.
+See <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.cache_enabled"></span><strong>cache_enabled</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_enabled">¶</a> &#8211; Boolean flag which enables caching of this
+template.  See <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.cache_impl"></span><strong>cache_impl</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_impl">¶</a> &#8211; String name of a <a class="reference internal" href="caching.html#mako.cache.CacheImpl" title="mako.cache.CacheImpl"><code class="xref py py-class docutils literal"><span class="pre">CacheImpl</span></code></a> caching
+implementation to use.   Defaults to <code class="docutils literal"><span class="pre">'beaker'</span></code>.</li>
+<li><span class="target" id="mako.template.Template.params.cache_type"></span><strong>cache_type</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_type">¶</a> &#8211; <div class="deprecated">
+<p><span class="versionmodified">Deprecated since version 0.6: </span>Use the <code class="docutils literal"><span class="pre">'type'</span></code> argument in the <code class="docutils literal"><span class="pre">cache_args</span></code> dictionary.
+See <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.cache_url"></span><strong>cache_url</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.cache_url">¶</a> &#8211; <div class="deprecated">
+<p><span class="versionmodified">Deprecated since version 0.6: </span>Use the <code class="docutils literal"><span class="pre">'url'</span></code> argument in the <code class="docutils literal"><span class="pre">cache_args</span></code> dictionary.
+See <a class="reference internal" href="caching.html"><span class="std std-ref">Caching</span></a>.</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.default_filters"></span><strong>default_filters</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.default_filters">¶</a> &#8211; List of string filter names that will
+be applied to all expressions.  See <a class="reference internal" href="filtering.html#filtering-default-filters"><span class="std std-ref">The default_filters Argument</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.disable_unicode"></span><strong>disable_unicode</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.disable_unicode">¶</a> &#8211; Disables all awareness of Python Unicode
+objects.  See <a class="reference internal" href="unicode.html#unicode-disabled"><span class="std std-ref">Saying to Heck with It: Disabling the Usage of Unicode Entirely</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.enable_loop"></span><strong>enable_loop</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.enable_loop">¶</a> &#8211; When <code class="docutils literal"><span class="pre">True</span></code>, enable the <code class="docutils literal"><span class="pre">loop</span></code> context variable.
+This can be set to <code class="docutils literal"><span class="pre">False</span></code> to support templates that may
+be making usage of the name &#8220;<code class="docutils literal"><span class="pre">loop</span></code>&#8221;.   Individual templates can
+re-enable the &#8220;loop&#8221; context by placing the directive
+<code class="docutils literal"><span class="pre">enable_loop=&quot;True&quot;</span></code> inside the <code class="docutils literal"><span class="pre">&lt;%page&gt;</span></code> tag &#8211; see
+<a class="reference internal" href="runtime.html#migrating-loop"><span class="std std-ref">Migrating Legacy Templates that Use the Word &#8220;loop&#8221;</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.encoding_errors"></span><strong>encoding_errors</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.encoding_errors">¶</a> &#8211; Error parameter passed to <code class="docutils literal"><span class="pre">encode()</span></code> when
+string encoding is performed. See <a class="reference internal" href="#usage-unicode"><span class="std std-ref">Using Unicode and Encoding</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.error_handler"></span><strong>error_handler</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.error_handler">¶</a> &#8211; <p>Python callable which is called whenever
+compile or runtime exceptions occur. The callable is passed
+the current context as well as the exception. If the
+callable returns <code class="docutils literal"><span class="pre">True</span></code>, the exception is considered to
+be handled, else it is re-raised after the function
+completes. Is used to provide custom error-rendering
+functions.</p>
+<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<p class="last"><a class="reference internal" href="#mako.template.Template.params.include_error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.include_error_handler</span></code></a> - include-specific
+error handler function</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.format_exceptions"></span><strong>format_exceptions</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.format_exceptions">¶</a> &#8211; if <code class="docutils literal"><span class="pre">True</span></code>, exceptions which occur during
+the render phase of this template will be caught and
+formatted into an HTML error page, which then becomes the
+rendered result of the <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a> call. Otherwise,
+runtime exceptions are propagated outwards.</li>
+<li><span class="target" id="mako.template.Template.params.imports"></span><strong>imports</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.imports">¶</a> &#8211; String list of Python statements, typically individual
+&#8220;import&#8221; lines, which will be placed into the module level
+preamble of all generated Python modules. See the example
+in <a class="reference internal" href="filtering.html#filtering-default-filters"><span class="std std-ref">The default_filters Argument</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.future_imports"></span><strong>future_imports</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.future_imports">¶</a> &#8211; String list of names to import from <cite>__future__</cite>.
+These will be concatenated into a comma-separated string and inserted
+into the beginning of the template, e.g. <code class="docutils literal"><span class="pre">futures_imports=['FOO',</span>
+<span class="pre">'BAR']</span></code> results in <code class="docutils literal"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">FOO,</span> <span class="pre">BAR</span></code>.  If you&#8217;re
+interested in using features like the new division operator, you must
+use future_imports to convey that to the renderer, as otherwise the
+import will not appear as the first executed statement in the generated
+code and will therefore not have the desired effect.</li>
+<li><span class="target" id="mako.template.Template.params.include_error_handler"></span><strong>include_error_handler</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.include_error_handler">¶</a> &#8211; <p>An error handler that runs when this template
+is included within another one via the <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code> tag, and raises an
+error.  Compare to the <a class="reference internal" href="#mako.template.Template.params.error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.error_handler</span></code></a> option.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 1.0.6.</span></p>
+</div>
+<div class="admonition seealso">
+<p class="first admonition-title">See also</p>
+<p class="last"><a class="reference internal" href="#mako.template.Template.params.error_handler" title="mako.template.Template"><code class="xref py py-paramref docutils literal"><span class="pre">Template.error_handler</span></code></a> - top-level error handler function</p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.input_encoding"></span><strong>input_encoding</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.input_encoding">¶</a> &#8211; Encoding of the template&#8217;s source code.  Can
+be used in lieu of the coding comment. See
+<a class="reference internal" href="#usage-unicode"><span class="std std-ref">Using Unicode and Encoding</span></a> as well as <a class="reference internal" href="unicode.html"><span class="std std-ref">The Unicode Chapter</span></a> for
+details on source encoding.</li>
+<li><span class="target" id="mako.template.Template.params.lookup"></span><strong>lookup</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.lookup">¶</a> &#8211; a <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> instance that will be used
+for all file lookups via the <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code>,
+<code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code>, and <code class="docutils literal"><span class="pre">&lt;%inherit&gt;</span></code> tags. See
+<a class="reference internal" href="#usage-templatelookup"><span class="std std-ref">Using TemplateLookup</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.module_directory"></span><strong>module_directory</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.module_directory">¶</a> &#8211; Filesystem location where generated
+Python module files will be placed.</li>
+<li><span class="target" id="mako.template.Template.params.module_filename"></span><strong>module_filename</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.module_filename">¶</a> &#8211; Overrides the filename of the generated
+Python module file. For advanced usage only.</li>
+<li><span class="target" id="mako.template.Template.params.module_writer"></span><strong>module_writer</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.module_writer">¶</a> &#8211; <p>A callable which overrides how the Python
+module is written entirely.  The callable is passed the
+encoded source content of the module and the destination
+path to be written to.   The default behavior of module writing
+uses a tempfile in conjunction with a file move in order
+to make the operation atomic.   So a user-defined module
+writing function that mimics the default behavior would be:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">tempfile</span>
+<span class="kn">import</span> <span class="nn">os</span>
+<span class="kn">import</span> <span class="nn">shutil</span>
+
+<span class="k">def</span> <span class="nf">module_writer</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">outputpath</span><span class="p">):</span>
+    <span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span> <span class="o">=</span> \
+        <span class="n">tempfile</span><span class="o">.</span><span class="n">mkstemp</span><span class="p">(</span>
+            <span class="nb">dir</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">outputpath</span><span class="p">)</span>
+        <span class="p">)</span>
+
+    <span class="n">os</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="n">source</span><span class="p">)</span>
+    <span class="n">os</span><span class="o">.</span><span class="n">close</span><span class="p">(</span><span class="n">dest</span><span class="p">)</span>
+    <span class="n">shutil</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">outputpath</span><span class="p">)</span>
+
+<span class="kn">from</span> <span class="nn">mako.template</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="n">mytemplate</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span>
+                <span class="n">filename</span><span class="o">=</span><span class="s2">&quot;index.html&quot;</span><span class="p">,</span>
+                <span class="n">module_directory</span><span class="o">=</span><span class="s2">&quot;/path/to/modules&quot;</span><span class="p">,</span>
+                <span class="n">module_writer</span><span class="o">=</span><span class="n">module_writer</span>
+            <span class="p">)</span>
+</pre></div>
+</div>
+<p>The function is provided for unusual configurations where
+certain platform-specific permissions or other special
+steps are needed.</p>
+</li>
+<li><span class="target" id="mako.template.Template.params.output_encoding"></span><strong>output_encoding</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.output_encoding">¶</a> &#8211; The encoding to use when <a class="reference internal" href="#mako.template.Template.render" title="mako.template.Template.render"><code class="xref py py-meth docutils literal"><span class="pre">render()</span></code></a>
+is called.
+See <a class="reference internal" href="#usage-unicode"><span class="std std-ref">Using Unicode and Encoding</span></a> as well as <a class="reference internal" href="unicode.html"><span class="std std-ref">The Unicode Chapter</span></a>.</li>
+<li><span class="target" id="mako.template.Template.params.preprocessor"></span><strong>preprocessor</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.preprocessor">¶</a> &#8211; Python callable which will be passed
+the full template source before it is parsed. The return
+result of the callable will be used as the template source
+code.</li>
+<li><span class="target" id="mako.template.Template.params.lexer_cls"></span><strong>lexer_cls</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.lexer_cls">¶</a> &#8211; <p>A <code class="xref py py-class docutils literal"><span class="pre">Lexer</span></code> class used to parse
+the template.   The <code class="xref py py-class docutils literal"><span class="pre">Lexer</span></code> class is used by
+default.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.7.4.</span></p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.strict_undefined"></span><strong>strict_undefined</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.strict_undefined">¶</a> &#8211; <p>Replaces the automatic usage of
+<code class="docutils literal"><span class="pre">UNDEFINED</span></code> for any undeclared variables not located in
+the <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> with an immediate raise of
+<code class="docutils literal"><span class="pre">NameError</span></code>. The advantage is immediate reporting of
+missing variables which include the name.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 0.3.6.</span></p>
+</div>
+</li>
+<li><span class="target" id="mako.template.Template.params.uri"></span><strong>uri</strong><a class="paramlink headerlink reference internal" href="#mako.template.Template.params.uri">¶</a> &#8211; string URI or other identifier for this template.
+If not provided, the <code class="docutils literal"><span class="pre">uri</span></code> is generated from the filesystem
+path, or from the in-memory identity of a non-file-based
+template. The primary usage of the <code class="docutils literal"><span class="pre">uri</span></code> is to provide a key
+within <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, as well as to generate the
+file path of the generated Python module file, if
+<code class="docutils literal"><span class="pre">module_directory</span></code> is specified.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+<dl class="attribute">
+<dt id="mako.template.Template.code">
+<code class="descname">code</code><a class="headerlink" href="#mako.template.Template.code" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the module source code for this <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.template.Template.get_def">
+<code class="descname">get_def</code><span class="sig-paren">(</span><em>name</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template.get_def" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a def of this template as a <a class="reference internal" href="#mako.template.DefTemplate" title="mako.template.DefTemplate"><code class="xref py py-class docutils literal"><span class="pre">DefTemplate</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.template.Template.list_defs">
+<code class="descname">list_defs</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template.list_defs" title="Permalink to this definition">¶</a></dt>
+<dd><p>return a list of defs in the template.</p>
+<div class="versionadded">
+<p><span class="versionmodified">New in version 1.0.4.</span></p>
+</div>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.template.Template.render">
+<code class="descname">render</code><span class="sig-paren">(</span><em>*args</em>, <em>**data</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template.render" title="Permalink to this definition">¶</a></dt>
+<dd><p>Render the output of this template as a string.</p>
+<p>If the template specifies an output encoding, the string
+will be encoded accordingly, else the output is raw (raw
+output uses <cite>cStringIO</cite> and can&#8217;t handle multibyte
+characters). A <a class="reference internal" href="runtime.html#mako.runtime.Context" title="mako.runtime.Context"><code class="xref py py-class docutils literal"><span class="pre">Context</span></code></a> object is created corresponding
+to the given data. Arguments that are explicitly declared
+by this template&#8217;s internal rendering method are also
+pulled from the given <code class="docutils literal"><span class="pre">*args</span></code>, <code class="docutils literal"><span class="pre">**data</span></code> members.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.template.Template.render_context">
+<code class="descname">render_context</code><span class="sig-paren">(</span><em>context</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template.render_context" title="Permalink to this definition">¶</a></dt>
+<dd><p>Render this <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> with the given context.</p>
+<p>The data is written to the context&#8217;s buffer.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.template.Template.render_unicode">
+<code class="descname">render_unicode</code><span class="sig-paren">(</span><em>*args</em>, <em>**data</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.Template.render_unicode" title="Permalink to this definition">¶</a></dt>
+<dd><p>Render the output of this template as a unicode object.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="mako.template.Template.source">
+<code class="descname">source</code><a class="headerlink" href="#mako.template.Template.source" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return the template source code for this <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.template.DefTemplate">
+<em class="property">class </em><code class="descclassname">mako.template.</code><code class="descname">DefTemplate</code><span class="sig-paren">(</span><em>parent</em>, <em>callable_</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.template.DefTemplate" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">mako.template.Template</span></code></a></p>
+<p>A <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> which represents a callable def in a parent
+template.</p>
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.lookup.TemplateCollection">
+<em class="property">class </em><code class="descclassname">mako.lookup.</code><code class="descname">TemplateCollection</code><a class="headerlink" href="#mako.lookup.TemplateCollection" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Represent a collection of <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> objects,
+identifiable via URI.</p>
+<p>A <a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a> is linked to the usage of
+all template tags that address other templates, such
+as <code class="docutils literal"><span class="pre">&lt;%include&gt;</span></code>, <code class="docutils literal"><span class="pre">&lt;%namespace&gt;</span></code>, and <code class="docutils literal"><span class="pre">&lt;%inherit&gt;</span></code>.
+The <code class="docutils literal"><span class="pre">file</span></code> attribute of each of those tags refers
+to a string URI that is passed to that <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>
+object&#8217;s <a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a> for resolution.</p>
+<p><a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a> is an abstract class,
+with the usual default implementation being <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>.</p>
+<dl class="method">
+<dt id="mako.lookup.TemplateCollection.adjust_uri">
+<code class="descname">adjust_uri</code><span class="sig-paren">(</span><em>uri</em>, <em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateCollection.adjust_uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>Adjust the given <code class="docutils literal"><span class="pre">uri</span></code> based on the calling <code class="docutils literal"><span class="pre">filename</span></code>.</p>
+<p>When this method is called from the runtime, the
+<code class="docutils literal"><span class="pre">filename</span></code> parameter is taken directly to the <code class="docutils literal"><span class="pre">filename</span></code>
+attribute of the calling template. Therefore a custom
+<a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a> subclass can place any string
+identifier desired in the <code class="docutils literal"><span class="pre">filename</span></code> parameter of the
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> objects it constructs and have them come back
+here.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateCollection.filename_to_uri">
+<code class="descname">filename_to_uri</code><span class="sig-paren">(</span><em>uri</em>, <em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateCollection.filename_to_uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>Convert the given <code class="docutils literal"><span class="pre">filename</span></code> to a URI relative to
+this <a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateCollection.get_template">
+<code class="descname">get_template</code><span class="sig-paren">(</span><em>uri</em>, <em>relativeto=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateCollection.get_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object corresponding to the given
+<code class="docutils literal"><span class="pre">uri</span></code>.</p>
+<p>The default implementation raises
+<code class="xref py py-class docutils literal"><span class="pre">NotImplementedError</span></code>. Implementations should
+raise <code class="xref py py-class docutils literal"><span class="pre">TemplateLookupException</span></code> if the given <code class="docutils literal"><span class="pre">uri</span></code>
+cannot be resolved.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.lookup.TemplateCollection.get_template.params.uri"></span><strong>uri</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateCollection.get_template.params.uri">¶</a> &#8211; String URI of the template to be resolved.</li>
+<li><span class="target" id="mako.lookup.TemplateCollection.get_template.params.relativeto"></span><strong>relativeto</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateCollection.get_template.params.relativeto">¶</a> &#8211; if present, the given <code class="docutils literal"><span class="pre">uri</span></code> is assumed to
+be relative to this URI.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateCollection.has_template">
+<code class="descname">has_template</code><span class="sig-paren">(</span><em>uri</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateCollection.has_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return <code class="docutils literal"><span class="pre">True</span></code> if this <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> is
+capable of returning a <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object for the
+given <code class="docutils literal"><span class="pre">uri</span></code>.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><span class="target" id="mako.lookup.TemplateCollection.has_template.params.uri"></span><strong>uri</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateCollection.has_template.params.uri">¶</a> &#8211; String URI of the template to be resolved.</td>
+</tr>
+</tbody>
+</table>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.lookup.TemplateLookup">
+<em class="property">class </em><code class="descclassname">mako.lookup.</code><code class="descname">TemplateLookup</code><span class="sig-paren">(</span><em>directories=None</em>, <em>module_directory=None</em>, <em>filesystem_checks=True</em>, <em>collection_size=-1</em>, <em>format_exceptions=False</em>, <em>error_handler=None</em>, <em>disable_unicode=False</em>, <em>bytestring_passthrough=False</em>, <em>output_encoding=None</em>, <em>encoding_errors='strict'</em>, <em>cache_args=None</em>, <em>cache_impl='beaker'</em>, <em>cache_enabled=True</em>, <em>cache_type=None</em>, <em>cache_dir=None</em>, <em>cache_url=None</em>, <em>modulename_callable=None</em>, <em>module_writer=None</em>, <em>default_filters=None</em>, <em>buffer_filters=()</em>, <em>strict_undefined=False</em>, <em>imports=None</em>, <em>future_imports=None</em>, <em>enable_loop=True</em>, <em>input_encoding=None</em>, <em>preprocessor=None</em>, <em>lexer_cls=None</em>, <em>include_error_handler=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">mako.lookup.TemplateCollection</span></code></a></p>
+<p>Represent a collection of templates that locates template source files
+from the local filesystem.</p>
+<p>The primary argument is the <code class="docutils literal"><span class="pre">directories</span></code> argument, the list of
+directories to search:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">lookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">([</span><span class="s2">&quot;/path/to/templates&quot;</span><span class="p">])</span>
+<span class="n">some_template</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s2">&quot;/index.html&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> can also be given <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> objects
+programatically using <a class="reference internal" href="#mako.lookup.TemplateLookup.put_string" title="mako.lookup.TemplateLookup.put_string"><code class="xref py py-meth docutils literal"><span class="pre">put_string()</span></code></a> or <a class="reference internal" href="#mako.lookup.TemplateLookup.put_template" title="mako.lookup.TemplateLookup.put_template"><code class="xref py py-meth docutils literal"><span class="pre">put_template()</span></code></a>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">lookup</span> <span class="o">=</span> <span class="n">TemplateLookup</span><span class="p">()</span>
+<span class="n">lookup</span><span class="o">.</span><span class="n">put_string</span><span class="p">(</span><span class="s2">&quot;base.html&quot;</span><span class="p">,</span> <span class="s1">&#39;&#39;&#39;</span>
+<span class="s1">    &lt;html&gt;&lt;body&gt;${self.next()}&lt;/body&gt;&lt;/html&gt;</span>
+<span class="s1">&#39;&#39;&#39;</span><span class="p">)</span>
+<span class="n">lookup</span><span class="o">.</span><span class="n">put_string</span><span class="p">(</span><span class="s2">&quot;hello.html&quot;</span><span class="p">,</span> <span class="s1">&#39;&#39;&#39;</span>
+<span class="s1">    &lt;</span><span class="si">%i</span><span class="s1">nclude file=&#39;base.html&#39;/&gt;</span>
+
+<span class="s1">    Hello, world !</span>
+<span class="s1">&#39;&#39;&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><span class="target" id="mako.lookup.TemplateLookup.params.directories"></span><strong>directories</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateLookup.params.directories">¶</a> &#8211; A list of directory names which will be
+searched for a particular template URI. The URI is appended
+to each directory and the filesystem checked.</li>
+<li><span class="target" id="mako.lookup.TemplateLookup.params.collection_size"></span><strong>collection_size</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateLookup.params.collection_size">¶</a> &#8211; Approximate size of the collection used
+to store templates. If left at its default of <code class="docutils literal"><span class="pre">-1</span></code>, the size
+is unbounded, and a plain Python dictionary is used to
+relate URI strings to <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> instances.
+Otherwise, a least-recently-used cache object is used which
+will maintain the size of the collection approximately to
+the number given.</li>
+<li><span class="target" id="mako.lookup.TemplateLookup.params.filesystem_checks"></span><strong>filesystem_checks</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateLookup.params.filesystem_checks">¶</a> &#8211; When at its default value of <code class="docutils literal"><span class="pre">True</span></code>,
+each call to <a class="reference internal" href="#mako.lookup.TemplateLookup.get_template" title="mako.lookup.TemplateLookup.get_template"><code class="xref py py-meth docutils literal"><span class="pre">TemplateLookup.get_template()</span></code></a> will
+compare the filesystem last modified time to the time in
+which an existing <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object was created.
+This allows the <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> to regenerate a
+new <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> whenever the original source has
+been updated. Set this to <code class="docutils literal"><span class="pre">False</span></code> for a very minor
+performance increase.</li>
+<li><span class="target" id="mako.lookup.TemplateLookup.params.modulename_callable"></span><strong>modulename_callable</strong><a class="paramlink headerlink reference internal" href="#mako.lookup.TemplateLookup.params.modulename_callable">¶</a> &#8211; A callable which, when present,
+is passed the path of the source file as well as the
+requested URI, and then returns the full path of the
+generated Python module file. This is used to inject
+alternate schemes for Python module location. If left at
+its default of <code class="docutils literal"><span class="pre">None</span></code>, the built in system of generation
+based on <code class="docutils literal"><span class="pre">module_directory</span></code> plus <code class="docutils literal"><span class="pre">uri</span></code> is used.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+<p>All other keyword parameters available for
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> are mirrored here. When new
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> objects are created, the keywords
+established with this <a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a> are passed on
+to each new <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a>.</p>
+<dl class="method">
+<dt id="mako.lookup.TemplateLookup.adjust_uri">
+<code class="descname">adjust_uri</code><span class="sig-paren">(</span><em>uri</em>, <em>relativeto</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup.adjust_uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>Adjust the given <code class="docutils literal"><span class="pre">uri</span></code> based on the given relative URI.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateLookup.filename_to_uri">
+<code class="descname">filename_to_uri</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup.filename_to_uri" title="Permalink to this definition">¶</a></dt>
+<dd><p>Convert the given <code class="docutils literal"><span class="pre">filename</span></code> to a URI relative to
+this <a class="reference internal" href="#mako.lookup.TemplateCollection" title="mako.lookup.TemplateCollection"><code class="xref py py-class docutils literal"><span class="pre">TemplateCollection</span></code></a>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateLookup.get_template">
+<code class="descname">get_template</code><span class="sig-paren">(</span><em>uri</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup.get_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object corresponding to the given
+<code class="docutils literal"><span class="pre">uri</span></code>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">The <code class="docutils literal"><span class="pre">relativeto</span></code> argument is not supported here at
+the moment.</p>
+</div>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateLookup.put_string">
+<code class="descname">put_string</code><span class="sig-paren">(</span><em>uri</em>, <em>text</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup.put_string" title="Permalink to this definition">¶</a></dt>
+<dd><p>Place a new <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object into this
+<a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, based on the given string of
+<code class="docutils literal"><span class="pre">text</span></code>.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="mako.lookup.TemplateLookup.put_template">
+<code class="descname">put_template</code><span class="sig-paren">(</span><em>uri</em>, <em>template</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.lookup.TemplateLookup.put_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Place a new <a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object into this
+<a class="reference internal" href="#mako.lookup.TemplateLookup" title="mako.lookup.TemplateLookup"><code class="xref py py-class docutils literal"><span class="pre">TemplateLookup</span></code></a>, based on the given
+<a class="reference internal" href="#mako.template.Template" title="mako.template.Template"><code class="xref py py-class docutils literal"><span class="pre">Template</span></code></a> object.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="class">
+<dt id="mako.exceptions.RichTraceback">
+<em class="property">class </em><code class="descclassname">mako.exceptions.</code><code class="descname">RichTraceback</code><span class="sig-paren">(</span><em>error=None</em>, <em>traceback=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.exceptions.RichTraceback" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">object</span></code></p>
+<p>Pull the current exception from the <code class="docutils literal"><span class="pre">sys</span></code> traceback and extracts
+Mako-specific template information.</p>
+<p>See the usage examples in <a class="reference internal" href="#handling-exceptions"><span class="std std-ref">Handling Exceptions</span></a>.</p>
+<dl class="attribute">
+<dt id="RichTraceback.error">
+<code class="descname">error</code><a class="headerlink" href="#RichTraceback.error" title="Permalink to this definition">¶</a></dt>
+<dd><p>the exception instance.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.message">
+<code class="descname">message</code><a class="headerlink" href="#RichTraceback.message" title="Permalink to this definition">¶</a></dt>
+<dd><p>the exception error message as unicode.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.source">
+<code class="descname">source</code><a class="headerlink" href="#RichTraceback.source" title="Permalink to this definition">¶</a></dt>
+<dd><p>source code of the file where the error occurred.
+If the error occurred within a compiled template,
+this is the template source.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.lineno">
+<code class="descname">lineno</code><a class="headerlink" href="#RichTraceback.lineno" title="Permalink to this definition">¶</a></dt>
+<dd><p>line number where the error occurred.  If the error
+occurred within a compiled template, the line number
+is adjusted to that of the template source.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.records">
+<code class="descname">records</code><a class="headerlink" href="#RichTraceback.records" title="Permalink to this definition">¶</a></dt>
+<dd><p>a list of 8-tuples containing the original
+python traceback elements, plus the
+filename, line number, source line, and full template source
+for the traceline mapped back to its originating source
+template, if any for that traceline (else the fields are <code class="docutils literal"><span class="pre">None</span></code>).</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.reverse_records">
+<code class="descname">reverse_records</code><a class="headerlink" href="#RichTraceback.reverse_records" title="Permalink to this definition">¶</a></dt>
+<dd><p>the list of records in reverse
+traceback &#8211; a list of 4-tuples, in the same format as a regular
+python traceback, with template-corresponding
+traceback records replacing the originals.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="RichTraceback.reverse_traceback">
+<code class="descname">reverse_traceback</code><a class="headerlink" href="#RichTraceback.reverse_traceback" title="Permalink to this definition">¶</a></dt>
+<dd><p>the traceback list in reverse.</p>
+</dd></dl>
+
+</dd></dl>
+
+<dl class="function">
+<dt id="mako.exceptions.html_error_template">
+<code class="descclassname">mako.exceptions.</code><code class="descname">html_error_template</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#mako.exceptions.html_error_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Provides a template that renders a stack trace in an HTML format,
+providing an excerpt of code as well as substituting source template
+filenames, line numbers and code for that of the originating source
+template, as applicable.</p>
+<p>The template&#8217;s default <code class="docutils literal"><span class="pre">encoding_errors</span></code> value is
+<code class="docutils literal"><span class="pre">'htmlentityreplace'</span></code>. The template has two options. With the
+<code class="docutils literal"><span class="pre">full</span></code> option disabled, only a section of an HTML document is
+returned. With the <code class="docutils literal"><span class="pre">css</span></code> option disabled, the default stylesheet
+won&#8217;t be included.</p>
+</dd></dl>
+
+<dl class="function">
+<dt id="mako.exceptions.text_error_template">
+<code class="descclassname">mako.exceptions.</code><code class="descname">text_error_template</code><span class="sig-paren">(</span><em>lookup=None</em><span class="sig-paren">)</span><a class="headerlink" href="#mako.exceptions.text_error_template" title="Permalink to this definition">¶</a></dt>
+<dd><p>Provides a template that renders a stack trace in a similar format to
+the Python interpreter, substituting source template filenames, line
+numbers and code for that of the originating source template, as
+applicable.</p>
+</dd></dl>
+
+</div>
+</div>
+
+    </div>
+
+</div>
+
+<div id="docs-bottom-navigation" class="docs-navigation-links">
+        Previous:
+        <a href="index.html" title="previous chapter">Table of Contents</a>
+        Next:
+        <a href="syntax.html" title="next chapter">Syntax</a>
+
+    <div id="docs-copyright">
+        &copy; Copyright the Mako authors and contributors.
+        Documentation generated using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.4.6
+        with Mako templates.
+    </div>
+</div>
+
+</div>
+
+<div class="clearfix">
+
+<hr/>
+
+<div class="copyright">Website content copyright &copy; by Michael Bayer.
+    All rights reserved.  Mako and its documentation are licensed
+    under the MIT license.  mike(&)zzzcomputing.com</div>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/examples/bench/basic.py b/examples/bench/basic.py
new file mode 100644 (file)
index 0000000..6835065
--- /dev/null
@@ -0,0 +1,191 @@
+# basic.py - basic benchmarks adapted from Genshi
+# Copyright (C) 2006 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.
+
+from cgi import escape
+import os
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
+import sys
+import timeit
+
+def u(stringlit):
+    if sys.version_info >= (3,):
+        return stringlit
+    else:
+        return stringlit.decode('latin1')
+
+__all__ = ['mako', 'mako_inheritance', 'jinja2', 'jinja2_inheritance',
+            'cheetah', 'django', 'myghty', 'genshi', 'kid']
+
+# Templates content and constants
+TITLE = 'Just a test'
+USER = 'joe'
+ITEMS = ['Number %d' % num for num in range(1, 15)]
+U_ITEMS = [u(item) for item in ITEMS]
+
+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=TITLE, user=USER, items=ITEMS)
+        return template.generate(**data).render('xhtml')
+
+    if verbose:
+        print(render())
+    return render
+
+def myghty(dirname, verbose=False):
+    from myghty import interp
+    interpreter = interp.Interpreter(component_root=dirname)
+    def render():
+        data = dict(title=TITLE, user=USER, items=ITEMS)
+        buffer = StringIO()
+        interpreter.execute("template.myt", request_args=data, out_buffer=buffer)
+        return buffer.getvalue()
+    if verbose:
+        print(render())
+    return render
+
+def mako(dirname, verbose=False):
+    from mako.template import Template
+    from mako.lookup import TemplateLookup
+    disable_unicode = (sys.version_info < (3,))
+    lookup = TemplateLookup(directories=[dirname], filesystem_checks=False, disable_unicode=disable_unicode)
+    template = lookup.get_template('template.html')
+    def render():
+        return template.render(title=TITLE, user=USER, list_items=U_ITEMS)
+    if verbose:
+        print(template.code + " " + render())
+    return render
+mako_inheritance = mako
+
+def jinja2(dirname, verbose=False):
+    from jinja2 import Environment, FileSystemLoader
+    env = Environment(loader=FileSystemLoader(dirname))
+    template = env.get_template('template.html')
+    def render():
+        return template.render(title=TITLE, user=USER, list_items=U_ITEMS)
+    if verbose:
+        print(render())
+    return render
+jinja2_inheritance = jinja2
+
+def cheetah(dirname, verbose=False):
+    from Cheetah.Template import Template
+    filename = os.path.join(dirname, 'template.tmpl')
+    template = Template(file=filename)
+    def render():
+        template.__dict__.update({'title': TITLE, 'user': USER,
+                                  'list_items': U_ITEMS})
+        return template.respond()
+
+    if verbose:
+        print(dir(template))
+        print(template.generatedModuleCode())
+        print(render())
+    return render
+
+def django(dirname, verbose=False):
+    from django.conf import settings
+    settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')])
+    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': TITLE, 'user': USER, 'items': ITEMS}
+        return tmpl.render(template.Context(data))
+
+    if verbose:
+        print(render())
+    return render
+
+def kid(dirname, verbose=False):
+    import kid
+    kid.path = kid.TemplatePath([dirname])
+    template = kid.Template(file='template.kid')
+    def render():
+        template = kid.Template(file='template.kid',
+                                title=TITLE, user=USER, items=ITEMS)
+        return template.serialize(output='xhtml')
+
+    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:
+            sys.stdout.write('%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:
+        try:
+            import hotshot, hotshot.stats
+            prof = hotshot.Profile("template.prof")
+            benchtime = prof.runcall(run, engines, number=100, verbose=verbose)
+            stats = hotshot.stats.load("template.prof")
+        except ImportError:
+            import cProfile, pstats
+            stmt = "run(%r, number=%r, verbose=%r)" % (engines, 1000, verbose)
+            cProfile.runctx(stmt, globals(), {}, "template.prof")
+            stats = pstats.Stats("template.prof")
+        stats.strip_dirs()
+        stats.sort_stats('time', 'calls')
+        stats.print_stats()
+    else:
+        run(engines, verbose=verbose)
diff --git a/examples/bench/cheetah/footer.tmpl b/examples/bench/cheetah/footer.tmpl
new file mode 100644 (file)
index 0000000..1b00330
--- /dev/null
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
diff --git a/examples/bench/cheetah/header.tmpl b/examples/bench/cheetah/header.tmpl
new file mode 100644 (file)
index 0000000..432487f
--- /dev/null
@@ -0,0 +1,5 @@
+<div id="header">
+  <h1>$title</h1>
+</div>
+
+
diff --git a/examples/bench/cheetah/template.tmpl b/examples/bench/cheetah/template.tmpl
new file mode 100644 (file)
index 0000000..f1c2243
--- /dev/null
@@ -0,0 +1,31 @@
+<!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 greeting(name)
+      <p>hello ${name}!</p>
+      #end def
+    #include "cheetah/header.tmpl"
+
+    $greeting($user)
+    $greeting('me')
+    $greeting('world')
+    <h2>Loop</h2>
+    #if $list_items
+      <ul>
+        #for $list_item in $list_items
+          <li #if $list_item is $list_items[-1] then "class='last'" else ""#>$list_item</li>
+        #end for
+      </ul>
+    #end if
+
+    #include "cheetah/footer.tmpl"
+  </body>
+</html>
diff --git a/examples/bench/django/templatetags/__init__.py b/examples/bench/django/templatetags/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/examples/bench/django/templatetags/bench.py b/examples/bench/django/templatetags/bench.py
new file mode 100644 (file)
index 0000000..7bf0abc
--- /dev/null
@@ -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/examples/bench/kid/base.kid b/examples/bench/kid/base.kid
new file mode 100644 (file)
index 0000000..061e9dd
--- /dev/null
@@ -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/examples/bench/kid/template.kid b/examples/bench/kid/template.kid
new file mode 100644 (file)
index 0000000..7f79d7a
--- /dev/null
@@ -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/examples/bench/myghty/base.myt b/examples/bench/myghty/base.myt
new file mode 100644 (file)
index 0000000..af0474a
--- /dev/null
@@ -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">
+<%args scope="request">
+    title
+</%args>
+
+<& REQUEST:header &>
+
+<body>
+<div id="header">
+  <h1><% title %></h1>
+</div>
+
+% m.call_next()
+
+<div id="footer"></div>
+
+</body>
+</html>
+
+
+<%method greeting>
+<%args>
+   name
+</%args>
+Hello, <% name | h %>
+</%method>
diff --git a/examples/bench/myghty/template.myt b/examples/bench/myghty/template.myt
new file mode 100644 (file)
index 0000000..138e0ae
--- /dev/null
@@ -0,0 +1,30 @@
+<%flags>inherit="base.myt"</%flags>
+<%args>
+       title
+       items
+       user
+</%args>
+
+<%method header>
+    <%args scope="request">
+    title
+    </%args>
+<head>
+  <title><% title %></title>
+</head>
+</%method>
+
+  <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 i, item in enumerate(items):
+  <li <% i+1==len(items) and "class='last'" or ""%>><% item %></li>
+%
+      </ul>
+%
+
diff --git a/examples/wsgi/run_wsgi.py b/examples/wsgi/run_wsgi.py
new file mode 100644 (file)
index 0000000..270022d
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import cgi, re, os, posixpath, mimetypes
+from mako.lookup import TemplateLookup
+from mako import exceptions
+
+root = './'
+port = 8000
+
+lookup = TemplateLookup(
+             directories=[root + 'templates', root + 'htdocs'],
+             filesystem_checks=True,
+             module_directory='./modules',
+             # even better would be to use 'charset' in start_response
+             output_encoding='ascii',
+             encoding_errors='replace'
+         )
+
+def serve(environ, start_response):
+    """serves requests using the WSGI callable interface."""
+    fieldstorage = cgi.FieldStorage(
+            fp = environ['wsgi.input'],
+            environ = environ,
+            keep_blank_values = True
+    )
+    d = dict([(k, getfield(fieldstorage[k])) for k in fieldstorage])
+
+    uri = environ.get('PATH_INFO', '/')
+    if not uri:
+        uri = '/index.html'
+    else:
+        uri = re.sub(r'^/$', '/index.html', uri)
+
+    if re.match(r'.*\.html$', uri):
+        try:
+            template = lookup.get_template(uri)
+        except exceptions.TopLevelLookupException:
+            start_response("404 Not Found", [])
+            return [str.encode("Cant find template '%s'" % uri)]
+
+        start_response("200 OK", [('Content-type','text/html')])
+
+        try:
+            return [template.render(**d)]
+        except:
+            return [exceptions.html_error_template().render()]
+    else:
+        u = re.sub(r'^\/+', '', uri)
+        filename = os.path.join(root, u)
+        if os.path.isfile(filename):
+            start_response("200 OK", [('Content-type',guess_type(uri))])
+            return [open(filename, 'rb').read()]
+        else:
+            start_response("404 Not Found", [])
+            return [str.encode("File not found: '%s'" % filename)]
+def getfield(f):
+    """convert values from cgi.Field objects to plain values."""
+    if isinstance(f, list):
+        return [getfield(x) for x in f]
+    else:
+        return f.value
+
+extensions_map = mimetypes.types_map.copy()
+
+def guess_type(path):
+    """return a mimetype for the given path based on file extension."""
+    base, ext = posixpath.splitext(path)
+    if ext in extensions_map:
+        return extensions_map[ext]
+    ext = ext.lower()
+    if ext in extensions_map:
+        return extensions_map[ext]
+    else:
+        return 'text/html'
+if __name__ == '__main__':
+    import wsgiref.simple_server
+    server = wsgiref.simple_server.make_server('', port, serve)
+    print("Server listening on port %d" % port)
+    server.serve_forever()
diff --git a/mako/__init__.py b/mako/__init__.py
new file mode 100644 (file)
index 0000000..eaa24dc
--- /dev/null
@@ -0,0 +1,8 @@
+# mako/__init__.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+
+__version__ = '1.0.6'
diff --git a/mako/_ast_util.py b/mako/_ast_util.py
new file mode 100644 (file)
index 0000000..8d19b0d
--- /dev/null
@@ -0,0 +1,851 @@
+# mako/_ast_util.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""
+    ast
+    ~~~
+
+    The `ast` module helps Python applications to process trees of the Python
+    abstract syntax grammar.  The abstract syntax itself might change with
+    each Python release; this module helps to find out programmatically what
+    the current grammar looks like and allows modifications of it.
+
+    An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
+    a flag to the `compile()` builtin function or by using the `parse()`
+    function from this module.  The result will be a tree of objects whose
+    classes all inherit from `ast.AST`.
+
+    A modified abstract syntax tree can be compiled into a Python code object
+    using the built-in `compile()` function.
+
+    Additionally various helper functions are provided that make working with
+    the trees simpler.  The main intention of the helper functions and this
+    module in general is to provide an easy to use interface for libraries
+    that work tightly with the python syntax (template engines for example).
+
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: Python License.
+"""
+from _ast import *  # noqa
+from mako.compat import arg_stringname
+
+BOOLOP_SYMBOLS = {
+    And: 'and',
+    Or: 'or'
+}
+
+BINOP_SYMBOLS = {
+    Add: '+',
+    Sub: '-',
+    Mult: '*',
+    Div: '/',
+    FloorDiv: '//',
+    Mod: '%',
+    LShift: '<<',
+    RShift: '>>',
+    BitOr: '|',
+    BitAnd: '&',
+    BitXor: '^'
+}
+
+CMPOP_SYMBOLS = {
+    Eq: '==',
+    Gt: '>',
+    GtE: '>=',
+    In: 'in',
+    Is: 'is',
+    IsNot: 'is not',
+    Lt: '<',
+    LtE: '<=',
+    NotEq: '!=',
+    NotIn: 'not in'
+}
+
+UNARYOP_SYMBOLS = {
+    Invert: '~',
+    Not: 'not',
+    UAdd: '+',
+    USub: '-'
+}
+
+ALL_SYMBOLS = {}
+ALL_SYMBOLS.update(BOOLOP_SYMBOLS)
+ALL_SYMBOLS.update(BINOP_SYMBOLS)
+ALL_SYMBOLS.update(CMPOP_SYMBOLS)
+ALL_SYMBOLS.update(UNARYOP_SYMBOLS)
+
+
+def parse(expr, filename='<unknown>', mode='exec'):
+    """Parse an expression into an AST node."""
+    return compile(expr, filename, mode, PyCF_ONLY_AST)
+
+
+def to_source(node, indent_with=' ' * 4):
+    """
+    This function can convert a node tree back into python sourcecode.  This
+    is useful for debugging purposes, especially if you're dealing with custom
+    asts not generated by python itself.
+
+    It could be that the sourcecode is evaluable when the AST itself is not
+    compilable / evaluable.  The reason for this is that the AST contains some
+    more data than regular sourcecode does, which is dropped during
+    conversion.
+
+    Each level of indentation is replaced with `indent_with`.  Per default this
+    parameter is equal to four spaces as suggested by PEP 8, but it might be
+    adjusted to match the application's styleguide.
+    """
+    generator = SourceGenerator(indent_with)
+    generator.visit(node)
+    return ''.join(generator.result)
+
+
+def dump(node):
+    """
+    A very verbose representation of the node passed.  This is useful for
+    debugging purposes.
+    """
+    def _format(node):
+        if isinstance(node, AST):
+            return '%s(%s)' % (node.__class__.__name__,
+                               ', '.join('%s=%s' % (a, _format(b))
+                                         for a, b in iter_fields(node)))
+        elif isinstance(node, list):
+            return '[%s]' % ', '.join(_format(x) for x in node)
+        return repr(node)
+    if not isinstance(node, AST):
+        raise TypeError('expected AST, got %r' % node.__class__.__name__)
+    return _format(node)
+
+
+def copy_location(new_node, old_node):
+    """
+    Copy the source location hint (`lineno` and `col_offset`) from the
+    old to the new node if possible and return the new one.
+    """
+    for attr in 'lineno', 'col_offset':
+        if attr in old_node._attributes and attr in new_node._attributes \
+           and hasattr(old_node, attr):
+            setattr(new_node, attr, getattr(old_node, attr))
+    return new_node
+
+
+def fix_missing_locations(node):
+    """
+    Some nodes require a line number and the column offset.  Without that
+    information the compiler will abort the compilation.  Because it can be
+    a dull task to add appropriate line numbers and column offsets when
+    adding new nodes this function can help.  It copies the line number and
+    column offset of the parent node to the child nodes without this
+    information.
+
+    Unlike `copy_location` this works recursive and won't touch nodes that
+    already have a location information.
+    """
+    def _fix(node, lineno, col_offset):
+        if 'lineno' in node._attributes:
+            if not hasattr(node, 'lineno'):
+                node.lineno = lineno
+            else:
+                lineno = node.lineno
+        if 'col_offset' in node._attributes:
+            if not hasattr(node, 'col_offset'):
+                node.col_offset = col_offset
+            else:
+                col_offset = node.col_offset
+        for child in iter_child_nodes(node):
+            _fix(child, lineno, col_offset)
+    _fix(node, 1, 0)
+    return node
+
+
+def increment_lineno(node, n=1):
+    """
+    Increment the line numbers of all nodes by `n` if they have line number
+    attributes.  This is useful to "move code" to a different location in a
+    file.
+    """
+    for node in zip((node,), walk(node)):
+        if 'lineno' in node._attributes:
+            node.lineno = getattr(node, 'lineno', 0) + n
+
+
+def iter_fields(node):
+    """Iterate over all fields of a node, only yielding existing fields."""
+    # CPython 2.5 compat
+    if not hasattr(node, '_fields') or not node._fields:
+        return
+    for field in node._fields:
+        try:
+            yield field, getattr(node, field)
+        except AttributeError:
+            pass
+
+
+def get_fields(node):
+    """Like `iter_fiels` but returns a dict."""
+    return dict(iter_fields(node))
+
+
+def iter_child_nodes(node):
+    """Iterate over all child nodes or a node."""
+    for name, field in iter_fields(node):
+        if isinstance(field, AST):
+            yield field
+        elif isinstance(field, list):
+            for item in field:
+                if isinstance(item, AST):
+                    yield item
+
+
+def get_child_nodes(node):
+    """Like `iter_child_nodes` but returns a list."""
+    return list(iter_child_nodes(node))
+
+
+def get_compile_mode(node):
+    """
+    Get the mode for `compile` of a given node.  If the node is not a `mod`
+    node (`Expression`, `Module` etc.) a `TypeError` is thrown.
+    """
+    if not isinstance(node, mod):
+        raise TypeError('expected mod node, got %r' % node.__class__.__name__)
+    return {
+        Expression: 'eval',
+        Interactive: 'single'
+    }.get(node.__class__, 'expr')
+
+
+def get_docstring(node):
+    """
+    Return the docstring for the given node or `None` if no docstring can be
+    found.  If the node provided does not accept docstrings a `TypeError`
+    will be raised.
+    """
+    if not isinstance(node, (FunctionDef, ClassDef, Module)):
+        raise TypeError("%r can't have docstrings" % node.__class__.__name__)
+    if node.body and isinstance(node.body[0], Str):
+        return node.body[0].s
+
+
+def walk(node):
+    """
+    Iterate over all nodes.  This is useful if you only want to modify nodes in
+    place and don't care about the context or the order the nodes are returned.
+    """
+    from collections import deque
+    todo = deque([node])
+    while todo:
+        node = todo.popleft()
+        todo.extend(iter_child_nodes(node))
+        yield node
+
+
+class NodeVisitor(object):
+
+    """
+    Walks the abstract syntax tree and call visitor functions for every node
+    found.  The visitor functions may return values which will be forwarded
+    by the `visit` method.
+
+    Per default the visitor functions for the nodes are ``'visit_'`` +
+    class name of the node.  So a `TryFinally` node visit function would
+    be `visit_TryFinally`.  This behavior can be changed by overriding
+    the `get_visitor` function.  If no visitor function exists for a node
+    (return value `None`) the `generic_visit` visitor is used instead.
+
+    Don't use the `NodeVisitor` if you want to apply changes to nodes during
+    traversing.  For this a special visitor exists (`NodeTransformer`) that
+    allows modifications.
+    """
+
+    def get_visitor(self, node):
+        """
+        Return the visitor function for this node or `None` if no visitor
+        exists for this node.  In that case the generic visit function is
+        used instead.
+        """
+        method = 'visit_' + node.__class__.__name__
+        return getattr(self, method, None)
+
+    def visit(self, node):
+        """Visit a node."""
+        f = self.get_visitor(node)
+        if f is not None:
+            return f(node)
+        return self.generic_visit(node)
+
+    def generic_visit(self, node):
+        """Called if no explicit visitor function exists for a node."""
+        for field, value in iter_fields(node):
+            if isinstance(value, list):
+                for item in value:
+                    if isinstance(item, AST):
+                        self.visit(item)
+            elif isinstance(value, AST):
+                self.visit(value)
+
+
+class NodeTransformer(NodeVisitor):
+
+    """
+    Walks the abstract syntax tree and allows modifications of nodes.
+
+    The `NodeTransformer` will walk the AST and use the return value of the
+    visitor functions to replace or remove the old node.  If the return
+    value of the visitor function is `None` the node will be removed
+    from the previous location otherwise it's replaced with the return
+    value.  The return value may be the original node in which case no
+    replacement takes place.
+
+    Here an example transformer that rewrites all `foo` to `data['foo']`::
+
+        class RewriteName(NodeTransformer):
+
+            def visit_Name(self, node):
+                return copy_location(Subscript(
+                    value=Name(id='data', ctx=Load()),
+                    slice=Index(value=Str(s=node.id)),
+                    ctx=node.ctx
+                ), node)
+
+    Keep in mind that if the node you're operating on has child nodes
+    you must either transform the child nodes yourself or call the generic
+    visit function for the node first.
+
+    Nodes that were part of a collection of statements (that applies to
+    all statement nodes) may also return a list of nodes rather than just
+    a single node.
+
+    Usually you use the transformer like this::
+
+        node = YourTransformer().visit(node)
+    """
+
+    def generic_visit(self, node):
+        for field, old_value in iter_fields(node):
+            old_value = getattr(node, field, None)
+            if isinstance(old_value, list):
+                new_values = []
+                for value in old_value:
+                    if isinstance(value, AST):
+                        value = self.visit(value)
+                        if value is None:
+                            continue
+                        elif not isinstance(value, AST):
+                            new_values.extend(value)
+                            continue
+                    new_values.append(value)
+                old_value[:] = new_values
+            elif isinstance(old_value, AST):
+                new_node = self.visit(old_value)
+                if new_node is None:
+                    delattr(node, field)
+                else:
+                    setattr(node, field, new_node)
+        return node
+
+
+class SourceGenerator(NodeVisitor):
+
+    """
+    This visitor is able to transform a well formed syntax tree into python
+    sourcecode.  For more details have a look at the docstring of the
+    `node_to_source` function.
+    """
+
+    def __init__(self, indent_with):
+        self.result = []
+        self.indent_with = indent_with
+        self.indentation = 0
+        self.new_lines = 0
+
+    def write(self, x):
+        if self.new_lines:
+            if self.result:
+                self.result.append('\n' * self.new_lines)
+            self.result.append(self.indent_with * self.indentation)
+            self.new_lines = 0
+        self.result.append(x)
+
+    def newline(self, n=1):
+        self.new_lines = max(self.new_lines, n)
+
+    def body(self, statements):
+        self.new_line = True
+        self.indentation += 1
+        for stmt in statements:
+            self.visit(stmt)
+        self.indentation -= 1
+
+    def body_or_else(self, node):
+        self.body(node.body)
+        if node.orelse:
+            self.newline()
+            self.write('else:')
+            self.body(node.orelse)
+
+    def signature(self, node):
+        want_comma = []
+
+        def write_comma():
+            if want_comma:
+                self.write(', ')
+            else:
+                want_comma.append(True)
+
+        padding = [None] * (len(node.args) - len(node.defaults))
+        for arg, default in zip(node.args, padding + node.defaults):
+            write_comma()
+            self.visit(arg)
+            if default is not None:
+                self.write('=')
+                self.visit(default)
+        if node.vararg is not None:
+            write_comma()
+            self.write('*' + arg_stringname(node.vararg))
+        if node.kwarg is not None:
+            write_comma()
+            self.write('**' + arg_stringname(node.kwarg))
+
+    def decorators(self, node):
+        for decorator in node.decorator_list:
+            self.newline()
+            self.write('@')
+            self.visit(decorator)
+
+    # Statements
+
+    def visit_Assign(self, node):
+        self.newline()
+        for idx, target in enumerate(node.targets):
+            if idx:
+                self.write(', ')
+            self.visit(target)
+        self.write(' = ')
+        self.visit(node.value)
+
+    def visit_AugAssign(self, node):
+        self.newline()
+        self.visit(node.target)
+        self.write(BINOP_SYMBOLS[type(node.op)] + '=')
+        self.visit(node.value)
+
+    def visit_ImportFrom(self, node):
+        self.newline()
+        self.write('from %s%s import ' % ('.' * node.level, node.module))
+        for idx, item in enumerate(node.names):
+            if idx:
+                self.write(', ')
+            self.write(item)
+
+    def visit_Import(self, node):
+        self.newline()
+        for item in node.names:
+            self.write('import ')
+            self.visit(item)
+
+    def visit_Expr(self, node):
+        self.newline()
+        self.generic_visit(node)
+
+    def visit_FunctionDef(self, node):
+        self.newline(n=2)
+        self.decorators(node)
+        self.newline()
+        self.write('def %s(' % node.name)
+        self.signature(node.args)
+        self.write('):')
+        self.body(node.body)
+
+    def visit_ClassDef(self, node):
+        have_args = []
+
+        def paren_or_comma():
+            if have_args:
+                self.write(', ')
+            else:
+                have_args.append(True)
+                self.write('(')
+
+        self.newline(n=3)
+        self.decorators(node)
+        self.newline()
+        self.write('class %s' % node.name)
+        for base in node.bases:
+            paren_or_comma()
+            self.visit(base)
+        # XXX: the if here is used to keep this module compatible
+        #      with python 2.6.
+        if hasattr(node, 'keywords'):
+            for keyword in node.keywords:
+                paren_or_comma()
+                self.write(keyword.arg + '=')
+                self.visit(keyword.value)
+            if getattr(node, "starargs", None):
+                paren_or_comma()
+                self.write('*')
+                self.visit(node.starargs)
+            if getattr(node, "kwargs", None):
+                paren_or_comma()
+                self.write('**')
+                self.visit(node.kwargs)
+        self.write(have_args and '):' or ':')
+        self.body(node.body)
+
+    def visit_If(self, node):
+        self.newline()
+        self.write('if ')
+        self.visit(node.test)
+        self.write(':')
+        self.body(node.body)
+        while True:
+            else_ = node.orelse
+            if len(else_) == 1 and isinstance(else_[0], If):
+                node = else_[0]
+                self.newline()
+                self.write('elif ')
+                self.visit(node.test)
+                self.write(':')
+                self.body(node.body)
+            else:
+                self.newline()
+                self.write('else:')
+                self.body(else_)
+                break
+
+    def visit_For(self, node):
+        self.newline()
+        self.write('for ')
+        self.visit(node.target)
+        self.write(' in ')
+        self.visit(node.iter)
+        self.write(':')
+        self.body_or_else(node)
+
+    def visit_While(self, node):
+        self.newline()
+        self.write('while ')
+        self.visit(node.test)
+        self.write(':')
+        self.body_or_else(node)
+
+    def visit_With(self, node):
+        self.newline()
+        self.write('with ')
+        self.visit(node.context_expr)
+        if node.optional_vars is not None:
+            self.write(' as ')
+            self.visit(node.optional_vars)
+        self.write(':')
+        self.body(node.body)
+
+    def visit_Pass(self, node):
+        self.newline()
+        self.write('pass')
+
+    def visit_Print(self, node):
+        # XXX: python 2.6 only
+        self.newline()
+        self.write('print ')
+        want_comma = False
+        if node.dest is not None:
+            self.write(' >> ')
+            self.visit(node.dest)
+            want_comma = True
+        for value in node.values:
+            if want_comma:
+                self.write(', ')
+            self.visit(value)
+            want_comma = True
+        if not node.nl:
+            self.write(',')
+
+    def visit_Delete(self, node):
+        self.newline()
+        self.write('del ')
+        for idx, target in enumerate(node):
+            if idx:
+                self.write(', ')
+            self.visit(target)
+
+    def visit_TryExcept(self, node):
+        self.newline()
+        self.write('try:')
+        self.body(node.body)
+        for handler in node.handlers:
+            self.visit(handler)
+
+    def visit_TryFinally(self, node):
+        self.newline()
+        self.write('try:')
+        self.body(node.body)
+        self.newline()
+        self.write('finally:')
+        self.body(node.finalbody)
+
+    def visit_Global(self, node):
+        self.newline()
+        self.write('global ' + ', '.join(node.names))
+
+    def visit_Nonlocal(self, node):
+        self.newline()
+        self.write('nonlocal ' + ', '.join(node.names))
+
+    def visit_Return(self, node):
+        self.newline()
+        self.write('return ')
+        self.visit(node.value)
+
+    def visit_Break(self, node):
+        self.newline()
+        self.write('break')
+
+    def visit_Continue(self, node):
+        self.newline()
+        self.write('continue')
+
+    def visit_Raise(self, node):
+        # XXX: Python 2.6 / 3.0 compatibility
+        self.newline()
+        self.write('raise')
+        if hasattr(node, 'exc') and node.exc is not None:
+            self.write(' ')
+            self.visit(node.exc)
+            if node.cause is not None:
+                self.write(' from ')
+                self.visit(node.cause)
+        elif hasattr(node, 'type') and node.type is not None:
+            self.visit(node.type)
+            if node.inst is not None:
+                self.write(', ')
+                self.visit(node.inst)
+            if node.tback is not None:
+                self.write(', ')
+                self.visit(node.tback)
+
+    # Expressions
+
+    def visit_Attribute(self, node):
+        self.visit(node.value)
+        self.write('.' + node.attr)
+
+    def visit_Call(self, node):
+        want_comma = []
+
+        def write_comma():
+            if want_comma:
+                self.write(', ')
+            else:
+                want_comma.append(True)
+
+        self.visit(node.func)
+        self.write('(')
+        for arg in node.args:
+            write_comma()
+            self.visit(arg)
+        for keyword in node.keywords:
+            write_comma()
+            self.write(keyword.arg + '=')
+            self.visit(keyword.value)
+        if getattr(node, "starargs", None):
+            write_comma()
+            self.write('*')
+            self.visit(node.starargs)
+        if getattr(node, "kwargs", None):
+            write_comma()
+            self.write('**')
+            self.visit(node.kwargs)
+        self.write(')')
+
+    def visit_Name(self, node):
+        self.write(node.id)
+
+    def visit_NameConstant(self, node):
+        self.write(str(node.value))
+
+    def visit_arg(self, node):
+        self.write(node.arg)
+
+    def visit_Str(self, node):
+        self.write(repr(node.s))
+
+    def visit_Bytes(self, node):
+        self.write(repr(node.s))
+
+    def visit_Num(self, node):
+        self.write(repr(node.n))
+
+    def visit_Tuple(self, node):
+        self.write('(')
+        idx = -1
+        for idx, item in enumerate(node.elts):
+            if idx:
+                self.write(', ')
+            self.visit(item)
+        self.write(idx and ')' or ',)')
+
+    def sequence_visit(left, right):
+        def visit(self, node):
+            self.write(left)
+            for idx, item in enumerate(node.elts):
+                if idx:
+                    self.write(', ')
+                self.visit(item)
+            self.write(right)
+        return visit
+
+    visit_List = sequence_visit('[', ']')
+    visit_Set = sequence_visit('{', '}')
+    del sequence_visit
+
+    def visit_Dict(self, node):
+        self.write('{')
+        for idx, (key, value) in enumerate(zip(node.keys, node.values)):
+            if idx:
+                self.write(', ')
+            self.visit(key)
+            self.write(': ')
+            self.visit(value)
+        self.write('}')
+
+    def visit_BinOp(self, node):
+        self.write('(')
+        self.visit(node.left)
+        self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
+        self.visit(node.right)
+        self.write(')')
+
+    def visit_BoolOp(self, node):
+        self.write('(')
+        for idx, value in enumerate(node.values):
+            if idx:
+                self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
+            self.visit(value)
+        self.write(')')
+
+    def visit_Compare(self, node):
+        self.write('(')
+        self.visit(node.left)
+        for op, right in zip(node.ops, node.comparators):
+            self.write(' %s ' % CMPOP_SYMBOLS[type(op)])
+            self.visit(right)
+        self.write(')')
+
+    def visit_UnaryOp(self, node):
+        self.write('(')
+        op = UNARYOP_SYMBOLS[type(node.op)]
+        self.write(op)
+        if op == 'not':
+            self.write(' ')
+        self.visit(node.operand)
+        self.write(')')
+
+    def visit_Subscript(self, node):
+        self.visit(node.value)
+        self.write('[')
+        self.visit(node.slice)
+        self.write(']')
+
+    def visit_Slice(self, node):
+        if node.lower is not None:
+            self.visit(node.lower)
+        self.write(':')
+        if node.upper is not None:
+            self.visit(node.upper)
+        if node.step is not None:
+            self.write(':')
+            if not (isinstance(node.step, Name) and node.step.id == 'None'):
+                self.visit(node.step)
+
+    def visit_ExtSlice(self, node):
+        for idx, item in node.dims:
+            if idx:
+                self.write(', ')
+            self.visit(item)
+
+    def visit_Yield(self, node):
+        self.write('yield ')
+        self.visit(node.value)
+
+    def visit_Lambda(self, node):
+        self.write('lambda ')
+        self.signature(node.args)
+        self.write(': ')
+        self.visit(node.body)
+
+    def visit_Ellipsis(self, node):
+        self.write('Ellipsis')
+
+    def generator_visit(left, right):
+        def visit(self, node):
+            self.write(left)
+            self.visit(node.elt)
+            for comprehension in node.generators:
+                self.visit(comprehension)
+            self.write(right)
+        return visit
+
+    visit_ListComp = generator_visit('[', ']')
+    visit_GeneratorExp = generator_visit('(', ')')
+    visit_SetComp = generator_visit('{', '}')
+    del generator_visit
+
+    def visit_DictComp(self, node):
+        self.write('{')
+        self.visit(node.key)
+        self.write(': ')
+        self.visit(node.value)
+        for comprehension in node.generators:
+            self.visit(comprehension)
+        self.write('}')
+
+    def visit_IfExp(self, node):
+        self.visit(node.body)
+        self.write(' if ')
+        self.visit(node.test)
+        self.write(' else ')
+        self.visit(node.orelse)
+
+    def visit_Starred(self, node):
+        self.write('*')
+        self.visit(node.value)
+
+    def visit_Repr(self, node):
+        # XXX: python 2.6 only
+        self.write('`')
+        self.visit(node.value)
+        self.write('`')
+
+    # Helper Nodes
+
+    def visit_alias(self, node):
+        self.write(node.name)
+        if node.asname is not None:
+            self.write(' as ' + node.asname)
+
+    def visit_comprehension(self, node):
+        self.write(' for ')
+        self.visit(node.target)
+        self.write(' in ')
+        self.visit(node.iter)
+        if node.ifs:
+            for if_ in node.ifs:
+                self.write(' if ')
+                self.visit(if_)
+
+    def visit_excepthandler(self, node):
+        self.newline()
+        self.write('except')
+        if node.type is not None:
+            self.write(' ')
+            self.visit(node.type)
+            if node.name is not None:
+                self.write(' as ')
+                self.visit(node.name)
+        self.write(':')
+        self.body(node.body)
diff --git a/mako/ast.py b/mako/ast.py
new file mode 100644 (file)
index 0000000..8d2d150
--- /dev/null
@@ -0,0 +1,191 @@
+# mako/ast.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""utilities for analyzing expressions and blocks of Python
+code, as well as generating Python from AST nodes"""
+
+from mako import exceptions, pyparser, compat
+import re
+
+
+class PythonCode(object):
+
+    """represents information about a string containing Python code"""
+
+    def __init__(self, code, **exception_kwargs):
+        self.code = code
+
+        # represents all identifiers which are assigned to at some point in
+        # the code
+        self.declared_identifiers = set()
+
+        # represents all identifiers which are referenced before their
+        # assignment, if any
+        self.undeclared_identifiers = set()
+
+        # note that an identifier can be in both the undeclared and declared
+        # lists.
+
+        # using AST to parse instead of using code.co_varnames,
+        # code.co_names has several advantages:
+        # - we can locate an identifier as "undeclared" even if
+        # its declared later in the same block of code
+        # - AST is less likely to break with version changes
+        # (for example, the behavior of co_names changed a little bit
+        # in python version 2.5)
+        if isinstance(code, compat.string_types):
+            expr = pyparser.parse(code.lstrip(), "exec", **exception_kwargs)
+        else:
+            expr = code
+
+        f = pyparser.FindIdentifiers(self, **exception_kwargs)
+        f.visit(expr)
+
+
+class ArgumentList(object):
+
+    """parses a fragment of code as a comma-separated list of expressions"""
+
+    def __init__(self, code, **exception_kwargs):
+        self.codeargs = []
+        self.args = []
+        self.declared_identifiers = set()
+        self.undeclared_identifiers = set()
+        if isinstance(code, compat.string_types):
+            if re.match(r"\S", code) and not re.match(r",\s*$", code):
+                # if theres text and no trailing comma, insure its parsed
+                # as a tuple by adding a trailing comma
+                code += ","
+            expr = pyparser.parse(code, "exec", **exception_kwargs)
+        else:
+            expr = code
+
+        f = pyparser.FindTuple(self, PythonCode, **exception_kwargs)
+        f.visit(expr)
+
+
+class PythonFragment(PythonCode):
+
+    """extends PythonCode to provide identifier lookups in partial control
+    statements
+
+    e.g.
+        for x in 5:
+        elif y==9:
+        except (MyException, e):
+    etc.
+    """
+
+    def __init__(self, code, **exception_kwargs):
+        m = re.match(r'^(\w+)(?:\s+(.*?))?:\s*(#|$)', code.strip(), re.S)
+        if not m:
+            raise exceptions.CompileException(
+                "Fragment '%s' is not a partial control statement" %
+                code, **exception_kwargs)
+        if m.group(3):
+            code = code[:m.start(3)]
+        (keyword, expr) = m.group(1, 2)
+        if keyword in ['for', 'if', 'while']:
+            code = code + "pass"
+        elif keyword == 'try':
+            code = code + "pass\nexcept:pass"
+        elif keyword == 'elif' or keyword == 'else':
+            code = "if False:pass\n" + code + "pass"
+        elif keyword == 'except':
+            code = "try:pass\n" + code + "pass"
+        elif keyword == 'with':
+            code = code + "pass"
+        else:
+            raise exceptions.CompileException(
+                "Unsupported control keyword: '%s'" %
+                keyword, **exception_kwargs)
+        super(PythonFragment, self).__init__(code, **exception_kwargs)
+
+
+class FunctionDecl(object):
+
+    """function declaration"""
+
+    def __init__(self, code, allow_kwargs=True, **exception_kwargs):
+        self.code = code
+        expr = pyparser.parse(code, "exec", **exception_kwargs)
+
+        f = pyparser.ParseFunc(self, **exception_kwargs)
+        f.visit(expr)
+        if not hasattr(self, 'funcname'):
+            raise exceptions.CompileException(
+                "Code '%s' is not a function declaration" % code,
+                **exception_kwargs)
+        if not allow_kwargs and self.kwargs:
+            raise exceptions.CompileException(
+                "'**%s' keyword argument not allowed here" %
+                self.kwargnames[-1], **exception_kwargs)
+
+    def get_argument_expressions(self, as_call=False):
+        """Return the argument declarations of this FunctionDecl as a printable
+        list.
+
+        By default the return value is appropriate for writing in a ``def``;
+        set `as_call` to true to build arguments to be passed to the function
+        instead (assuming locals with the same names as the arguments exist).
+        """
+
+        namedecls = []
+
+        # Build in reverse order, since defaults and slurpy args come last
+        argnames = self.argnames[::-1]
+        kwargnames = self.kwargnames[::-1]
+        defaults = self.defaults[::-1]
+        kwdefaults = self.kwdefaults[::-1]
+
+        # Named arguments
+        if self.kwargs:
+            namedecls.append("**" + kwargnames.pop(0))
+
+        for name in kwargnames:
+            # Keyword-only arguments must always be used by name, so even if
+            # this is a call, print out `foo=foo`
+            if as_call:
+                namedecls.append("%s=%s" % (name, name))
+            elif kwdefaults:
+                default = kwdefaults.pop(0)
+                if default is None:
+                    # The AST always gives kwargs a default, since you can do
+                    # `def foo(*, a=1, b, c=3)`
+                    namedecls.append(name)
+                else:
+                    namedecls.append("%s=%s" % (
+                        name, pyparser.ExpressionGenerator(default).value()))
+            else:
+                namedecls.append(name)
+
+        # Positional arguments
+        if self.varargs:
+            namedecls.append("*" + argnames.pop(0))
+
+        for name in argnames:
+            if as_call or not defaults:
+                namedecls.append(name)
+            else:
+                default = defaults.pop(0)
+                namedecls.append("%s=%s" % (
+                    name, pyparser.ExpressionGenerator(default).value()))
+
+        namedecls.reverse()
+        return namedecls
+
+    @property
+    def allargnames(self):
+        return tuple(self.argnames) + tuple(self.kwargnames)
+
+
+class FunctionArgs(FunctionDecl):
+
+    """the argument portion of a function declaration"""
+
+    def __init__(self, code, **kwargs):
+        super(FunctionArgs, self).__init__("def ANON(%s):pass" % code,
+                                           **kwargs)
diff --git a/mako/cache.py b/mako/cache.py
new file mode 100644 (file)
index 0000000..94f3870
--- /dev/null
@@ -0,0 +1,240 @@
+# mako/cache.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+from mako import compat, util
+
+_cache_plugins = util.PluginLoader("mako.cache")
+
+register_plugin = _cache_plugins.register
+register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl")
+
+
+class Cache(object):
+
+    """Represents a data content cache made available to the module
+    space of a specific :class:`.Template` object.
+
+    .. versionadded:: 0.6
+       :class:`.Cache` by itself is mostly a
+       container for a :class:`.CacheImpl` object, which implements
+       a fixed API to provide caching services; specific subclasses exist to
+       implement different
+       caching strategies.   Mako includes a backend that works with
+       the Beaker caching system.   Beaker itself then supports
+       a number of backends (i.e. file, memory, memcached, etc.)
+
+    The construction of a :class:`.Cache` is part of the mechanics
+    of a :class:`.Template`, and programmatic access to this
+    cache is typically via the :attr:`.Template.cache` attribute.
+
+    """
+
+    impl = None
+    """Provide the :class:`.CacheImpl` in use by this :class:`.Cache`.
+
+    This accessor allows a :class:`.CacheImpl` with additional
+    methods beyond that of :class:`.Cache` to be used programmatically.
+
+    """
+
+    id = None
+    """Return the 'id' that identifies this cache.
+
+    This is a value that should be globally unique to the
+    :class:`.Template` associated with this cache, and can
+    be used by a caching system to name a local container
+    for data specific to this template.
+
+    """
+
+    starttime = None
+    """Epochal time value for when the owning :class:`.Template` was
+    first compiled.
+
+    A cache implementation may wish to invalidate data earlier than
+    this timestamp; this has the effect of the cache for a specific
+    :class:`.Template` starting clean any time the :class:`.Template`
+    is recompiled, such as when the original template file changed on
+    the filesystem.
+
+    """
+
+    def __init__(self, template, *args):
+        # check for a stale template calling the
+        # constructor
+        if isinstance(template, compat.string_types) and args:
+            return
+        self.template = template
+        self.id = template.module.__name__
+        self.starttime = template.module._modified_time
+        self._def_regions = {}
+        self.impl = self._load_impl(self.template.cache_impl)
+
+    def _load_impl(self, name):
+        return _cache_plugins.load(name)(self)
+
+    def get_or_create(self, key, creation_function, **kw):
+        """Retrieve a value from the cache, using the given creation function
+        to generate a new value."""
+
+        return self._ctx_get_or_create(key, creation_function, None, **kw)
+
+    def _ctx_get_or_create(self, key, creation_function, context, **kw):
+        """Retrieve a value from the cache, using the given creation function
+        to generate a new value."""
+
+        if not self.template.cache_enabled:
+            return creation_function()
+
+        return self.impl.get_or_create(
+            key,
+            creation_function,
+            **self._get_cache_kw(kw, context))
+
+    def set(self, key, value, **kw):
+        """Place a value in the cache.
+
+        :param key: the value's key.
+        :param value: the value.
+        :param \**kw: cache configuration arguments.
+
+        """
+
+        self.impl.set(key, value, **self._get_cache_kw(kw, None))
+
+    put = set
+    """A synonym for :meth:`.Cache.set`.
+
+    This is here for backwards compatibility.
+
+    """
+
+    def get(self, key, **kw):
+        """Retrieve a value from the cache.
+
+        :param key: the value's key.
+        :param \**kw: cache configuration arguments.  The
+         backend is configured using these arguments upon first request.
+         Subsequent requests that use the same series of configuration
+         values will use that same backend.
+
+        """
+        return self.impl.get(key, **self._get_cache_kw(kw, None))
+
+    def invalidate(self, key, **kw):
+        """Invalidate a value in the cache.
+
+        :param key: the value's key.
+        :param \**kw: cache configuration arguments.  The
+         backend is configured using these arguments upon first request.
+         Subsequent requests that use the same series of configuration
+         values will use that same backend.
+
+        """
+        self.impl.invalidate(key, **self._get_cache_kw(kw, None))
+
+    def invalidate_body(self):
+        """Invalidate the cached content of the "body" method for this
+        template.
+
+        """
+        self.invalidate('render_body', __M_defname='render_body')
+
+    def invalidate_def(self, name):
+        """Invalidate the cached content of a particular ``<%def>`` within this
+        template.
+
+        """
+
+        self.invalidate('render_%s' % name, __M_defname='render_%s' % name)
+
+    def invalidate_closure(self, name):
+        """Invalidate a nested ``<%def>`` within this template.
+
+        Caching of nested defs is a blunt tool as there is no
+        management of scope -- nested defs that use cache tags
+        need to have names unique of all other nested defs in the
+        template, else their content will be overwritten by
+        each other.
+
+        """
+
+        self.invalidate(name, __M_defname=name)
+
+    def _get_cache_kw(self, kw, context):
+        defname = kw.pop('__M_defname', None)
+        if not defname:
+            tmpl_kw = self.template.cache_args.copy()
+            tmpl_kw.update(kw)
+        elif defname in self._def_regions:
+            tmpl_kw = self._def_regions[defname]
+        else:
+            tmpl_kw = self.template.cache_args.copy()
+            tmpl_kw.update(kw)
+            self._def_regions[defname] = tmpl_kw
+        if context and self.impl.pass_context:
+            tmpl_kw = tmpl_kw.copy()
+            tmpl_kw.setdefault('context', context)
+        return tmpl_kw
+
+
+class CacheImpl(object):
+
+    """Provide a cache implementation for use by :class:`.Cache`."""
+
+    def __init__(self, cache):
+        self.cache = cache
+
+    pass_context = False
+    """If ``True``, the :class:`.Context` will be passed to
+    :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``.
+    """
+
+    def get_or_create(self, key, creation_function, **kw):
+        """Retrieve a value from the cache, using the given creation function
+        to generate a new value.
+
+        This function *must* return a value, either from
+        the cache, or via the given creation function.
+        If the creation function is called, the newly
+        created value should be populated into the cache
+        under the given key before being returned.
+
+        :param key: the value's key.
+        :param creation_function: function that when called generates
+         a new value.
+        :param \**kw: cache configuration arguments.
+
+        """
+        raise NotImplementedError()
+
+    def set(self, key, value, **kw):
+        """Place a value in the cache.
+
+        :param key: the value's key.
+        :param value: the value.
+        :param \**kw: cache configuration arguments.
+
+        """
+        raise NotImplementedError()
+
+    def get(self, key, **kw):
+        """Retrieve a value from the cache.
+
+        :param key: the value's key.
+        :param \**kw: cache configuration arguments.
+
+        """
+        raise NotImplementedError()
+
+    def invalidate(self, key, **kw):
+        """Invalidate a value in the cache.
+
+        :param key: the value's key.
+        :param \**kw: cache configuration arguments.
+
+        """
+        raise NotImplementedError()
diff --git a/mako/cmd.py b/mako/cmd.py
new file mode 100755 (executable)
index 0000000..dd1f833
--- /dev/null
@@ -0,0 +1,67 @@
+# mako/cmd.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+from argparse import ArgumentParser
+from os.path import isfile, dirname
+import sys
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako import exceptions
+
+
+def varsplit(var):
+    if "=" not in var:
+        return (var, "")
+    return var.split("=", 1)
+
+
+def _exit():
+    sys.stderr.write(exceptions.text_error_template().render())
+    sys.exit(1)
+
+
+def cmdline(argv=None):
+
+    parser = ArgumentParser("usage: %prog [FILENAME]")
+    parser.add_argument(
+        "--var", default=[], action="append",
+        help="variable (can be used multiple times, use name=value)")
+    parser.add_argument(
+        "--template-dir", default=[], action="append",
+        help="Directory to use for template lookup (multiple "
+        "directories may be provided). If not given then if the "
+        "template is read from stdin, the value defaults to be "
+        "the current directory, otherwise it defaults to be the "
+        "parent directory of the file provided.")
+    parser.add_argument('input', nargs='?', default='-')
+
+    options = parser.parse_args(argv)
+    if options.input == '-':
+        lookup_dirs = options.template_dir or ["."]
+        lookup = TemplateLookup(lookup_dirs)
+        try:
+            template = Template(sys.stdin.read(), lookup=lookup)
+        except:
+            _exit()
+    else:
+        filename = options.input
+        if not isfile(filename):
+            raise SystemExit("error: can't find %s" % filename)
+        lookup_dirs = options.template_dir or [dirname(filename)]
+        lookup = TemplateLookup(lookup_dirs)
+        try:
+            template = Template(filename=filename, lookup=lookup)
+        except:
+            _exit()
+
+    kw = dict([varsplit(var) for var in options.var])
+    try:
+        print(template.render(**kw))
+    except:
+        _exit()
+
+
+if __name__ == "__main__":
+    cmdline()
diff --git a/mako/codegen.py b/mako/codegen.py
new file mode 100644 (file)
index 0000000..d4ecbe8
--- /dev/null
@@ -0,0 +1,1255 @@
+# mako/codegen.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides functionality for rendering a parsetree constructing into module
+source code."""
+
+import time
+import re
+from mako.pygen import PythonPrinter
+from mako import util, ast, parsetree, filters, exceptions
+from mako import compat
+
+
+MAGIC_NUMBER = 10
+
+# names which are hardwired into the
+# template and are not accessed via the
+# context itself
+TOPLEVEL_DECLARED = set(["UNDEFINED", "STOP_RENDERING"])
+RESERVED_NAMES = set(['context', 'loop']).union(TOPLEVEL_DECLARED)
+
+
+def compile(node,
+            uri,
+            filename=None,
+            default_filters=None,
+            buffer_filters=None,
+            imports=None,
+            future_imports=None,
+            source_encoding=None,
+            generate_magic_comment=True,
+            disable_unicode=False,
+            strict_undefined=False,
+            enable_loop=True,
+            reserved_names=frozenset()):
+    """Generate module source code given a parsetree node,
+      uri, and optional source filename"""
+
+    # if on Py2K, push the "source_encoding" string to be
+    # a bytestring itself, as we will be embedding it into
+    # the generated source and we don't want to coerce the
+    # result into a unicode object, in "disable_unicode" mode
+    if not compat.py3k and isinstance(source_encoding, compat.text_type):
+        source_encoding = source_encoding.encode(source_encoding)
+
+    buf = util.FastEncodingBuffer()
+
+    printer = PythonPrinter(buf)
+    _GenerateRenderMethod(printer,
+                          _CompileContext(uri,
+                                          filename,
+                                          default_filters,
+                                          buffer_filters,
+                                          imports,
+                                          future_imports,
+                                          source_encoding,
+                                          generate_magic_comment,
+                                          disable_unicode,
+                                          strict_undefined,
+                                          enable_loop,
+                                          reserved_names),
+                          node)
+    return buf.getvalue()
+
+
+class _CompileContext(object):
+
+    def __init__(self,
+                 uri,
+                 filename,
+                 default_filters,
+                 buffer_filters,
+                 imports,
+                 future_imports,
+                 source_encoding,
+                 generate_magic_comment,
+                 disable_unicode,
+                 strict_undefined,
+                 enable_loop,
+                 reserved_names):
+        self.uri = uri
+        self.filename = filename
+        self.default_filters = default_filters
+        self.buffer_filters = buffer_filters
+        self.imports = imports
+        self.future_imports = future_imports
+        self.source_encoding = source_encoding
+        self.generate_magic_comment = generate_magic_comment
+        self.disable_unicode = disable_unicode
+        self.strict_undefined = strict_undefined
+        self.enable_loop = enable_loop
+        self.reserved_names = reserved_names
+
+
+class _GenerateRenderMethod(object):
+
+    """A template visitor object which generates the
+       full module source for a template.
+
+    """
+
+    def __init__(self, printer, compiler, node):
+        self.printer = printer
+        self.compiler = compiler
+        self.node = node
+        self.identifier_stack = [None]
+        self.in_def = isinstance(node, (parsetree.DefTag, parsetree.BlockTag))
+
+        if self.in_def:
+            name = "render_%s" % node.funcname
+            args = node.get_argument_expressions()
+            filtered = len(node.filter_args.args) > 0
+            buffered = eval(node.attributes.get('buffered', 'False'))
+            cached = eval(node.attributes.get('cached', 'False'))
+            defs = None
+            pagetag = None
+            if node.is_block and not node.is_anonymous:
+                args += ['**pageargs']
+        else:
+            defs = self.write_toplevel()
+            pagetag = self.compiler.pagetag
+            name = "render_body"
+            if pagetag is not None:
+                args = pagetag.body_decl.get_argument_expressions()
+                if not pagetag.body_decl.kwargs:
+                    args += ['**pageargs']
+                cached = eval(pagetag.attributes.get('cached', 'False'))
+                self.compiler.enable_loop = self.compiler.enable_loop or eval(
+                    pagetag.attributes.get(
+                        'enable_loop', 'False')
+                )
+            else:
+                args = ['**pageargs']
+                cached = False
+            buffered = filtered = False
+        if args is None:
+            args = ['context']
+        else:
+            args = [a for a in ['context'] + args]
+
+        self.write_render_callable(
+            pagetag or node,
+            name, args,
+            buffered, filtered, cached)
+
+        if defs is not None:
+            for node in defs:
+                _GenerateRenderMethod(printer, compiler, node)
+
+        if not self.in_def:
+            self.write_metadata_struct()
+
+    def write_metadata_struct(self):
+        self.printer.source_map[self.printer.lineno] = \
+            max(self.printer.source_map)
+        struct = {
+            "filename": self.compiler.filename,
+            "uri": self.compiler.uri,
+            "source_encoding": self.compiler.source_encoding,
+            "line_map": self.printer.source_map,
+        }
+        self.printer.writelines(
+            '"""',
+            '__M_BEGIN_METADATA',
+            compat.json.dumps(struct),
+            '__M_END_METADATA\n'
+            '"""'
+        )
+
+    @property
+    def identifiers(self):
+        return self.identifier_stack[-1]
+
+    def write_toplevel(self):
+        """Traverse a template structure for module-level directives and
+        generate the start of module-level code.
+
+        """
+        inherit = []
+        namespaces = {}
+        module_code = []
+
+        self.compiler.pagetag = None
+
+        class FindTopLevel(object):
+
+            def visitInheritTag(s, node):
+                inherit.append(node)
+
+            def visitNamespaceTag(s, node):
+                namespaces[node.name] = node
+
+            def visitPageTag(s, node):
+                self.compiler.pagetag = node
+
+            def visitCode(s, node):
+                if node.ismodule:
+                    module_code.append(node)
+
+        f = FindTopLevel()
+        for n in self.node.nodes:
+            n.accept_visitor(f)
+
+        self.compiler.namespaces = namespaces
+
+        module_ident = set()
+        for n in module_code:
+            module_ident = module_ident.union(n.declared_identifiers())
+
+        module_identifiers = _Identifiers(self.compiler)
+        module_identifiers.declared = module_ident
+
+        # module-level names, python code
+        if self.compiler.generate_magic_comment and \
+                self.compiler.source_encoding:
+            self.printer.writeline("# -*- coding:%s -*-" %
+                                   self.compiler.source_encoding)
+
+        if self.compiler.future_imports:
+            self.printer.writeline("from __future__ import %s" %
+                                   (", ".join(self.compiler.future_imports),))
+        self.printer.writeline("from mako import runtime, filters, cache")
+        self.printer.writeline("UNDEFINED = runtime.UNDEFINED")
+        self.printer.writeline("STOP_RENDERING = runtime.STOP_RENDERING")
+        self.printer.writeline("__M_dict_builtin = dict")
+        self.printer.writeline("__M_locals_builtin = locals")
+        self.printer.writeline("_magic_number = %r" % MAGIC_NUMBER)
+        self.printer.writeline("_modified_time = %r" % time.time())
+        self.printer.writeline("_enable_loop = %r" % self.compiler.enable_loop)
+        self.printer.writeline(
+            "_template_filename = %r" % self.compiler.filename)
+        self.printer.writeline("_template_uri = %r" % self.compiler.uri)
+        self.printer.writeline(
+            "_source_encoding = %r" % self.compiler.source_encoding)
+        if self.compiler.imports:
+            buf = ''
+            for imp in self.compiler.imports:
+                buf += imp + "\n"
+                self.printer.writeline(imp)
+            impcode = ast.PythonCode(
+                buf,
+                source='', lineno=0,
+                pos=0,
+                filename='template defined imports')
+        else:
+            impcode = None
+
+        main_identifiers = module_identifiers.branch(self.node)
+        module_identifiers.topleveldefs = \
+            module_identifiers.topleveldefs.\
+            union(main_identifiers.topleveldefs)
+        module_identifiers.declared.update(TOPLEVEL_DECLARED)
+        if impcode:
+            module_identifiers.declared.update(impcode.declared_identifiers)
+
+        self.compiler.identifiers = module_identifiers
+        self.printer.writeline("_exports = %r" %
+                               [n.name for n in
+                                main_identifiers.topleveldefs.values()]
+                               )
+        self.printer.write_blanks(2)
+
+        if len(module_code):
+            self.write_module_code(module_code)
+
+        if len(inherit):
+            self.write_namespaces(namespaces)
+            self.write_inherit(inherit[-1])
+        elif len(namespaces):
+            self.write_namespaces(namespaces)
+
+        return list(main_identifiers.topleveldefs.values())
+
+    def write_render_callable(self, node, name, args, buffered, filtered,
+                              cached):
+        """write a top-level render callable.
+
+        this could be the main render() method or that of a top-level def."""
+
+        if self.in_def:
+            decorator = node.decorator
+            if decorator:
+                self.printer.writeline(
+                    "@runtime._decorate_toplevel(%s)" % decorator)
+
+        self.printer.start_source(node.lineno)
+        self.printer.writelines(
+            "def %s(%s):" % (name, ','.join(args)),
+            # push new frame, assign current frame to __M_caller
+            "__M_caller = context.caller_stack._push_frame()",
+            "try:"
+        )
+        if buffered or filtered or cached:
+            self.printer.writeline("context._push_buffer()")
+
+        self.identifier_stack.append(
+            self.compiler.identifiers.branch(self.node))
+        if (not self.in_def or self.node.is_block) and '**pageargs' in args:
+            self.identifier_stack[-1].argument_declared.add('pageargs')
+
+        if not self.in_def and (
+            len(self.identifiers.locally_assigned) > 0 or
+            len(self.identifiers.argument_declared) > 0
+        ):
+            self.printer.writeline("__M_locals = __M_dict_builtin(%s)" %
+                                   ','.join([
+                                       "%s=%s" % (x, x) for x in
+                                            self.identifiers.argument_declared
+                                            ]))
+
+        self.write_variable_declares(self.identifiers, toplevel=True)
+
+        for n in self.node.nodes:
+            n.accept_visitor(self)
+
+        self.write_def_finish(self.node, buffered, filtered, cached)
+        self.printer.writeline(None)
+        self.printer.write_blanks(2)
+        if cached:
+            self.write_cache_decorator(
+                node, name,
+                args, buffered,
+                self.identifiers, toplevel=True)
+
+    def write_module_code(self, module_code):
+        """write module-level template code, i.e. that which
+        is enclosed in <%! %> tags in the template."""
+        for n in module_code:
+            self.printer.start_source(n.lineno)
+            self.printer.write_indented_block(n.text)
+
+    def write_inherit(self, node):
+        """write the module-level inheritance-determination callable."""
+
+        self.printer.writelines(
+            "def _mako_inherit(template, context):",
+            "_mako_generate_namespaces(context)",
+            "return runtime._inherit_from(context, %s, _template_uri)" %
+            (node.parsed_attributes['file']),
+            None
+        )
+
+    def write_namespaces(self, namespaces):
+        """write the module-level namespace-generating callable."""
+        self.printer.writelines(
+            "def _mako_get_namespace(context, name):",
+            "try:",
+            "return context.namespaces[(__name__, name)]",
+            "except KeyError:",
+            "_mako_generate_namespaces(context)",
+            "return context.namespaces[(__name__, name)]",
+            None, None
+        )
+        self.printer.writeline("def _mako_generate_namespaces(context):")
+
+        for node in namespaces.values():
+            if 'import' in node.attributes:
+                self.compiler.has_ns_imports = True
+            self.printer.start_source(node.lineno)
+            if len(node.nodes):
+                self.printer.writeline("def make_namespace():")
+                export = []
+                identifiers = self.compiler.identifiers.branch(node)
+                self.in_def = True
+
+                class NSDefVisitor(object):
+
+                    def visitDefTag(s, node):
+                        s.visitDefOrBase(node)
+
+                    def visitBlockTag(s, node):
+                        s.visitDefOrBase(node)
+
+                    def visitDefOrBase(s, node):
+                        if node.is_anonymous:
+                            raise exceptions.CompileException(
+                                "Can't put anonymous blocks inside "
+                                "<%namespace>",
+                                **node.exception_kwargs
+                            )
+                        self.write_inline_def(node, identifiers, nested=False)
+                        export.append(node.funcname)
+                vis = NSDefVisitor()
+                for n in node.nodes:
+                    n.accept_visitor(vis)
+                self.printer.writeline("return [%s]" % (','.join(export)))
+                self.printer.writeline(None)
+                self.in_def = False
+                callable_name = "make_namespace()"
+            else:
+                callable_name = "None"
+
+            if 'file' in node.parsed_attributes:
+                self.printer.writeline(
+                    "ns = runtime.TemplateNamespace(%r,"
+                    " context._clean_inheritance_tokens(),"
+                    " templateuri=%s, callables=%s, "
+                    " calling_uri=_template_uri)" %
+                    (
+                        node.name,
+                        node.parsed_attributes.get('file', 'None'),
+                        callable_name,
+                    )
+                )
+            elif 'module' in node.parsed_attributes:
+                self.printer.writeline(
+                    "ns = runtime.ModuleNamespace(%r,"
+                    " context._clean_inheritance_tokens(),"
+                    " callables=%s, calling_uri=_template_uri,"
+                    " module=%s)" %
+                    (
+                        node.name,
+                        callable_name,
+                        node.parsed_attributes.get(
+                            'module', 'None')
+                    )
+                )
+            else:
+                self.printer.writeline(
+                    "ns = runtime.Namespace(%r,"
+                    " context._clean_inheritance_tokens(),"
+                    " callables=%s, calling_uri=_template_uri)" %
+                    (
+                        node.name,
+                        callable_name,
+                    )
+                )
+            if eval(node.attributes.get('inheritable', "False")):
+                self.printer.writeline("context['self'].%s = ns" % (node.name))
+
+            self.printer.writeline(
+                "context.namespaces[(__name__, %s)] = ns" % repr(node.name))
+            self.printer.write_blanks(1)
+        if not len(namespaces):
+            self.printer.writeline("pass")
+        self.printer.writeline(None)
+
+    def write_variable_declares(self, identifiers, toplevel=False, limit=None):
+        """write variable declarations at the top of a function.
+
+        the variable declarations are in the form of callable
+        definitions for defs and/or name lookup within the
+        function's context argument. the names declared are based
+        on the names that are referenced in the function body,
+        which don't otherwise have any explicit assignment
+        operation. names that are assigned within the body are
+        assumed to be locally-scoped variables and are not
+        separately declared.
+
+        for def callable definitions, if the def is a top-level
+        callable then a 'stub' callable is generated which wraps
+        the current Context into a closure. if the def is not
+        top-level, it is fully rendered as a local closure.
+
+        """
+
+        # collection of all defs available to us in this scope
+        comp_idents = dict([(c.funcname, c) for c in identifiers.defs])
+        to_write = set()
+
+        # write "context.get()" for all variables we are going to
+        # need that arent in the namespace yet
+        to_write = to_write.union(identifiers.undeclared)
+
+        # write closure functions for closures that we define
+        # right here
+        to_write = to_write.union(
+            [c.funcname for c in identifiers.closuredefs.values()])
+
+        # remove identifiers that are declared in the argument
+        # signature of the callable
+        to_write = to_write.difference(identifiers.argument_declared)
+
+        # remove identifiers that we are going to assign to.
+        # in this way we mimic Python's behavior,
+        # i.e. assignment to a variable within a block
+        # means that variable is now a "locally declared" var,
+        # which cannot be referenced beforehand.
+        to_write = to_write.difference(identifiers.locally_declared)
+
+        if self.compiler.enable_loop:
+            has_loop = "loop" in to_write
+            to_write.discard("loop")
+        else:
+            has_loop = False
+
+        # if a limiting set was sent, constraint to those items in that list
+        # (this is used for the caching decorator)
+        if limit is not None:
+            to_write = to_write.intersection(limit)
+
+        if toplevel and getattr(self.compiler, 'has_ns_imports', False):
+            self.printer.writeline("_import_ns = {}")
+            self.compiler.has_imports = True
+            for ident, ns in self.compiler.namespaces.items():
+                if 'import' in ns.attributes:
+                    self.printer.writeline(
+                        "_mako_get_namespace(context, %r)."
+                        "_populate(_import_ns, %r)" %
+                        (
+                            ident,
+                            re.split(r'\s*,\s*', ns.attributes['import'])
+                        ))
+
+        if has_loop:
+            self.printer.writeline(
+                'loop = __M_loop = runtime.LoopStack()'
+            )
+
+        for ident in to_write:
+            if ident in comp_idents:
+                comp = comp_idents[ident]
+                if comp.is_block:
+                    if not comp.is_anonymous:
+                        self.write_def_decl(comp, identifiers)
+                    else:
+                        self.write_inline_def(comp, identifiers, nested=True)
+                else:
+                    if comp.is_root():
+                        self.write_def_decl(comp, identifiers)
+                    else:
+                        self.write_inline_def(comp, identifiers, nested=True)
+
+            elif ident in self.compiler.namespaces:
+                self.printer.writeline(
+                    "%s = _mako_get_namespace(context, %r)" %
+                    (ident, ident)
+                )
+            else:
+                if getattr(self.compiler, 'has_ns_imports', False):
+                    if self.compiler.strict_undefined:
+                        self.printer.writelines(
+                            "%s = _import_ns.get(%r, UNDEFINED)" %
+                            (ident, ident),
+                            "if %s is UNDEFINED:" % ident,
+                            "try:",
+                            "%s = context[%r]" % (ident, ident),
+                            "except KeyError:",
+                            "raise NameError(\"'%s' is not defined\")" %
+                            ident,
+                            None, None
+                        )
+                    else:
+                        self.printer.writeline(
+                            "%s = _import_ns.get"
+                            "(%r, context.get(%r, UNDEFINED))" %
+                            (ident, ident, ident))
+                else:
+                    if self.compiler.strict_undefined:
+                        self.printer.writelines(
+                            "try:",
+                            "%s = context[%r]" % (ident, ident),
+                            "except KeyError:",
+                            "raise NameError(\"'%s' is not defined\")" %
+                            ident,
+                            None
+                        )
+                    else:
+                        self.printer.writeline(
+                            "%s = context.get(%r, UNDEFINED)" % (ident, ident)
+                        )
+
+        self.printer.writeline("__M_writer = context.writer()")
+
+    def write_def_decl(self, node, identifiers):
+        """write a locally-available callable referencing a top-level def"""
+        funcname = node.funcname
+        namedecls = node.get_argument_expressions()
+        nameargs = node.get_argument_expressions(as_call=True)
+
+        if not self.in_def and (
+                len(self.identifiers.locally_assigned) > 0 or
+                len(self.identifiers.argument_declared) > 0):
+            nameargs.insert(0, 'context._locals(__M_locals)')
+        else:
+            nameargs.insert(0, 'context')
+        self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))
+        self.printer.writeline(
+            "return render_%s(%s)" % (funcname, ",".join(nameargs)))
+        self.printer.writeline(None)
+
+    def write_inline_def(self, node, identifiers, nested):
+        """write a locally-available def callable inside an enclosing def."""
+
+        namedecls = node.get_argument_expressions()
+
+        decorator = node.decorator
+        if decorator:
+            self.printer.writeline(
+                "@runtime._decorate_inline(context, %s)" % decorator)
+        self.printer.writeline(
+            "def %s(%s):" % (node.funcname, ",".join(namedecls)))
+        filtered = len(node.filter_args.args) > 0
+        buffered = eval(node.attributes.get('buffered', 'False'))
+        cached = eval(node.attributes.get('cached', 'False'))
+        self.printer.writelines(
+            # push new frame, assign current frame to __M_caller
+            "__M_caller = context.caller_stack._push_frame()",
+            "try:"
+        )
+        if buffered or filtered or cached:
+            self.printer.writelines(
+                "context._push_buffer()",
+            )
+
+        identifiers = identifiers.branch(node, nested=nested)
+
+        self.write_variable_declares(identifiers)
+
+        self.identifier_stack.append(identifiers)
+        for n in node.nodes:
+            n.accept_visitor(self)
+        self.identifier_stack.pop()
+
+        self.write_def_finish(node, buffered, filtered, cached)
+        self.printer.writeline(None)
+        if cached:
+            self.write_cache_decorator(node, node.funcname,
+                                       namedecls, False, identifiers,
+                                       inline=True, toplevel=False)
+
+    def write_def_finish(self, node, buffered, filtered, cached,
+                         callstack=True):
+        """write the end section of a rendering function, either outermost or
+        inline.
+
+        this takes into account if the rendering function was filtered,
+        buffered, etc.  and closes the corresponding try: block if any, and
+        writes code to retrieve captured content, apply filters, send proper
+        return value."""
+
+        if not buffered and not cached and not filtered:
+            self.printer.writeline("return ''")
+            if callstack:
+                self.printer.writelines(
+                    "finally:",
+                    "context.caller_stack._pop_frame()",
+                    None
+                )
+
+        if buffered or filtered or cached:
+            if buffered or cached:
+                # in a caching scenario, don't try to get a writer
+                # from the context after popping; assume the caching
+                # implemenation might be using a context with no
+                # extra buffers
+                self.printer.writelines(
+                    "finally:",
+                    "__M_buf = context._pop_buffer()"
+                )
+            else:
+                self.printer.writelines(
+                    "finally:",
+                    "__M_buf, __M_writer = context._pop_buffer_and_writer()"
+                )
+
+            if callstack:
+                self.printer.writeline("context.caller_stack._pop_frame()")
+
+            s = "__M_buf.getvalue()"
+            if filtered:
+                s = self.create_filter_callable(node.filter_args.args, s,
+                                                False)
+            self.printer.writeline(None)
+            if buffered and not cached:
+                s = self.create_filter_callable(self.compiler.buffer_filters,
+                                                s, False)
+            if buffered or cached:
+                self.printer.writeline("return %s" % s)
+            else:
+                self.printer.writelines(
+                    "__M_writer(%s)" % s,
+                    "return ''"
+                )
+
+    def write_cache_decorator(self, node_or_pagetag, name,
+                              args, buffered, identifiers,
+                              inline=False, toplevel=False):
+        """write a post-function decorator to replace a rendering
+            callable with a cached version of itself."""
+
+        self.printer.writeline("__M_%s = %s" % (name, name))
+        cachekey = node_or_pagetag.parsed_attributes.get('cache_key',
+                                                         repr(name))
+
+        cache_args = {}
+        if self.compiler.pagetag is not None:
+            cache_args.update(
+                (
+                    pa[6:],
+                    self.compiler.pagetag.parsed_attributes[pa]
+                )
+                for pa in self.compiler.pagetag.parsed_attributes
+                if pa.startswith('cache_') and pa != 'cache_key'
+            )
+        cache_args.update(
+            (
+                pa[6:],
+                node_or_pagetag.parsed_attributes[pa]
+            ) for pa in node_or_pagetag.parsed_attributes
+            if pa.startswith('cache_') and pa != 'cache_key'
+        )
+        if 'timeout' in cache_args:
+            cache_args['timeout'] = int(eval(cache_args['timeout']))
+
+        self.printer.writeline("def %s(%s):" % (name, ','.join(args)))
+
+        # form "arg1, arg2, arg3=arg3, arg4=arg4", etc.
+        pass_args = [
+            "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a
+            for a in args
+        ]
+
+        self.write_variable_declares(
+            identifiers,
+            toplevel=toplevel,
+            limit=node_or_pagetag.undeclared_identifiers()
+        )
+        if buffered:
+            s = "context.get('local')."\
+                "cache._ctx_get_or_create("\
+                "%s, lambda:__M_%s(%s),  context, %s__M_defname=%r)" % (
+                    cachekey, name, ','.join(pass_args),
+                    ''.join(["%s=%s, " % (k, v)
+                             for k, v in cache_args.items()]),
+                    name
+                )
+            # apply buffer_filters
+            s = self.create_filter_callable(self.compiler.buffer_filters, s,
+                                            False)
+            self.printer.writelines("return " + s, None)
+        else:
+            self.printer.writelines(
+                "__M_writer(context.get('local')."
+                "cache._ctx_get_or_create("
+                "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
+                (
+                    cachekey, name, ','.join(pass_args),
+                    ''.join(["%s=%s, " % (k, v)
+                             for k, v in cache_args.items()]),
+                    name,
+                ),
+                "return ''",
+                None
+            )
+
+    def create_filter_callable(self, args, target, is_expression):
+        """write a filter-applying expression based on the filters
+        present in the given filter names, adjusting for the global
+        'default' filter aliases as needed."""
+
+        def locate_encode(name):
+            if re.match(r'decode\..+', name):
+                return "filters." + name
+            elif self.compiler.disable_unicode:
+                return filters.NON_UNICODE_ESCAPES.get(name, name)
+            else:
+                return filters.DEFAULT_ESCAPES.get(name, name)
+
+        if 'n' not in args:
+            if is_expression:
+                if self.compiler.pagetag:
+                    args = self.compiler.pagetag.filter_args.args + args
+                if self.compiler.default_filters:
+                    args = self.compiler.default_filters + args
+        for e in args:
+            # if filter given as a function, get just the identifier portion
+            if e == 'n':
+                continue
+            m = re.match(r'(.+?)(\(.*\))', e)
+            if m:
+                ident, fargs = m.group(1, 2)
+                f = locate_encode(ident)
+                e = f + fargs
+            else:
+                e = locate_encode(e)
+                assert e is not None
+            target = "%s(%s)" % (e, target)
+        return target
+
+    def visitExpression(self, node):
+        self.printer.start_source(node.lineno)
+        if len(node.escapes) or \
+                (
+                    self.compiler.pagetag is not None and
+                    len(self.compiler.pagetag.filter_args.args)
+        ) or \
+                len(self.compiler.default_filters):
+
+            s = self.create_filter_callable(node.escapes_code.args,
+                                            "%s" % node.text, True)
+            self.printer.writeline("__M_writer(%s)" % s)
+        else:
+            self.printer.writeline("__M_writer(%s)" % node.text)
+
+    def visitControlLine(self, node):
+        if node.isend:
+            self.printer.writeline(None)
+            if node.has_loop_context:
+                self.printer.writeline('finally:')
+                self.printer.writeline("loop = __M_loop._exit()")
+                self.printer.writeline(None)
+        else:
+            self.printer.start_source(node.lineno)
+            if self.compiler.enable_loop and node.keyword == 'for':
+                text = mangle_mako_loop(node, self.printer)
+            else:
+                text = node.text
+            self.printer.writeline(text)
+            children = node.get_children()
+            # this covers the three situations where we want to insert a pass:
+            #    1) a ternary control line with no children,
+            #    2) a primary control line with nothing but its own ternary
+            #          and end control lines, and
+            #    3) any control line with no content other than comments
+            if not children or (
+                    compat.all(isinstance(c, (parsetree.Comment,
+                                              parsetree.ControlLine))
+                               for c in children) and
+                    compat.all((node.is_ternary(c.keyword) or c.isend)
+                               for c in children
+                               if isinstance(c, parsetree.ControlLine))):
+                self.printer.writeline("pass")
+
+    def visitText(self, node):
+        self.printer.start_source(node.lineno)
+        self.printer.writeline("__M_writer(%s)" % repr(node.content))
+
+    def visitTextTag(self, node):
+        filtered = len(node.filter_args.args) > 0
+        if filtered:
+            self.printer.writelines(
+                "__M_writer = context._push_writer()",
+                "try:",
+            )
+        for n in node.nodes:
+            n.accept_visitor(self)
+        if filtered:
+            self.printer.writelines(
+                "finally:",
+                "__M_buf, __M_writer = context._pop_buffer_and_writer()",
+                "__M_writer(%s)" %
+                self.create_filter_callable(
+                    node.filter_args.args,
+                    "__M_buf.getvalue()",
+                    False),
+                None
+            )
+
+    def visitCode(self, node):
+        if not node.ismodule:
+            self.printer.start_source(node.lineno)
+            self.printer.write_indented_block(node.text)
+
+            if not self.in_def and len(self.identifiers.locally_assigned) > 0:
+                # if we are the "template" def, fudge locally
+                # declared/modified variables into the "__M_locals" dictionary,
+                # which is used for def calls within the same template,
+                # to simulate "enclosing scope"
+                self.printer.writeline(
+                    '__M_locals_builtin_stored = __M_locals_builtin()')
+                self.printer.writeline(
+                    '__M_locals.update(__M_dict_builtin([(__M_key,'
+                    ' __M_locals_builtin_stored[__M_key]) for __M_key in'
+                    ' [%s] if __M_key in __M_locals_builtin_stored]))' %
+                    ','.join([repr(x) for x in node.declared_identifiers()]))
+
+    def visitIncludeTag(self, node):
+        self.printer.start_source(node.lineno)
+        args = node.attributes.get('args')
+        if args:
+            self.printer.writeline(
+                "runtime._include_file(context, %s, _template_uri, %s)" %
+                (node.parsed_attributes['file'], args))
+        else:
+            self.printer.writeline(
+                "runtime._include_file(context, %s, _template_uri)" %
+                (node.parsed_attributes['file']))
+
+    def visitNamespaceTag(self, node):
+        pass
+
+    def visitDefTag(self, node):
+        pass
+
+    def visitBlockTag(self, node):
+        if node.is_anonymous:
+            self.printer.writeline("%s()" % node.funcname)
+        else:
+            nameargs = node.get_argument_expressions(as_call=True)
+            nameargs += ['**pageargs']
+            self.printer.writeline(
+                "if 'parent' not in context._data or "
+                "not hasattr(context._data['parent'], '%s'):"
+                % node.funcname)
+            self.printer.writeline(
+                "context['self'].%s(%s)" % (node.funcname, ",".join(nameargs)))
+            self.printer.writeline("\n")
+
+    def visitCallNamespaceTag(self, node):
+        # TODO: we can put namespace-specific checks here, such
+        # as ensure the given namespace will be imported,
+        # pre-import the namespace, etc.
+        self.visitCallTag(node)
+
+    def visitCallTag(self, node):
+        self.printer.writeline("def ccall(caller):")
+        export = ['body']
+        callable_identifiers = self.identifiers.branch(node, nested=True)
+        body_identifiers = callable_identifiers.branch(node, nested=False)
+        # we want the 'caller' passed to ccall to be used
+        # for the body() function, but for other non-body()
+        # <%def>s within <%call> we want the current caller
+        # off the call stack (if any)
+        body_identifiers.add_declared('caller')
+
+        self.identifier_stack.append(body_identifiers)
+
+        class DefVisitor(object):
+
+            def visitDefTag(s, node):
+                s.visitDefOrBase(node)
+
+            def visitBlockTag(s, node):
+                s.visitDefOrBase(node)
+
+            def visitDefOrBase(s, node):
+                self.write_inline_def(node, callable_identifiers, nested=False)
+                if not node.is_anonymous:
+                    export.append(node.funcname)
+                # remove defs that are within the <%call> from the
+                # "closuredefs" defined in the body, so they dont render twice
+                if node.funcname in body_identifiers.closuredefs:
+                    del body_identifiers.closuredefs[node.funcname]
+
+        vis = DefVisitor()
+        for n in node.nodes:
+            n.accept_visitor(vis)
+        self.identifier_stack.pop()
+
+        bodyargs = node.body_decl.get_argument_expressions()
+        self.printer.writeline("def body(%s):" % ','.join(bodyargs))
+
+        # TODO: figure out best way to specify
+        # buffering/nonbuffering (at call time would be better)
+        buffered = False
+        if buffered:
+            self.printer.writelines(
+                "context._push_buffer()",
+                "try:"
+            )
+        self.write_variable_declares(body_identifiers)
+        self.identifier_stack.append(body_identifiers)
+
+        for n in node.nodes:
+            n.accept_visitor(self)
+        self.identifier_stack.pop()
+
+        self.write_def_finish(node, buffered, False, False, callstack=False)
+        self.printer.writelines(
+            None,
+            "return [%s]" % (','.join(export)),
+            None
+        )
+
+        self.printer.writelines(
+            # push on caller for nested call
+            "context.caller_stack.nextcaller = "
+            "runtime.Namespace('caller', context, "
+            "callables=ccall(__M_caller))",
+            "try:")
+        self.printer.start_source(node.lineno)
+        self.printer.writelines(
+            "__M_writer(%s)" % self.create_filter_callable(
+                [], node.expression, True),
+            "finally:",
+            "context.caller_stack.nextcaller = None",
+            None
+        )
+
+
+class _Identifiers(object):
+
+    """tracks the status of identifier names as template code is rendered."""
+
+    def __init__(self, compiler, node=None, parent=None, nested=False):
+        if parent is not None:
+            # if we are the branch created in write_namespaces(),
+            # we don't share any context from the main body().
+            if isinstance(node, parsetree.NamespaceTag):
+                self.declared = set()
+                self.topleveldefs = util.SetLikeDict()
+            else:
+                # things that have already been declared
+                # in an enclosing namespace (i.e. names we can just use)
+                self.declared = set(parent.declared).\
+                    union([c.name for c in parent.closuredefs.values()]).\
+                    union(parent.locally_declared).\
+                    union(parent.argument_declared)
+
+                # if these identifiers correspond to a "nested"
+                # scope, it means whatever the parent identifiers
+                # had as undeclared will have been declared by that parent,
+                # and therefore we have them in our scope.
+                if nested:
+                    self.declared = self.declared.union(parent.undeclared)
+
+                # top level defs that are available
+                self.topleveldefs = util.SetLikeDict(**parent.topleveldefs)
+        else:
+            self.declared = set()
+            self.topleveldefs = util.SetLikeDict()
+
+        self.compiler = compiler
+
+        # things within this level that are referenced before they
+        # are declared (e.g. assigned to)
+        self.undeclared = set()
+
+        # things that are declared locally.  some of these things
+        # could be in the "undeclared" list as well if they are
+        # referenced before declared
+        self.locally_declared = set()
+
+        # assignments made in explicit python blocks.
+        # these will be propagated to
+        # the context of local def calls.
+        self.locally_assigned = set()
+
+        # things that are declared in the argument
+        # signature of the def callable
+        self.argument_declared = set()
+
+        # closure defs that are defined in this level
+        self.closuredefs = util.SetLikeDict()
+
+        self.node = node
+
+        if node is not None:
+            node.accept_visitor(self)
+
+        illegal_names = self.compiler.reserved_names.intersection(
+            self.locally_declared)
+        if illegal_names:
+            raise exceptions.NameConflictError(
+                "Reserved words declared in template: %s" %
+                ", ".join(illegal_names))
+
+    def branch(self, node, **kwargs):
+        """create a new Identifiers for a new Node, with
+          this Identifiers as the parent."""
+
+        return _Identifiers(self.compiler, node, self, **kwargs)
+
+    @property
+    def defs(self):
+        return set(self.topleveldefs.union(self.closuredefs).values())
+
+    def __repr__(self):
+        return "Identifiers(declared=%r, locally_declared=%r, "\
+            "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\
+            "argumentdeclared=%r)" %\
+            (
+                list(self.declared),
+                list(self.locally_declared),
+                list(self.undeclared),
+                [c.name for c in self.topleveldefs.values()],
+                [c.name for c in self.closuredefs.values()],
+                self.argument_declared)
+
+    def check_declared(self, node):
+        """update the state of this Identifiers with the undeclared
+            and declared identifiers of the given node."""
+
+        for ident in node.undeclared_identifiers():
+            if ident != 'context' and\
+                    ident not in self.declared.union(self.locally_declared):
+                self.undeclared.add(ident)
+        for ident in node.declared_identifiers():
+            self.locally_declared.add(ident)
+
+    def add_declared(self, ident):
+        self.declared.add(ident)
+        if ident in self.undeclared:
+            self.undeclared.remove(ident)
+
+    def visitExpression(self, node):
+        self.check_declared(node)
+
+    def visitControlLine(self, node):
+        self.check_declared(node)
+
+    def visitCode(self, node):
+        if not node.ismodule:
+            self.check_declared(node)
+            self.locally_assigned = self.locally_assigned.union(
+                node.declared_identifiers())
+
+    def visitNamespaceTag(self, node):
+        # only traverse into the sub-elements of a
+        # <%namespace> tag if we are the branch created in
+        # write_namespaces()
+        if self.node is node:
+            for n in node.nodes:
+                n.accept_visitor(self)
+
+    def _check_name_exists(self, collection, node):
+        existing = collection.get(node.funcname)
+        collection[node.funcname] = node
+        if existing is not None and \
+                existing is not node and \
+                (node.is_block or existing.is_block):
+            raise exceptions.CompileException(
+                "%%def or %%block named '%s' already "
+                "exists in this template." %
+                node.funcname, **node.exception_kwargs)
+
+    def visitDefTag(self, node):
+        if node.is_root() and not node.is_anonymous:
+            self._check_name_exists(self.topleveldefs, node)
+        elif node is not self.node:
+            self._check_name_exists(self.closuredefs, node)
+
+        for ident in node.undeclared_identifiers():
+            if ident != 'context' and \
+                    ident not in self.declared.union(self.locally_declared):
+                self.undeclared.add(ident)
+
+        # visit defs only one level deep
+        if node is self.node:
+            for ident in node.declared_identifiers():
+                self.argument_declared.add(ident)
+
+            for n in node.nodes:
+                n.accept_visitor(self)
+
+    def visitBlockTag(self, node):
+        if node is not self.node and not node.is_anonymous:
+
+            if isinstance(self.node, parsetree.DefTag):
+                raise exceptions.CompileException(
+                    "Named block '%s' not allowed inside of def '%s'"
+                    % (node.name, self.node.name), **node.exception_kwargs)
+            elif isinstance(self.node,
+                            (parsetree.CallTag, parsetree.CallNamespaceTag)):
+                raise exceptions.CompileException(
+                    "Named block '%s' not allowed inside of <%%call> tag"
+                    % (node.name, ), **node.exception_kwargs)
+
+        for ident in node.undeclared_identifiers():
+            if ident != 'context' and \
+                    ident not in self.declared.union(self.locally_declared):
+                self.undeclared.add(ident)
+
+        if not node.is_anonymous:
+            self._check_name_exists(self.topleveldefs, node)
+            self.undeclared.add(node.funcname)
+        elif node is not self.node:
+            self._check_name_exists(self.closuredefs, node)
+        for ident in node.declared_identifiers():
+            self.argument_declared.add(ident)
+        for n in node.nodes:
+            n.accept_visitor(self)
+
+    def visitTextTag(self, node):
+        for ident in node.undeclared_identifiers():
+            if ident != 'context' and \
+                    ident not in self.declared.union(self.locally_declared):
+                self.undeclared.add(ident)
+
+    def visitIncludeTag(self, node):
+        self.check_declared(node)
+
+    def visitPageTag(self, node):
+        for ident in node.declared_identifiers():
+            self.argument_declared.add(ident)
+        self.check_declared(node)
+
+    def visitCallNamespaceTag(self, node):
+        self.visitCallTag(node)
+
+    def visitCallTag(self, node):
+        if node is self.node:
+            for ident in node.undeclared_identifiers():
+                if ident != 'context' and \
+                        ident not in self.declared.union(
+                            self.locally_declared):
+                    self.undeclared.add(ident)
+            for ident in node.declared_identifiers():
+                self.argument_declared.add(ident)
+            for n in node.nodes:
+                n.accept_visitor(self)
+        else:
+            for ident in node.undeclared_identifiers():
+                if ident != 'context' and \
+                        ident not in self.declared.union(
+                            self.locally_declared):
+                    self.undeclared.add(ident)
+
+
+_FOR_LOOP = re.compile(
+    r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*'
+    r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):'
+)
+
+
+def mangle_mako_loop(node, printer):
+    """converts a for loop into a context manager wrapped around a for loop
+    when access to the `loop` variable has been detected in the for loop body
+    """
+    loop_variable = LoopVariable()
+    node.accept_visitor(loop_variable)
+    if loop_variable.detected:
+        node.nodes[-1].has_loop_context = True
+        match = _FOR_LOOP.match(node.text)
+        if match:
+            printer.writelines(
+                'loop = __M_loop._enter(%s)' % match.group(2),
+                'try:'
+                # 'with __M_loop(%s) as loop:' % match.group(2)
+            )
+            text = 'for %s in loop:' % match.group(1)
+        else:
+            raise SyntaxError("Couldn't apply loop context: %s" % node.text)
+    else:
+        text = node.text
+    return text
+
+
+class LoopVariable(object):
+
+    """A node visitor which looks for the name 'loop' within undeclared
+    identifiers."""
+
+    def __init__(self):
+        self.detected = False
+
+    def _loop_reference_detected(self, node):
+        if 'loop' in node.undeclared_identifiers():
+            self.detected = True
+        else:
+            for n in node.get_children():
+                n.accept_visitor(self)
+
+    def visitControlLine(self, node):
+        self._loop_reference_detected(node)
+
+    def visitCode(self, node):
+        self._loop_reference_detected(node)
+
+    def visitExpression(self, node):
+        self._loop_reference_detected(node)
diff --git a/mako/compat.py b/mako/compat.py
new file mode 100644 (file)
index 0000000..a2ab243
--- /dev/null
@@ -0,0 +1,201 @@
+import sys
+import time
+
+py3k = sys.version_info >= (3, 0)
+py33 = sys.version_info >= (3, 3)
+py2k = sys.version_info < (3,)
+py26 = sys.version_info >= (2, 6)
+py27 = sys.version_info >= (2, 7)
+jython = sys.platform.startswith('java')
+win32 = sys.platform.startswith('win')
+pypy = hasattr(sys, 'pypy_version_info')
+
+if py3k:
+    # create a "getargspec" from getfullargspec(), which is not deprecated
+    # in Py3K; getargspec() has started to emit warnings as of Py3.5.
+    # As of Py3.4, now they are trying to move from getfullargspec()
+    # to "signature()", but getfullargspec() is not deprecated, so stick
+    # with that for now.
+
+    import collections
+    ArgSpec = collections.namedtuple(
+        "ArgSpec",
+        ["args", "varargs", "keywords", "defaults"])
+    from inspect import getfullargspec as inspect_getfullargspec
+
+    def inspect_getargspec(func):
+        return ArgSpec(
+            *inspect_getfullargspec(func)[0:4]
+        )
+else:
+    from inspect import getargspec as inspect_getargspec  # noqa
+
+
+if py3k:
+    from io import StringIO
+    import builtins as compat_builtins
+    from urllib.parse import quote_plus, unquote_plus
+    from html.entities import codepoint2name, name2codepoint
+    string_types = str,
+    binary_type = bytes
+    text_type = str
+
+    from io import BytesIO as byte_buffer
+
+    def u(s):
+        return s
+
+    def b(s):
+        return s.encode("latin-1")
+
+    def octal(lit):
+        return eval("0o" + lit)
+
+else:
+    import __builtin__ as compat_builtins  # noqa
+    try:
+        from cStringIO import StringIO
+    except:
+        from StringIO import StringIO
+
+    byte_buffer = StringIO
+
+    from urllib import quote_plus, unquote_plus  # noqa
+    from htmlentitydefs import codepoint2name, name2codepoint  # noqa
+    string_types = basestring,  # noqa
+    binary_type = str
+    text_type = unicode  # noqa
+
+    def u(s):
+        return unicode(s, "utf-8")  # noqa
+
+    def b(s):
+        return s
+
+    def octal(lit):
+        return eval("0" + lit)
+
+
+if py33:
+    from importlib import machinery
+
+    def load_module(module_id, path):
+        return machinery.SourceFileLoader(module_id, path).load_module()
+else:
+    import imp
+
+    def load_module(module_id, path):
+        fp = open(path, 'rb')
+        try:
+            return imp.load_source(module_id, path, fp)
+        finally:
+            fp.close()
+
+
+if py3k:
+    def reraise(tp, value, tb=None, cause=None):
+        if cause is not None:
+            value.__cause__ = cause
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+else:
+    exec("def reraise(tp, value, tb=None, cause=None):\n"
+         "    raise tp, value, tb\n")
+
+
+def exception_as():
+    return sys.exc_info()[1]
+
+try:
+    import threading
+    if py3k:
+        import _thread as thread
+    else:
+        import thread
+except ImportError:
+    import dummy_threading as threading  # noqa
+    if py3k:
+        import _dummy_thread as thread
+    else:
+        import dummy_thread as thread  # noqa
+
+if win32 or jython:
+    time_func = time.clock
+else:
+    time_func = time.time
+
+try:
+    from functools import partial
+except:
+    def partial(func, *args, **keywords):
+        def newfunc(*fargs, **fkeywords):
+            newkeywords = keywords.copy()
+            newkeywords.update(fkeywords)
+            return func(*(args + fargs), **newkeywords)
+        return newfunc
+
+
+all = all
+import json  # noqa
+
+
+def exception_name(exc):
+    return exc.__class__.__name__
+
+try:
+    from inspect import CO_VARKEYWORDS, CO_VARARGS
+
+    def inspect_func_args(fn):
+        if py3k:
+            co = fn.__code__
+        else:
+            co = fn.func_code
+
+        nargs = co.co_argcount
+        names = co.co_varnames
+        args = list(names[:nargs])
+
+        varargs = None
+        if co.co_flags & CO_VARARGS:
+            varargs = co.co_varnames[nargs]
+            nargs = nargs + 1
+        varkw = None
+        if co.co_flags & CO_VARKEYWORDS:
+            varkw = co.co_varnames[nargs]
+
+        if py3k:
+            return args, varargs, varkw, fn.__defaults__
+        else:
+            return args, varargs, varkw, fn.func_defaults
+except ImportError:
+    import inspect
+
+    def inspect_func_args(fn):
+        return inspect.getargspec(fn)
+
+if py3k:
+    def callable(fn):
+        return hasattr(fn, '__call__')
+else:
+    callable = callable
+
+
+################################################
+# cross-compatible metaclass implementation
+# Copyright (c) 2010-2012 Benjamin Peterson
+def with_metaclass(meta, base=object):
+    """Create a base class with a metaclass."""
+    return meta("%sBase" % meta.__name__, (base,), {})
+################################################
+
+
+def arg_stringname(func_arg):
+    """Gets the string name of a kwarg or vararg
+    In Python3.4 a function's args are
+    of _ast.arg type not _ast.name
+    """
+    if hasattr(func_arg, 'arg'):
+        return func_arg.arg
+    else:
+        return str(func_arg)
diff --git a/mako/exceptions.py b/mako/exceptions.py
new file mode 100644 (file)
index 0000000..cb6fb3f
--- /dev/null
@@ -0,0 +1,394 @@
+# mako/exceptions.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""exception classes"""
+
+import traceback
+import sys
+from mako import util, compat
+
+
+class MakoException(Exception):
+    pass
+
+
+class RuntimeException(MakoException):
+    pass
+
+
+def _format_filepos(lineno, pos, filename):
+    if filename is None:
+        return " at line: %d char: %d" % (lineno, pos)
+    else:
+        return " in file '%s' at line: %d char: %d" % (filename, lineno, pos)
+
+
+class CompileException(MakoException):
+
+    def __init__(self, message, source, lineno, pos, filename):
+        MakoException.__init__(
+            self,
+            message + _format_filepos(lineno, pos, filename))
+        self.lineno = lineno
+        self.pos = pos
+        self.filename = filename
+        self.source = source
+
+
+class SyntaxException(MakoException):
+
+    def __init__(self, message, source, lineno, pos, filename):
+        MakoException.__init__(
+            self,
+            message + _format_filepos(lineno, pos, filename))
+        self.lineno = lineno
+        self.pos = pos
+        self.filename = filename
+        self.source = source
+
+
+class UnsupportedError(MakoException):
+
+    """raised when a retired feature is used."""
+
+
+class NameConflictError(MakoException):
+
+    """raised when a reserved word is used inappropriately"""
+
+
+class TemplateLookupException(MakoException):
+    pass
+
+
+class TopLevelLookupException(TemplateLookupException):
+    pass
+
+
+class RichTraceback(object):
+
+    """Pull the current exception from the ``sys`` traceback and extracts
+    Mako-specific template information.
+
+    See the usage examples in :ref:`handling_exceptions`.
+
+    """
+
+    def __init__(self, error=None, traceback=None):
+        self.source, self.lineno = "", 0
+
+        if error is None or traceback is None:
+            t, value, tback = sys.exc_info()
+
+        if error is None:
+            error = value or t
+
+        if traceback is None:
+            traceback = tback
+
+        self.error = error
+        self.records = self._init(traceback)
+
+        if isinstance(self.error, (CompileException, SyntaxException)):
+            self.source = self.error.source
+            self.lineno = self.error.lineno
+            self._has_source = True
+
+        self._init_message()
+
+    @property
+    def errorname(self):
+        return compat.exception_name(self.error)
+
+    def _init_message(self):
+        """Find a unicode representation of self.error"""
+        try:
+            self.message = compat.text_type(self.error)
+        except UnicodeError:
+            try:
+                self.message = str(self.error)
+            except UnicodeEncodeError:
+                # Fallback to args as neither unicode nor
+                # str(Exception(u'\xe6')) work in Python < 2.6
+                self.message = self.error.args[0]
+        if not isinstance(self.message, compat.text_type):
+            self.message = compat.text_type(self.message, 'ascii', 'replace')
+
+    def _get_reformatted_records(self, records):
+        for rec in records:
+            if rec[6] is not None:
+                yield (rec[4], rec[5], rec[2], rec[6])
+            else:
+                yield tuple(rec[0:4])
+
+    @property
+    def traceback(self):
+        """Return a list of 4-tuple traceback records (i.e. normal python
+        format) with template-corresponding lines remapped to the originating
+        template.
+
+        """
+        return list(self._get_reformatted_records(self.records))
+
+    @property
+    def reverse_records(self):
+        return reversed(self.records)
+
+    @property
+    def reverse_traceback(self):
+        """Return the same data as traceback, except in reverse order.
+        """
+
+        return list(self._get_reformatted_records(self.reverse_records))
+
+    def _init(self, trcback):
+        """format a traceback from sys.exc_info() into 7-item tuples,
+        containing the regular four traceback tuple items, plus the original
+        template filename, the line number adjusted relative to the template
+        source, and code line from that line number of the template."""
+
+        import mako.template
+        mods = {}
+        rawrecords = traceback.extract_tb(trcback)
+        new_trcback = []
+        for filename, lineno, function, line in rawrecords:
+            if not line:
+                line = ''
+            try:
+                (line_map, template_lines) = mods[filename]
+            except KeyError:
+                try:
+                    info = mako.template._get_module_info(filename)
+                    module_source = info.code
+                    template_source = info.source
+                    template_filename = info.template_filename or filename
+                except KeyError:
+                    # A normal .py file (not a Template)
+                    if not compat.py3k:
+                        try:
+                            fp = open(filename, 'rb')
+                            encoding = util.parse_encoding(fp)
+                            fp.close()
+                        except IOError:
+                            encoding = None
+                        if encoding:
+                            line = line.decode(encoding)
+                        else:
+                            line = line.decode('ascii', 'replace')
+                    new_trcback.append((filename, lineno, function, line,
+                                        None, None, None, None))
+                    continue
+
+                template_ln = 1
+
+                source_map = mako.template.ModuleInfo.\
+                    get_module_source_metadata(
+                        module_source, full_line_map=True)
+                line_map = source_map['full_line_map']
+
+                template_lines = [line_ for line_ in
+                                  template_source.split("\n")]
+                mods[filename] = (line_map, template_lines)
+
+            template_ln = line_map[lineno - 1]
+
+            if template_ln <= len(template_lines):
+                template_line = template_lines[template_ln - 1]
+            else:
+                template_line = None
+            new_trcback.append((filename, lineno, function,
+                                line, template_filename, template_ln,
+                                template_line, template_source))
+        if not self.source:
+            for l in range(len(new_trcback) - 1, 0, -1):
+                if new_trcback[l][5]:
+                    self.source = new_trcback[l][7]
+                    self.lineno = new_trcback[l][5]
+                    break
+            else:
+                if new_trcback:
+                    try:
+                        # A normal .py file (not a Template)
+                        fp = open(new_trcback[-1][0], 'rb')
+                        encoding = util.parse_encoding(fp)
+                        fp.seek(0)
+                        self.source = fp.read()
+                        fp.close()
+                        if encoding:
+                            self.source = self.source.decode(encoding)
+                    except IOError:
+                        self.source = ''
+                    self.lineno = new_trcback[-1][1]
+        return new_trcback
+
+
+def text_error_template(lookup=None):
+    """Provides a template that renders a stack trace in a similar format to
+    the Python interpreter, substituting source template filenames, line
+    numbers and code for that of the originating source template, as
+    applicable.
+
+    """
+    import mako.template
+    return mako.template.Template(r"""
+<%page args="error=None, traceback=None"/>
+<%!
+    from mako.exceptions import RichTraceback
+%>\
+<%
+    tback = RichTraceback(error=error, traceback=traceback)
+%>\
+Traceback (most recent call last):
+% for (filename, lineno, function, line) in tback.traceback:
+  File "${filename}", line ${lineno}, in ${function or '?'}
+    ${line | trim}
+% endfor
+${tback.errorname}: ${tback.message}
+""")
+
+
+def _install_pygments():
+    global syntax_highlight, pygments_html_formatter
+    from mako.ext.pygmentplugin import syntax_highlight  # noqa
+    from mako.ext.pygmentplugin import pygments_html_formatter  # noqa
+
+
+def _install_fallback():
+    global syntax_highlight, pygments_html_formatter
+    from mako.filters import html_escape
+    pygments_html_formatter = None
+
+    def syntax_highlight(filename='', language=None):
+        return html_escape
+
+
+def _install_highlighting():
+    try:
+        _install_pygments()
+    except ImportError:
+        _install_fallback()
+_install_highlighting()
+
+
+def html_error_template():
+    """Provides a template that renders a stack trace in an HTML format,
+    providing an excerpt of code as well as substituting source template
+    filenames, line numbers and code for that of the originating source
+    template, as applicable.
+
+    The template's default ``encoding_errors`` value is
+    ``'htmlentityreplace'``. The template has two options. With the
+    ``full`` option disabled, only a section of an HTML document is
+    returned. With the ``css`` option disabled, the default stylesheet
+    won't be included.
+
+    """
+    import mako.template
+    return mako.template.Template(r"""
+<%!
+    from mako.exceptions import RichTraceback, syntax_highlight,\
+            pygments_html_formatter
+%>
+<%page args="full=True, css=True, error=None, traceback=None"/>
+% if full:
+<html>
+<head>
+    <title>Mako Runtime Error</title>
+% endif
+% if css:
+    <style>
+        body { font-family:verdana; margin:10px 30px 10px 30px;}
+        .stacktrace { margin:5px 5px 5px 5px; }
+        .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; }
+        .nonhighlight { padding:0px; background-color:#DFDFDF; }
+        .sample { padding:10px; margin:10px 10px 10px 10px;
+                  font-family:monospace; }
+        .sampleline { padding:0px 10px 0px 10px; }
+        .sourceline { margin:5px 5px 10px 5px; font-family:monospace;}
+        .location { font-size:80%; }
+        .highlight { white-space:pre; }
+        .sampleline { white-space:pre; }
+
+    % if pygments_html_formatter:
+        ${pygments_html_formatter.get_style_defs()}
+        .linenos { min-width: 2.5em; text-align: right; }
+        pre { margin: 0; }
+        .syntax-highlighted { padding: 0 10px; }
+        .syntax-highlightedtable { border-spacing: 1px; }
+        .nonhighlight { border-top: 1px solid #DFDFDF;
+                        border-bottom: 1px solid #DFDFDF; }
+        .stacktrace .nonhighlight { margin: 5px 15px 10px; }
+        .sourceline { margin: 0 0; font-family:monospace; }
+        .code { background-color: #F8F8F8; width: 100%; }
+        .error .code { background-color: #FFBDBD; }
+        .error .syntax-highlighted { background-color: #FFBDBD; }
+    % endif
+
+    </style>
+% endif
+% if full:
+</head>
+<body>
+% endif
+
+<h2>Error !</h2>
+<%
+    tback = RichTraceback(error=error, traceback=traceback)
+    src = tback.source
+    line = tback.lineno
+    if src:
+        lines = src.split('\n')
+    else:
+        lines = None
+%>
+<h3>${tback.errorname}: ${tback.message|h}</h3>
+
+% if lines:
+    <div class="sample">
+    <div class="nonhighlight">
+% for index in range(max(0, line-4),min(len(lines), line+5)):
+    <%
+       if pygments_html_formatter:
+           pygments_html_formatter.linenostart = index + 1
+    %>
+    % if index + 1 == line:
+    <%
+       if pygments_html_formatter:
+           old_cssclass = pygments_html_formatter.cssclass
+           pygments_html_formatter.cssclass = 'error ' + old_cssclass
+    %>
+        ${lines[index] | syntax_highlight(language='mako')}
+    <%
+       if pygments_html_formatter:
+           pygments_html_formatter.cssclass = old_cssclass
+    %>
+    % else:
+        ${lines[index] | syntax_highlight(language='mako')}
+    % endif
+% endfor
+    </div>
+    </div>
+% endif
+
+<div class="stacktrace">
+% for (filename, lineno, function, line) in tback.reverse_traceback:
+    <div class="location">${filename}, line ${lineno}:</div>
+    <div class="nonhighlight">
+    <%
+       if pygments_html_formatter:
+           pygments_html_formatter.linenostart = lineno
+    %>
+      <div class="sourceline">${line | syntax_highlight(filename)}</div>
+    </div>
+% endfor
+</div>
+
+% if full:
+</body>
+</html>
+% endif
+""", output_encoding=sys.getdefaultencoding(),
+                                  encoding_errors='htmlentityreplace')
diff --git a/mako/ext/__init__.py b/mako/ext/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/mako/ext/autohandler.py b/mako/ext/autohandler.py
new file mode 100644 (file)
index 0000000..9d1c911
--- /dev/null
@@ -0,0 +1,68 @@
+# ext/autohandler.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""adds autohandler functionality to Mako templates.
+
+requires that the TemplateLookup class is used with templates.
+
+usage:
+
+<%!
+    from mako.ext.autohandler import autohandler
+%>
+<%inherit file="${autohandler(template, context)}"/>
+
+
+or with custom autohandler filename:
+
+<%!
+    from mako.ext.autohandler import autohandler
+%>
+<%inherit file="${autohandler(template, context, name='somefilename')}"/>
+
+"""
+
+import posixpath
+import os
+import re
+
+
+def autohandler(template, context, name='autohandler'):
+    lookup = context.lookup
+    _template_uri = template.module._template_uri
+    if not lookup.filesystem_checks:
+        try:
+            return lookup._uri_cache[(autohandler, _template_uri, name)]
+        except KeyError:
+            pass
+
+    tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name]
+    while len(tokens):
+        path = '/' + '/'.join(tokens)
+        if path != _template_uri and _file_exists(lookup, path):
+            if not lookup.filesystem_checks:
+                return lookup._uri_cache.setdefault(
+                    (autohandler, _template_uri, name), path)
+            else:
+                return path
+        if len(tokens) == 1:
+            break
+        tokens[-2:] = [name]
+
+    if not lookup.filesystem_checks:
+        return lookup._uri_cache.setdefault(
+            (autohandler, _template_uri, name), None)
+    else:
+        return None
+
+
+def _file_exists(lookup, path):
+    psub = re.sub(r'^/', '', path)
+    for d in lookup.directories:
+        if os.path.exists(d + '/' + psub):
+            return True
+    else:
+        return False
diff --git a/mako/ext/babelplugin.py b/mako/ext/babelplugin.py
new file mode 100644 (file)
index 0000000..0b5e84f
--- /dev/null
@@ -0,0 +1,50 @@
+# ext/babelplugin.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""gettext message extraction via Babel: http://babel.edgewall.org/"""
+from babel.messages.extract import extract_python
+from mako.ext.extract import MessageExtractor
+
+
+class BabelMakoExtractor(MessageExtractor):
+
+    def __init__(self, keywords, comment_tags, options):
+        self.keywords = keywords
+        self.options = options
+        self.config = {
+            'comment-tags': u' '.join(comment_tags),
+            'encoding': options.get('input_encoding',
+                                    options.get('encoding', None)),
+        }
+        super(BabelMakoExtractor, self).__init__()
+
+    def __call__(self, fileobj):
+        return self.process_file(fileobj)
+
+    def process_python(self, code, code_lineno, translator_strings):
+        comment_tags = self.config['comment-tags']
+        for lineno, funcname, messages, python_translator_comments \
+                in extract_python(code,
+                                  self.keywords, comment_tags, self.options):
+            yield (code_lineno + (lineno - 1), funcname, messages,
+                   translator_strings + python_translator_comments)
+
+
+def extract(fileobj, keywords, comment_tags, options):
+    """Extract messages from Mako templates.
+
+    :param fileobj: the file-like object the messages should be extracted from
+    :param keywords: a list of keywords (i.e. function names) that should be
+                     recognized as translation functions
+    :param comment_tags: a list of translator tags to search for and include
+                         in the results
+    :param options: a dictionary of additional options (optional)
+    :return: an iterator over ``(lineno, funcname, message, comments)`` tuples
+    :rtype: ``iterator``
+    """
+    extractor = BabelMakoExtractor(keywords, comment_tags, options)
+    for message in extractor(fileobj):
+        yield message
diff --git a/mako/ext/beaker_cache.py b/mako/ext/beaker_cache.py
new file mode 100644 (file)
index 0000000..c7c260d
--- /dev/null
@@ -0,0 +1,76 @@
+"""Provide a :class:`.CacheImpl` for the Beaker caching system."""
+
+from mako import exceptions
+
+from mako.cache import CacheImpl
+
+try:
+    from beaker import cache as beaker_cache
+except:
+    has_beaker = False
+else:
+    has_beaker = True
+
+_beaker_cache = None
+
+
+class BeakerCacheImpl(CacheImpl):
+
+    """A :class:`.CacheImpl` provided for the Beaker caching system.
+
+    This plugin is used by default, based on the default
+    value of ``'beaker'`` for the ``cache_impl`` parameter of the
+    :class:`.Template` or :class:`.TemplateLookup` classes.
+
+    """
+
+    def __init__(self, cache):
+        if not has_beaker:
+            raise exceptions.RuntimeException(
+                "Can't initialize Beaker plugin; Beaker is not installed.")
+        global _beaker_cache
+        if _beaker_cache is None:
+            if 'manager' in cache.template.cache_args:
+                _beaker_cache = cache.template.cache_args['manager']
+            else:
+                _beaker_cache = beaker_cache.CacheManager()
+        super(BeakerCacheImpl, self).__init__(cache)
+
+    def _get_cache(self, **kw):
+        expiretime = kw.pop('timeout', None)
+        if 'dir' in kw:
+            kw['data_dir'] = kw.pop('dir')
+        elif self.cache.template.module_directory:
+            kw['data_dir'] = self.cache.template.module_directory
+
+        if 'manager' in kw:
+            kw.pop('manager')
+
+        if kw.get('type') == 'memcached':
+            kw['type'] = 'ext:memcached'
+
+        if 'region' in kw:
+            region = kw.pop('region')
+            cache = _beaker_cache.get_cache_region(self.cache.id, region, **kw)
+        else:
+            cache = _beaker_cache.get_cache(self.cache.id, **kw)
+        cache_args = {'starttime': self.cache.starttime}
+        if expiretime:
+            cache_args['expiretime'] = expiretime
+        return cache, cache_args
+
+    def get_or_create(self, key, creation_function, **kw):
+        cache, kw = self._get_cache(**kw)
+        return cache.get(key, createfunc=creation_function, **kw)
+
+    def put(self, key, value, **kw):
+        cache, kw = self._get_cache(**kw)
+        cache.put(key, value, **kw)
+
+    def get(self, key, **kw):
+        cache, kw = self._get_cache(**kw)
+        return cache.get(key, **kw)
+
+    def invalidate(self, key, **kw):
+        cache, kw = self._get_cache(**kw)
+        cache.remove_value(key, **kw)
diff --git a/mako/ext/extract.py b/mako/ext/extract.py
new file mode 100644 (file)
index 0000000..8dd2e96
--- /dev/null
@@ -0,0 +1,108 @@
+import re
+from mako import compat
+from mako import lexer
+from mako import parsetree
+
+
+class MessageExtractor(object):
+
+    def process_file(self, fileobj):
+        template_node = lexer.Lexer(
+            fileobj.read(),
+            input_encoding=self.config['encoding']).parse()
+        for extracted in self.extract_nodes(template_node.get_children()):
+            yield extracted
+
+    def extract_nodes(self, nodes):
+        translator_comments = []
+        in_translator_comments = False
+        input_encoding = self.config['encoding'] or 'ascii'
+        comment_tags = list(
+            filter(None, re.split(r'\s+', self.config['comment-tags'])))
+
+        for node in nodes:
+            child_nodes = None
+            if in_translator_comments and \
+                    isinstance(node, parsetree.Text) and \
+                    not node.content.strip():
+                # Ignore whitespace within translator comments
+                continue
+
+            if isinstance(node, parsetree.Comment):
+                value = node.text.strip()
+                if in_translator_comments:
+                    translator_comments.extend(
+                        self._split_comment(node.lineno, value))
+                    continue
+                for comment_tag in comment_tags:
+                    if value.startswith(comment_tag):
+                        in_translator_comments = True
+                        translator_comments.extend(
+                            self._split_comment(node.lineno, value))
+                continue
+
+            if isinstance(node, parsetree.DefTag):
+                code = node.function_decl.code
+                child_nodes = node.nodes
+            elif isinstance(node, parsetree.BlockTag):
+                code = node.body_decl.code
+                child_nodes = node.nodes
+            elif isinstance(node, parsetree.CallTag):
+                code = node.code.code
+                child_nodes = node.nodes
+            elif isinstance(node, parsetree.PageTag):
+                code = node.body_decl.code
+            elif isinstance(node, parsetree.CallNamespaceTag):
+                code = node.expression
+                child_nodes = node.nodes
+            elif isinstance(node, parsetree.ControlLine):
+                if node.isend:
+                    in_translator_comments = False
+                    continue
+                code = node.text
+            elif isinstance(node, parsetree.Code):
+                in_translator_comments = False
+                code = node.code.code
+            elif isinstance(node, parsetree.Expression):
+                code = node.code.code
+            else:
+                continue
+
+            # Comments don't apply unless they immediately preceed the message
+            if translator_comments and \
+                    translator_comments[-1][0] < node.lineno - 1:
+                translator_comments = []
+
+            translator_strings = [
+                comment[1] for comment in translator_comments]
+
+            if isinstance(code, compat.text_type):
+                code = code.encode(input_encoding, 'backslashreplace')
+
+            used_translator_comments = False
+            # We add extra newline to work around a pybabel bug
+            # (see python-babel/babel#274, parse_encoding dies if the first
+            # input string of the input is non-ascii)
+            # Also, because we added it, we have to subtract one from
+            # node.lineno
+            code = compat.byte_buffer(compat.b('\n') + code)
+
+            for message in self.process_python(
+                    code, node.lineno - 1, translator_strings):
+                yield message
+                used_translator_comments = True
+
+            if used_translator_comments:
+                translator_comments = []
+            in_translator_comments = False
+
+            if child_nodes:
+                for extracted in self.extract_nodes(child_nodes):
+                    yield extracted
+
+    @staticmethod
+    def _split_comment(lineno, comment):
+        """Return the multiline comment at lineno split into a list of
+        comment line numbers and the accompanying comment line"""
+        return [(lineno + index, line) for index, line in
+                enumerate(comment.splitlines())]
diff --git a/mako/ext/linguaplugin.py b/mako/ext/linguaplugin.py
new file mode 100644 (file)
index 0000000..46b0d6a
--- /dev/null
@@ -0,0 +1,43 @@
+import io
+from lingua.extractors import Extractor
+from lingua.extractors import Message
+from lingua.extractors import get_extractor
+from mako.ext.extract import MessageExtractor
+from mako import compat
+
+
+class LinguaMakoExtractor(Extractor, MessageExtractor):
+
+    '''Mako templates'''
+    extensions = ['.mako']
+    default_config = {
+        'encoding': 'utf-8',
+        'comment-tags': '',
+    }
+
+    def __call__(self, filename, options, fileobj=None):
+        self.options = options
+        self.filename = filename
+        self.python_extractor = get_extractor('x.py')
+        if fileobj is None:
+            fileobj = open(filename, 'rb')
+        return self.process_file(fileobj)
+
+    def process_python(self, code, code_lineno, translator_strings):
+        source = code.getvalue().strip()
+        if source.endswith(compat.b(':')):
+            if source in (compat.b('try:'), compat.b('else:')) or source.startswith(compat.b('except')):
+                source = compat.b('') # Ignore try/except and else
+            elif source.startswith(compat.b('elif')):
+                source = source[2:] # Replace "elif" with "if"
+            source += compat.b('pass')
+        code = io.BytesIO(source)
+        for msg in self.python_extractor(
+                self.filename, self.options, code, code_lineno -1):
+            if translator_strings:
+                msg = Message(msg.msgctxt, msg.msgid, msg.msgid_plural,
+                              msg.flags,
+                              compat.u(' ').join(
+                                  translator_strings + [msg.comment]),
+                              msg.tcomment, msg.location)
+            yield msg
diff --git a/mako/ext/preprocessors.py b/mako/ext/preprocessors.py
new file mode 100644 (file)
index 0000000..9b700d1
--- /dev/null
@@ -0,0 +1,20 @@
+# ext/preprocessors.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""preprocessing functions, used with the 'preprocessor'
+argument on Template, TemplateLookup"""
+
+import re
+
+
+def convert_comments(text):
+    """preprocess old style comments.
+
+    example:
+
+    from mako.ext.preprocessors import convert_comments
+    t = Template(..., preprocessor=convert_comments)"""
+    return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
diff --git a/mako/ext/pygmentplugin.py b/mako/ext/pygmentplugin.py
new file mode 100644 (file)
index 0000000..4057caa
--- /dev/null
@@ -0,0 +1,127 @@
+# ext/pygmentplugin.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+from pygments.lexers.web import \
+    HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
+from pygments.lexers.agile import PythonLexer, Python3Lexer
+from pygments.lexer import DelegatingLexer, RegexLexer, bygroups, \
+    include, using
+from pygments.token import \
+    Text, Comment, Operator, Keyword, Name, String, Other
+from pygments.formatters.html import HtmlFormatter
+from pygments import highlight
+from mako import compat
+
+
+class MakoLexer(RegexLexer):
+    name = 'Mako'
+    aliases = ['mako']
+    filenames = ['*.mao']
+
+    tokens = {
+        'root': [
+            (r'(\s*)(\%)(\s*end(?:\w+))(\n|\Z)',
+             bygroups(Text, Comment.Preproc, Keyword, Other)),
+            (r'(\s*)(\%(?!%))([^\n]*)(\n|\Z)',
+             bygroups(Text, Comment.Preproc, using(PythonLexer), Other)),
+            (r'(\s*)(##[^\n]*)(\n|\Z)',
+             bygroups(Text, Comment.Preproc, Other)),
+            (r'''(?s)<%doc>.*?</%doc>''', Comment.Preproc),
+            (r'(<%)([\w\.\:]+)',
+             bygroups(Comment.Preproc, Name.Builtin), 'tag'),
+            (r'(</%)([\w\.\:]+)(>)',
+             bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)),
+            (r'<%(?=([\w\.\:]+))', Comment.Preproc, 'ondeftags'),
+            (r'(<%(?:!?))(.*?)(%>)(?s)',
+             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
+            (r'(\$\{)(.*?)(\})',
+             bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
+            (r'''(?sx)
+                (.+?)               # anything, followed by:
+                (?:
+                 (?<=\n)(?=%(?!%)|\#\#) |  # an eval or comment line
+                 (?=\#\*) |          # multiline comment
+                 (?=</?%) |         # a python block
+                                    # call start or end
+                 (?=\$\{) |         # a substitution
+                 (?<=\n)(?=\s*%) |
+                                    # - don't consume
+                 (\\\n) |           # an escaped newline
+                 \Z                 # end of string
+                )
+            ''', bygroups(Other, Operator)),
+            (r'\s+', Text),
+        ],
+        'ondeftags': [
+            (r'<%', Comment.Preproc),
+            (r'(?<=<%)(include|inherit|namespace|page)', Name.Builtin),
+            include('tag'),
+        ],
+        'tag': [
+            (r'((?:\w+)\s*=)\s*(".*?")',
+             bygroups(Name.Attribute, String)),
+            (r'/?\s*>', Comment.Preproc, '#pop'),
+            (r'\s+', Text),
+        ],
+        'attr': [
+            ('".*?"', String, '#pop'),
+            ("'.*?'", String, '#pop'),
+            (r'[^\s>]+', String, '#pop'),
+        ],
+    }
+
+
+class MakoHtmlLexer(DelegatingLexer):
+    name = 'HTML+Mako'
+    aliases = ['html+mako']
+
+    def __init__(self, **options):
+        super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer,
+                                            **options)
+
+
+class MakoXmlLexer(DelegatingLexer):
+    name = 'XML+Mako'
+    aliases = ['xml+mako']
+
+    def __init__(self, **options):
+        super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer,
+                                           **options)
+
+
+class MakoJavascriptLexer(DelegatingLexer):
+    name = 'JavaScript+Mako'
+    aliases = ['js+mako', 'javascript+mako']
+
+    def __init__(self, **options):
+        super(MakoJavascriptLexer, self).__init__(JavascriptLexer,
+                                                  MakoLexer, **options)
+
+
+class MakoCssLexer(DelegatingLexer):
+    name = 'CSS+Mako'
+    aliases = ['css+mako']
+
+    def __init__(self, **options):
+        super(MakoCssLexer, self).__init__(CssLexer, MakoLexer,
+                                           **options)
+
+
+pygments_html_formatter = HtmlFormatter(cssclass='syntax-highlighted',
+                                        linenos=True)
+
+
+def syntax_highlight(filename='', language=None):
+    mako_lexer = MakoLexer()
+    if compat.py3k:
+        python_lexer = Python3Lexer()
+    else:
+        python_lexer = PythonLexer()
+    if filename.startswith('memory:') or language == 'mako':
+        return lambda string: highlight(string, mako_lexer,
+                                        pygments_html_formatter)
+    return lambda string: highlight(string, python_lexer,
+                                    pygments_html_formatter)
diff --git a/mako/ext/turbogears.py b/mako/ext/turbogears.py
new file mode 100644 (file)
index 0000000..eaa2d78
--- /dev/null
@@ -0,0 +1,58 @@
+# ext/turbogears.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+from mako import compat
+from mako.lookup import TemplateLookup
+from mako.template import Template
+
+
+class TGPlugin(object):
+
+    """TurboGears compatible Template Plugin."""
+
+    def __init__(self, extra_vars_func=None, options=None, extension='mak'):
+        self.extra_vars_func = extra_vars_func
+        self.extension = extension
+        if not options:
+            options = {}
+
+        # Pull the options out and initialize the lookup
+        lookup_options = {}
+        for k, v in options.items():
+            if k.startswith('mako.'):
+                lookup_options[k[5:]] = v
+            elif k in ['directories', 'filesystem_checks', 'module_directory']:
+                lookup_options[k] = v
+        self.lookup = TemplateLookup(**lookup_options)
+
+        self.tmpl_options = {}
+        # transfer lookup args to template args, based on those available
+        # in getargspec
+        for kw in compat.inspect_getargspec(Template.__init__)[0]:
+            if kw in lookup_options:
+                self.tmpl_options[kw] = lookup_options[kw]
+
+    def load_template(self, templatename, template_string=None):
+        """Loads a template from a file or a string"""
+        if template_string is not None:
+            return Template(template_string, **self.tmpl_options)
+        # Translate TG dot notation to normal / template path
+        if '/' not in templatename:
+            templatename = '/' + templatename.replace('.', '/') + '.' +\
+                self.extension
+
+        # Lookup template
+        return self.lookup.get_template(templatename)
+
+    def render(self, info, format="html", fragment=False, template=None):
+        if isinstance(template, compat.string_types):
+            template = self.load_template(template)
+
+        # Load extra vars func if provided
+        if self.extra_vars_func:
+            info.update(self.extra_vars_func())
+
+        return template.render(**info)
diff --git a/mako/filters.py b/mako/filters.py
new file mode 100644 (file)
index 0000000..c082690
--- /dev/null
@@ -0,0 +1,209 @@
+# mako/filters.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+
+import re
+import codecs
+
+from mako.compat import quote_plus, unquote_plus, codepoint2name, \
+    name2codepoint
+
+from mako import compat
+
+xml_escapes = {
+    '&': '&amp;',
+    '>': '&gt;',
+    '<': '&lt;',
+    '"': '&#34;',   # also &quot; in html-only
+    "'": '&#39;'    # also &apos; in html-only
+}
+
+# XXX: &quot; is valid in HTML and XML
+#      &apos; is not valid HTML, but is valid XML
+
+
+def legacy_html_escape(s):
+    """legacy HTML escape for non-unicode mode."""
+    s = s.replace("&", "&amp;")
+    s = s.replace(">", "&gt;")
+    s = s.replace("<", "&lt;")
+    s = s.replace('"', "&#34;")
+    s = s.replace("'", "&#39;")
+    return s
+
+
+try:
+    import markupsafe
+    html_escape = markupsafe.escape
+except ImportError:
+    html_escape = legacy_html_escape
+
+
+def xml_escape(string):
+    return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
+
+
+def url_escape(string):
+    # convert into a list of octets
+    string = string.encode("utf8")
+    return quote_plus(string)
+
+
+def legacy_url_escape(string):
+    # convert into a list of octets
+    return quote_plus(string)
+
+
+def url_unescape(string):
+    text = unquote_plus(string)
+    if not is_ascii_str(text):
+        text = text.decode("utf8")
+    return text
+
+
+def trim(string):
+    return string.strip()
+
+
+class Decode(object):
+
+    def __getattr__(self, key):
+        def decode(x):
+            if isinstance(x, compat.text_type):
+                return x
+            elif not isinstance(x, compat.binary_type):
+                return decode(str(x))
+            else:
+                return compat.text_type(x, encoding=key)
+        return decode
+decode = Decode()
+
+
+_ASCII_re = re.compile(r'\A[\x00-\x7f]*\Z')
+
+
+def is_ascii_str(text):
+    return isinstance(text, str) and _ASCII_re.match(text)
+
+################################################################
+
+
+class XMLEntityEscaper(object):
+
+    def __init__(self, codepoint2name, name2codepoint):
+        self.codepoint2entity = dict([(c, compat.text_type('&%s;' % n))
+                                      for c, n in codepoint2name.items()])
+        self.name2codepoint = name2codepoint
+
+    def escape_entities(self, text):
+        """Replace characters with their character entity references.
+
+        Only characters corresponding to a named entity are replaced.
+        """
+        return compat.text_type(text).translate(self.codepoint2entity)
+
+    def __escape(self, m):
+        codepoint = ord(m.group())
+        try:
+            return self.codepoint2entity[codepoint]
+        except (KeyError, IndexError):
+            return '&#x%X;' % codepoint
+
+    __escapable = re.compile(r'["&<>]|[^\x00-\x7f]')
+
+    def escape(self, text):
+        """Replace characters with their character references.
+
+        Replace characters by their named entity references.
+        Non-ASCII characters, if they do not have a named entity reference,
+        are replaced by numerical character references.
+
+        The return value is guaranteed to be ASCII.
+        """
+        return self.__escapable.sub(self.__escape, compat.text_type(text)
+                                    ).encode('ascii')
+
+    # XXX: This regexp will not match all valid XML entity names__.
+    # (It punts on details involving involving CombiningChars and Extenders.)
+    #
+    # .. __: http://www.w3.org/TR/2000/REC-xml-20001006#NT-EntityRef
+    __characterrefs = re.compile(r'''& (?:
+                                          \#(\d+)
+                                          | \#x([\da-f]+)
+                                          | ( (?!\d) [:\w] [-.:\w]+ )
+                                          ) ;''',
+                                 re.X | re.UNICODE)
+
+    def __unescape(self, m):
+        dval, hval, name = m.groups()
+        if dval:
+            codepoint = int(dval)
+        elif hval:
+            codepoint = int(hval, 16)
+        else:
+            codepoint = self.name2codepoint.get(name, 0xfffd)
+            # U+FFFD = "REPLACEMENT CHARACTER"
+        if codepoint < 128:
+            return chr(codepoint)
+        return chr(codepoint)
+
+    def unescape(self, text):
+        """Unescape character references.
+
+        All character references (both entity references and numerical
+        character references) are unescaped.
+        """
+        return self.__characterrefs.sub(self.__unescape, text)
+
+
+_html_entities_escaper = XMLEntityEscaper(codepoint2name, name2codepoint)
+
+html_entities_escape = _html_entities_escaper.escape_entities
+html_entities_unescape = _html_entities_escaper.unescape
+
+
+def htmlentityreplace_errors(ex):
+    """An encoding error handler.
+
+    This python `codecs`_ error handler replaces unencodable
+    characters with HTML entities, or, if no HTML entity exists for
+    the character, XML character references.
+
+    >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace')
+    'The cost was &euro;12.'
+    """
+    if isinstance(ex, UnicodeEncodeError):
+        # Handle encoding errors
+        bad_text = ex.object[ex.start:ex.end]
+        text = _html_entities_escaper.escape(bad_text)
+        return (compat.text_type(text), ex.end)
+    raise ex
+
+codecs.register_error('htmlentityreplace', htmlentityreplace_errors)
+
+
+# TODO: options to make this dynamic per-compilation will be added in a later
+# release
+DEFAULT_ESCAPES = {
+    'x': 'filters.xml_escape',
+    'h': 'filters.html_escape',
+    'u': 'filters.url_escape',
+    'trim': 'filters.trim',
+    'entity': 'filters.html_entities_escape',
+    'unicode': 'unicode',
+    'decode': 'decode',
+    'str': 'str',
+    'n': 'n'
+}
+
+if compat.py3k:
+    DEFAULT_ESCAPES.update({
+        'unicode': 'str'
+    })
+
+NON_UNICODE_ESCAPES = DEFAULT_ESCAPES.copy()
+NON_UNICODE_ESCAPES['h'] = 'filters.legacy_html_escape'
+NON_UNICODE_ESCAPES['u'] = 'filters.legacy_url_escape'
diff --git a/mako/lexer.py b/mako/lexer.py
new file mode 100644 (file)
index 0000000..cf4187f
--- /dev/null
@@ -0,0 +1,449 @@
+# mako/lexer.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides the Lexer class for parsing template strings into parse trees."""
+
+import re
+import codecs
+from mako import parsetree, exceptions, compat
+from mako.pygen import adjust_whitespace
+
+_regexp_cache = {}
+
+
+class Lexer(object):
+
+    def __init__(self, text, filename=None,
+                 disable_unicode=False,
+                 input_encoding=None, preprocessor=None):
+        self.text = text
+        self.filename = filename
+        self.template = parsetree.TemplateNode(self.filename)
+        self.matched_lineno = 1
+        self.matched_charpos = 0
+        self.lineno = 1
+        self.match_position = 0
+        self.tag = []
+        self.control_line = []
+        self.ternary_stack = []
+        self.disable_unicode = disable_unicode
+        self.encoding = input_encoding
+
+        if compat.py3k and disable_unicode:
+            raise exceptions.UnsupportedError(
+                "Mako for Python 3 does not "
+                "support disabling Unicode")
+
+        if preprocessor is None:
+            self.preprocessor = []
+        elif not hasattr(preprocessor, '__iter__'):
+            self.preprocessor = [preprocessor]
+        else:
+            self.preprocessor = preprocessor
+
+    @property
+    def exception_kwargs(self):
+        return {'source': self.text,
+                'lineno': self.matched_lineno,
+                'pos': self.matched_charpos,
+                'filename': self.filename}
+
+    def match(self, regexp, flags=None):
+        """compile the given regexp, cache the reg, and call match_reg()."""
+
+        try:
+            reg = _regexp_cache[(regexp, flags)]
+        except KeyError:
+            if flags:
+                reg = re.compile(regexp, flags)
+            else:
+                reg = re.compile(regexp)
+            _regexp_cache[(regexp, flags)] = reg
+
+        return self.match_reg(reg)
+
+    def match_reg(self, reg):
+        """match the given regular expression object to the current text
+        position.
+
+        if a match occurs, update the current text and line position.
+
+        """
+
+        mp = self.match_position
+
+        match = reg.match(self.text, self.match_position)
+        if match:
+            (start, end) = match.span()
+            if end == start:
+                self.match_position = end + 1
+            else:
+                self.match_position = end
+            self.matched_lineno = self.lineno
+            lines = re.findall(r"\n", self.text[mp:self.match_position])
+            cp = mp - 1
+            while (cp >= 0 and cp < self.textlength and self.text[cp] != '\n'):
+                cp -= 1
+            self.matched_charpos = mp - cp
+            self.lineno += len(lines)
+            # print "MATCHED:", match.group(0), "LINE START:",
+            # self.matched_lineno, "LINE END:", self.lineno
+        # print "MATCH:", regexp, "\n", self.text[mp : mp + 15], \
+        #          (match and "TRUE" or "FALSE")
+        return match
+
+    def parse_until_text(self, watch_nesting, *text):
+        startpos = self.match_position
+        text_re = r'|'.join(text)
+        brace_level = 0
+        paren_level = 0
+        bracket_level = 0
+        while True:
+            match = self.match(r'#.*\n')
+            if match:
+                continue
+            match = self.match(r'(\"\"\"|\'\'\'|\"|\')[^\\]*?(\\.[^\\]*?)*\1',
+                               re.S)
+            if match:
+                continue
+            match = self.match(r'(%s)' % text_re)
+            if match and not (watch_nesting
+                              and (brace_level > 0 or paren_level > 0
+                                   or bracket_level > 0)):
+                return \
+                    self.text[startpos:
+                              self.match_position - len(match.group(1))],\
+                    match.group(1)
+            elif not match:
+                match = self.match(r"(.*?)(?=\"|\'|#|%s)" % text_re, re.S)
+            if match:
+                brace_level += match.group(1).count('{')
+                brace_level -= match.group(1).count('}')
+                paren_level += match.group(1).count('(')
+                paren_level -= match.group(1).count(')')
+                bracket_level += match.group(1).count('[')
+                bracket_level -= match.group(1).count(']')
+                continue
+            raise exceptions.SyntaxException(
+                "Expected: %s" %
+                ','.join(text),
+                **self.exception_kwargs)
+
+    def append_node(self, nodecls, *args, **kwargs):
+        kwargs.setdefault('source', self.text)
+        kwargs.setdefault('lineno', self.matched_lineno)
+        kwargs.setdefault('pos', self.matched_charpos)
+        kwargs['filename'] = self.filename
+        node = nodecls(*args, **kwargs)
+        if len(self.tag):
+            self.tag[-1].nodes.append(node)
+        else:
+            self.template.nodes.append(node)
+        # build a set of child nodes for the control line
+        # (used for loop variable detection)
+        # also build a set of child nodes on ternary control lines
+        # (used for determining if a pass needs to be auto-inserted
+        if self.control_line:
+            control_frame = self.control_line[-1]
+            control_frame.nodes.append(node)
+            if not (isinstance(node, parsetree.ControlLine) and
+                    control_frame.is_ternary(node.keyword)):
+                if self.ternary_stack and self.ternary_stack[-1]:
+                    self.ternary_stack[-1][-1].nodes.append(node)
+        if isinstance(node, parsetree.Tag):
+            if len(self.tag):
+                node.parent = self.tag[-1]
+            self.tag.append(node)
+        elif isinstance(node, parsetree.ControlLine):
+            if node.isend:
+                self.control_line.pop()
+                self.ternary_stack.pop()
+            elif node.is_primary:
+                self.control_line.append(node)
+                self.ternary_stack.append([])
+            elif self.control_line and \
+                    self.control_line[-1].is_ternary(node.keyword):
+                self.ternary_stack[-1].append(node)
+            elif self.control_line and \
+                    not self.control_line[-1].is_ternary(node.keyword):
+                raise exceptions.SyntaxException(
+                    "Keyword '%s' not a legal ternary for keyword '%s'" %
+                    (node.keyword, self.control_line[-1].keyword),
+                    **self.exception_kwargs)
+
+    _coding_re = re.compile(r'#.*coding[:=]\s*([-\w.]+).*\r?\n')
+
+    def decode_raw_stream(self, text, decode_raw, known_encoding, filename):
+        """given string/unicode or bytes/string, determine encoding
+           from magic encoding comment, return body as unicode
+           or raw if decode_raw=False
+
+        """
+        if isinstance(text, compat.text_type):
+            m = self._coding_re.match(text)
+            encoding = m and m.group(1) or known_encoding or 'ascii'
+            return encoding, text
+
+        if text.startswith(codecs.BOM_UTF8):
+            text = text[len(codecs.BOM_UTF8):]
+            parsed_encoding = 'utf-8'
+            m = self._coding_re.match(text.decode('utf-8', 'ignore'))
+            if m is not None and m.group(1) != 'utf-8':
+                raise exceptions.CompileException(
+                    "Found utf-8 BOM in file, with conflicting "
+                    "magic encoding comment of '%s'" % m.group(1),
+                    text.decode('utf-8', 'ignore'),
+                    0, 0, filename)
+        else:
+            m = self._coding_re.match(text.decode('utf-8', 'ignore'))
+            if m:
+                parsed_encoding = m.group(1)
+            else:
+                parsed_encoding = known_encoding or 'ascii'
+
+        if decode_raw:
+            try:
+                text = text.decode(parsed_encoding)
+            except UnicodeDecodeError:
+                raise exceptions.CompileException(
+                    "Unicode decode operation of encoding '%s' failed" %
+                    parsed_encoding,
+                    text.decode('utf-8', 'ignore'),
+                    0, 0, filename)
+
+        return parsed_encoding, text
+
+    def parse(self):
+        self.encoding, self.text = self.decode_raw_stream(
+            self.text,
+            not self.disable_unicode,
+            self.encoding,
+            self.filename)
+
+        for preproc in self.preprocessor:
+            self.text = preproc(self.text)
+
+        # push the match marker past the
+        # encoding comment.
+        self.match_reg(self._coding_re)
+
+        self.textlength = len(self.text)
+
+        while (True):
+            if self.match_position > self.textlength:
+                break
+
+            if self.match_end():
+                break
+            if self.match_expression():
+                continue
+            if self.match_control_line():
+                continue
+            if self.match_comment():
+                continue
+            if self.match_tag_start():
+                continue
+            if self.match_tag_end():
+                continue
+            if self.match_python_block():
+                continue
+            if self.match_text():
+                continue
+
+            if self.match_position > self.textlength:
+                break
+            raise exceptions.CompileException("assertion failed")
+
+        if len(self.tag):
+            raise exceptions.SyntaxException("Unclosed tag: <%%%s>" %
+                                             self.tag[-1].keyword,
+                                             **self.exception_kwargs)
+        if len(self.control_line):
+            raise exceptions.SyntaxException(
+                "Unterminated control keyword: '%s'" %
+                self.control_line[-1].keyword,
+                self.text,
+                self.control_line[-1].lineno,
+                self.control_line[-1].pos, self.filename)
+        return self.template
+
+    def match_tag_start(self):
+        match = self.match(r'''
+            \<%     # opening tag
+
+            ([\w\.\:]+)   # keyword
+
+            ((?:\s+\w+|\s*=\s*|".*?"|'.*?')*)  # attrname, = \
+                                               #        sign, string expression
+
+            \s*     # more whitespace
+
+            (/)?>   # closing
+
+            ''',
+
+                           re.I | re.S | re.X)
+
+        if match:
+            keyword, attr, isend = match.groups()
+            self.keyword = keyword
+            attributes = {}
+            if attr:
+                for att in re.findall(
+                        r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr):
+                    key, val1, val2 = att
+                    text = val1 or val2
+                    text = text.replace('\r\n', '\n')
+                    attributes[key] = text
+            self.append_node(parsetree.Tag, keyword, attributes)
+            if isend:
+                self.tag.pop()
+            else:
+                if keyword == 'text':
+                    match = self.match(r'(.*?)(?=\</%text>)', re.S)
+                    if not match:
+                        raise exceptions.SyntaxException(
+                            "Unclosed tag: <%%%s>" %
+                            self.tag[-1].keyword,
+                            **self.exception_kwargs)
+                    self.append_node(parsetree.Text, match.group(1))
+                    return self.match_tag_end()
+            return True
+        else:
+            return False
+
+    def match_tag_end(self):
+        match = self.match(r'\</%[\t ]*(.+?)[\t ]*>')
+        if match:
+            if not len(self.tag):
+                raise exceptions.SyntaxException(
+                    "Closing tag without opening tag: </%%%s>" %
+                    match.group(1),
+                    **self.exception_kwargs)
+            elif self.tag[-1].keyword != match.group(1):
+                raise exceptions.SyntaxException(
+                    "Closing tag </%%%s> does not match tag: <%%%s>" %
+                    (match.group(1), self.tag[-1].keyword),
+                    **self.exception_kwargs)
+            self.tag.pop()
+            return True
+        else:
+            return False
+
+    def match_end(self):
+        match = self.match(r'\Z', re.S)
+        if match:
+            string = match.group()
+            if string:
+                return string
+            else:
+                return True
+        else:
+            return False
+
+    def match_text(self):
+        match = self.match(r"""
+                (.*?)         # anything, followed by:
+                (
+                 (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based
+                                             # comment preceded by a
+                                             # consumed newline and whitespace
+                 |
+                 (?=\${)      # an expression
+                 |
+                 (?=</?[%&])  # a substitution or block or call start or end
+                              # - don't consume
+                 |
+                 (\\\r?\n)    # an escaped newline  - throw away
+                 |
+                 \Z           # end of string
+                )""", re.X | re.S)
+
+        if match:
+            text = match.group(1)
+            if text:
+                self.append_node(parsetree.Text, text)
+            return True
+        else:
+            return False
+
+    def match_python_block(self):
+        match = self.match(r"<%(!)?")
+        if match:
+            line, pos = self.matched_lineno, self.matched_charpos
+            text, end = self.parse_until_text(False, r'%>')
+            # the trailing newline helps
+            # compiler.parse() not complain about indentation
+            text = adjust_whitespace(text) + "\n"
+            self.append_node(
+                parsetree.Code,
+                text,
+                match.group(1) == '!', lineno=line, pos=pos)
+            return True
+        else:
+            return False
+
+    def match_expression(self):
+        match = self.match(r"\${")
+        if match:
+            line, pos = self.matched_lineno, self.matched_charpos
+            text, end = self.parse_until_text(True, r'\|', r'}')
+            if end == '|':
+                escapes, end = self.parse_until_text(True, r'}')
+            else:
+                escapes = ""
+            text = text.replace('\r\n', '\n')
+            self.append_node(
+                parsetree.Expression,
+                text, escapes.strip(),
+                lineno=line, pos=pos)
+            return True
+        else:
+            return False
+
+    def match_control_line(self):
+        match = self.match(
+            r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
+            r"(?:\r?\n|\Z)", re.M)
+        if match:
+            operator = match.group(1)
+            text = match.group(2)
+            if operator == '%':
+                m2 = re.match(r'(end)?(\w+)\s*(.*)', text)
+                if not m2:
+                    raise exceptions.SyntaxException(
+                        "Invalid control line: '%s'" %
+                        text,
+                        **self.exception_kwargs)
+                isend, keyword = m2.group(1, 2)
+                isend = (isend is not None)
+
+                if isend:
+                    if not len(self.control_line):
+                        raise exceptions.SyntaxException(
+                            "No starting keyword '%s' for '%s'" %
+                            (keyword, text),
+                            **self.exception_kwargs)
+                    elif self.control_line[-1].keyword != keyword:
+                        raise exceptions.SyntaxException(
+                            "Keyword '%s' doesn't match keyword '%s'" %
+                            (text, self.control_line[-1].keyword),
+                            **self.exception_kwargs)
+                self.append_node(parsetree.ControlLine, keyword, isend, text)
+            else:
+                self.append_node(parsetree.Comment, text)
+            return True
+        else:
+            return False
+
+    def match_comment(self):
+        """matches the multiline version of a comment"""
+        match = self.match(r"<%doc>(.*?)</%doc>", re.S)
+        if match:
+            self.append_node(parsetree.Comment, match.group(1))
+            return True
+        else:
+            return False
diff --git a/mako/lookup.py b/mako/lookup.py
new file mode 100644 (file)
index 0000000..0d3f304
--- /dev/null
@@ -0,0 +1,369 @@
+# mako/lookup.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+import os
+import stat
+import posixpath
+import re
+from mako import exceptions, util
+from mako.template import Template
+
+try:
+    import threading
+except:
+    import dummy_threading as threading
+
+
+class TemplateCollection(object):
+
+    """Represent a collection of :class:`.Template` objects,
+    identifiable via URI.
+
+    A :class:`.TemplateCollection` is linked to the usage of
+    all template tags that address other templates, such
+    as ``<%include>``, ``<%namespace>``, and ``<%inherit>``.
+    The ``file`` attribute of each of those tags refers
+    to a string URI that is passed to that :class:`.Template`
+    object's :class:`.TemplateCollection` for resolution.
+
+    :class:`.TemplateCollection` is an abstract class,
+    with the usual default implementation being :class:`.TemplateLookup`.
+
+     """
+
+    def has_template(self, uri):
+        """Return ``True`` if this :class:`.TemplateLookup` is
+        capable of returning a :class:`.Template` object for the
+        given ``uri``.
+
+        :param uri: String URI of the template to be resolved.
+
+        """
+        try:
+            self.get_template(uri)
+            return True
+        except exceptions.TemplateLookupException:
+            return False
+
+    def get_template(self, uri, relativeto=None):
+        """Return a :class:`.Template` object corresponding to the given
+        ``uri``.
+
+        The default implementation raises
+        :class:`.NotImplementedError`. Implementations should
+        raise :class:`.TemplateLookupException` if the given ``uri``
+        cannot be resolved.
+
+        :param uri: String URI of the template to be resolved.
+        :param relativeto: if present, the given ``uri`` is assumed to
+         be relative to this URI.
+
+        """
+        raise NotImplementedError()
+
+    def filename_to_uri(self, uri, filename):
+        """Convert the given ``filename`` to a URI relative to
+           this :class:`.TemplateCollection`."""
+
+        return uri
+
+    def adjust_uri(self, uri, filename):
+        """Adjust the given ``uri`` based on the calling ``filename``.
+
+        When this method is called from the runtime, the
+        ``filename`` parameter is taken directly to the ``filename``
+        attribute of the calling template. Therefore a custom
+        :class:`.TemplateCollection` subclass can place any string
+        identifier desired in the ``filename`` parameter of the
+        :class:`.Template` objects it constructs and have them come back
+        here.
+
+        """
+        return uri
+
+
+class TemplateLookup(TemplateCollection):
+
+    """Represent a collection of templates that locates template source files
+    from the local filesystem.
+
+    The primary argument is the ``directories`` argument, the list of
+    directories to search:
+
+    .. sourcecode:: python
+
+        lookup = TemplateLookup(["/path/to/templates"])
+        some_template = lookup.get_template("/index.html")
+
+    The :class:`.TemplateLookup` can also be given :class:`.Template` objects
+    programatically using :meth:`.put_string` or :meth:`.put_template`:
+
+    .. sourcecode:: python
+
+        lookup = TemplateLookup()
+        lookup.put_string("base.html", '''
+            <html><body>${self.next()}</body></html>
+        ''')
+        lookup.put_string("hello.html", '''
+            <%include file='base.html'/>
+
+            Hello, world !
+        ''')
+
+
+    :param directories: A list of directory names which will be
+     searched for a particular template URI. The URI is appended
+     to each directory and the filesystem checked.
+
+    :param collection_size: Approximate size of the collection used
+     to store templates. If left at its default of ``-1``, the size
+     is unbounded, and a plain Python dictionary is used to
+     relate URI strings to :class:`.Template` instances.
+     Otherwise, a least-recently-used cache object is used which
+     will maintain the size of the collection approximately to
+     the number given.
+
+    :param filesystem_checks: When at its default value of ``True``,
+     each call to :meth:`.TemplateLookup.get_template()` will
+     compare the filesystem last modified time to the time in
+     which an existing :class:`.Template` object was created.
+     This allows the :class:`.TemplateLookup` to regenerate a
+     new :class:`.Template` whenever the original source has
+     been updated. Set this to ``False`` for a very minor
+     performance increase.
+
+    :param modulename_callable: A callable which, when present,
+     is passed the path of the source file as well as the
+     requested URI, and then returns the full path of the
+     generated Python module file. This is used to inject
+     alternate schemes for Python module location. If left at
+     its default of ``None``, the built in system of generation
+     based on ``module_directory`` plus ``uri`` is used.
+
+    All other keyword parameters available for
+    :class:`.Template` are mirrored here. When new
+    :class:`.Template` objects are created, the keywords
+    established with this :class:`.TemplateLookup` are passed on
+    to each new :class:`.Template`.
+
+    """
+
+    def __init__(self,
+                 directories=None,
+                 module_directory=None,
+                 filesystem_checks=True,
+                 collection_size=-1,
+                 format_exceptions=False,
+                 error_handler=None,
+                 disable_unicode=False,
+                 bytestring_passthrough=False,
+                 output_encoding=None,
+                 encoding_errors='strict',
+
+                 cache_args=None,
+                 cache_impl='beaker',
+                 cache_enabled=True,
+                 cache_type=None,
+                 cache_dir=None,
+                 cache_url=None,
+
+                 modulename_callable=None,
+                 module_writer=None,
+                 default_filters=None,
+                 buffer_filters=(),
+                 strict_undefined=False,
+                 imports=None,
+                 future_imports=None,
+                 enable_loop=True,
+                 input_encoding=None,
+                 preprocessor=None,
+                 lexer_cls=None,
+                 include_error_handler=None):
+
+        self.directories = [posixpath.normpath(d) for d in
+                            util.to_list(directories, ())
+                            ]
+        self.module_directory = module_directory
+        self.modulename_callable = modulename_callable
+        self.filesystem_checks = filesystem_checks
+        self.collection_size = collection_size
+
+        if cache_args is None:
+            cache_args = {}
+        # transfer deprecated cache_* args
+        if cache_dir:
+            cache_args.setdefault('dir', cache_dir)
+        if cache_url:
+            cache_args.setdefault('url', cache_url)
+        if cache_type:
+            cache_args.setdefault('type', cache_type)
+
+        self.template_args = {
+            'format_exceptions': format_exceptions,
+            'error_handler': error_handler,
+            'include_error_handler': include_error_handler,
+            'disable_unicode': disable_unicode,
+            'bytestring_passthrough': bytestring_passthrough,
+            'output_encoding': output_encoding,
+            'cache_impl': cache_impl,
+            'encoding_errors': encoding_errors,
+            'input_encoding': input_encoding,
+            'module_directory': module_directory,
+            'module_writer': module_writer,
+            'cache_args': cache_args,
+            'cache_enabled': cache_enabled,
+            'default_filters': default_filters,
+            'buffer_filters': buffer_filters,
+            'strict_undefined': strict_undefined,
+            'imports': imports,
+            'future_imports': future_imports,
+            'enable_loop': enable_loop,
+            'preprocessor': preprocessor,
+            'lexer_cls': lexer_cls
+        }
+
+        if collection_size == -1:
+            self._collection = {}
+            self._uri_cache = {}
+        else:
+            self._collection = util.LRUCache(collection_size)
+            self._uri_cache = util.LRUCache(collection_size)
+        self._mutex = threading.Lock()
+
+    def get_template(self, uri):
+        """Return a :class:`.Template` object corresponding to the given
+        ``uri``.
+
+        .. note:: The ``relativeto`` argument is not supported here at
+           the moment.
+
+        """
+
+        try:
+            if self.filesystem_checks:
+                return self._check(uri, self._collection[uri])
+            else:
+                return self._collection[uri]
+        except KeyError:
+            u = re.sub(r'^\/+', '', uri)
+            for dir in self.directories:
+                # make sure the path seperators are posix - os.altsep is empty
+                # on POSIX and cannot be used.
+                dir = dir.replace(os.path.sep, posixpath.sep)
+                srcfile = posixpath.normpath(posixpath.join(dir, u))
+                if os.path.isfile(srcfile):
+                    return self._load(srcfile, uri)
+            else:
+                raise exceptions.TopLevelLookupException(
+                    "Cant locate template for uri %r" % uri)
+
+    def adjust_uri(self, uri, relativeto):
+        """Adjust the given ``uri`` based on the given relative URI."""
+
+        key = (uri, relativeto)
+        if key in self._uri_cache:
+            return self._uri_cache[key]
+
+        if uri[0] != '/':
+            if relativeto is not None:
+                v = self._uri_cache[key] = posixpath.join(
+                    posixpath.dirname(relativeto), uri)
+            else:
+                v = self._uri_cache[key] = '/' + uri
+        else:
+            v = self._uri_cache[key] = uri
+        return v
+
+    def filename_to_uri(self, filename):
+        """Convert the given ``filename`` to a URI relative to
+           this :class:`.TemplateCollection`."""
+
+        try:
+            return self._uri_cache[filename]
+        except KeyError:
+            value = self._relativeize(filename)
+            self._uri_cache[filename] = value
+            return value
+
+    def _relativeize(self, filename):
+        """Return the portion of a filename that is 'relative'
+           to the directories in this lookup.
+
+        """
+
+        filename = posixpath.normpath(filename)
+        for dir in self.directories:
+            if filename[0:len(dir)] == dir:
+                return filename[len(dir):]
+        else:
+            return None
+
+    def _load(self, filename, uri):
+        self._mutex.acquire()
+        try:
+            try:
+                # try returning from collection one
+                # more time in case concurrent thread already loaded
+                return self._collection[uri]
+            except KeyError:
+                pass
+            try:
+                if self.modulename_callable is not None:
+                    module_filename = self.modulename_callable(filename, uri)
+                else:
+                    module_filename = None
+                self._collection[uri] = template = Template(
+                    uri=uri,
+                    filename=posixpath.normpath(filename),
+                    lookup=self,
+                    module_filename=module_filename,
+                    **self.template_args)
+                return template
+            except:
+                # if compilation fails etc, ensure
+                # template is removed from collection,
+                # re-raise
+                self._collection.pop(uri, None)
+                raise
+        finally:
+            self._mutex.release()
+
+    def _check(self, uri, template):
+        if template.filename is None:
+            return template
+
+        try:
+            template_stat = os.stat(template.filename)
+            if template.module._modified_time < \
+                    template_stat[stat.ST_MTIME]:
+                self._collection.pop(uri, None)
+                return self._load(template.filename, uri)
+            else:
+                return template
+        except OSError:
+            self._collection.pop(uri, None)
+            raise exceptions.TemplateLookupException(
+                "Cant locate template for uri %r" % uri)
+
+    def put_string(self, uri, text):
+        """Place a new :class:`.Template` object into this
+        :class:`.TemplateLookup`, based on the given string of
+        ``text``.
+
+        """
+        self._collection[uri] = Template(
+            text,
+            lookup=self,
+            uri=uri,
+            **self.template_args)
+
+    def put_template(self, uri, template):
+        """Place a new :class:`.Template` object into this
+        :class:`.TemplateLookup`, based on the given
+        :class:`.Template` object.
+
+        """
+        self._collection[uri] = template
diff --git a/mako/parsetree.py b/mako/parsetree.py
new file mode 100644 (file)
index 0000000..879882e
--- /dev/null
@@ -0,0 +1,616 @@
+# mako/parsetree.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""defines the parse tree components for Mako templates."""
+
+from mako import exceptions, ast, util, filters, compat
+import re
+
+
+class Node(object):
+
+    """base class for a Node in the parse tree."""
+
+    def __init__(self, source, lineno, pos, filename):
+        self.source = source
+        self.lineno = lineno
+        self.pos = pos
+        self.filename = filename
+
+    @property
+    def exception_kwargs(self):
+        return {'source': self.source, 'lineno': self.lineno,
+                'pos': self.pos, 'filename': self.filename}
+
+    def get_children(self):
+        return []
+
+    def accept_visitor(self, visitor):
+        def traverse(node):
+            for n in node.get_children():
+                n.accept_visitor(visitor)
+
+        method = getattr(visitor, "visit" + self.__class__.__name__, traverse)
+        method(self)
+
+
+class TemplateNode(Node):
+
+    """a 'container' node that stores the overall collection of nodes."""
+
+    def __init__(self, filename):
+        super(TemplateNode, self).__init__('', 0, 0, filename)
+        self.nodes = []
+        self.page_attributes = {}
+
+    def get_children(self):
+        return self.nodes
+
+    def __repr__(self):
+        return "TemplateNode(%s, %r)" % (
+            util.sorted_dict_repr(self.page_attributes),
+            self.nodes)
+
+
+class ControlLine(Node):
+
+    """defines a control line, a line-oriented python line or end tag.
+
+    e.g.::
+
+        % if foo:
+            (markup)
+        % endif
+
+    """
+
+    has_loop_context = False
+
+    def __init__(self, keyword, isend, text, **kwargs):
+        super(ControlLine, self).__init__(**kwargs)
+        self.text = text
+        self.keyword = keyword
+        self.isend = isend
+        self.is_primary = keyword in ['for', 'if', 'while', 'try', 'with']
+        self.nodes = []
+        if self.isend:
+            self._declared_identifiers = []
+            self._undeclared_identifiers = []
+        else:
+            code = ast.PythonFragment(text, **self.exception_kwargs)
+            self._declared_identifiers = code.declared_identifiers
+            self._undeclared_identifiers = code.undeclared_identifiers
+
+    def get_children(self):
+        return self.nodes
+
+    def declared_identifiers(self):
+        return self._declared_identifiers
+
+    def undeclared_identifiers(self):
+        return self._undeclared_identifiers
+
+    def is_ternary(self, keyword):
+        """return true if the given keyword is a ternary keyword
+        for this ControlLine"""
+
+        return keyword in {
+            'if': set(['else', 'elif']),
+            'try': set(['except', 'finally']),
+            'for': set(['else'])
+        }.get(self.keyword, [])
+
+    def __repr__(self):
+        return "ControlLine(%r, %r, %r, %r)" % (
+            self.keyword,
+            self.text,
+            self.isend,
+            (self.lineno, self.pos)
+        )
+
+
+class Text(Node):
+
+    """defines plain text in the template."""
+
+    def __init__(self, content, **kwargs):
+        super(Text, self).__init__(**kwargs)
+        self.content = content
+
+    def __repr__(self):
+        return "Text(%r, %r)" % (self.content, (self.lineno, self.pos))
+
+
+class Code(Node):
+
+    """defines a Python code block, either inline or module level.
+
+    e.g.::
+
+        inline:
+        <%
+            x = 12
+        %>
+
+        module level:
+        <%!
+            import logger
+        %>
+
+    """
+
+    def __init__(self, text, ismodule, **kwargs):
+        super(Code, self).__init__(**kwargs)
+        self.text = text
+        self.ismodule = ismodule
+        self.code = ast.PythonCode(text, **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return self.code.declared_identifiers
+
+    def undeclared_identifiers(self):
+        return self.code.undeclared_identifiers
+
+    def __repr__(self):
+        return "Code(%r, %r, %r)" % (
+            self.text,
+            self.ismodule,
+            (self.lineno, self.pos)
+        )
+
+
+class Comment(Node):
+
+    """defines a comment line.
+
+    # this is a comment
+
+    """
+
+    def __init__(self, text, **kwargs):
+        super(Comment, self).__init__(**kwargs)
+        self.text = text
+
+    def __repr__(self):
+        return "Comment(%r, %r)" % (self.text, (self.lineno, self.pos))
+
+
+class Expression(Node):
+
+    """defines an inline expression.
+
+    ${x+y}
+
+    """
+
+    def __init__(self, text, escapes, **kwargs):
+        super(Expression, self).__init__(**kwargs)
+        self.text = text
+        self.escapes = escapes
+        self.escapes_code = ast.ArgumentList(escapes, **self.exception_kwargs)
+        self.code = ast.PythonCode(text, **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return []
+
+    def undeclared_identifiers(self):
+        # TODO: make the "filter" shortcut list configurable at parse/gen time
+        return self.code.undeclared_identifiers.union(
+            self.escapes_code.undeclared_identifiers.difference(
+                set(filters.DEFAULT_ESCAPES.keys())
+            )
+        ).difference(self.code.declared_identifiers)
+
+    def __repr__(self):
+        return "Expression(%r, %r, %r)" % (
+            self.text,
+            self.escapes_code.args,
+            (self.lineno, self.pos)
+        )
+
+
+class _TagMeta(type):
+
+    """metaclass to allow Tag to produce a subclass according to
+    its keyword"""
+
+    _classmap = {}
+
+    def __init__(cls, clsname, bases, dict):
+        if getattr(cls, '__keyword__', None) is not None:
+            cls._classmap[cls.__keyword__] = cls
+        super(_TagMeta, cls).__init__(clsname, bases, dict)
+
+    def __call__(cls, keyword, attributes, **kwargs):
+        if ":" in keyword:
+            ns, defname = keyword.split(':')
+            return type.__call__(CallNamespaceTag, ns, defname,
+                                 attributes, **kwargs)
+
+        try:
+            cls = _TagMeta._classmap[keyword]
+        except KeyError:
+            raise exceptions.CompileException(
+                "No such tag: '%s'" % keyword,
+                source=kwargs['source'],
+                lineno=kwargs['lineno'],
+                pos=kwargs['pos'],
+                filename=kwargs['filename']
+            )
+        return type.__call__(cls, keyword, attributes, **kwargs)
+
+
+class Tag(compat.with_metaclass(_TagMeta, Node)):
+
+    """abstract base class for tags.
+
+    <%sometag/>
+
+    <%someothertag>
+        stuff
+    </%someothertag>
+
+    """
+    __keyword__ = None
+
+    def __init__(self, keyword, attributes, expressions,
+                 nonexpressions, required, **kwargs):
+        """construct a new Tag instance.
+
+        this constructor not called directly, and is only called
+        by subclasses.
+
+        :param keyword: the tag keyword
+
+        :param attributes: raw dictionary of attribute key/value pairs
+
+        :param expressions: a set of identifiers that are legal attributes,
+         which can also contain embedded expressions
+
+        :param nonexpressions: a set of identifiers that are legal
+         attributes, which cannot contain embedded expressions
+
+        :param \**kwargs:
+         other arguments passed to the Node superclass (lineno, pos)
+
+        """
+        super(Tag, self).__init__(**kwargs)
+        self.keyword = keyword
+        self.attributes = attributes
+        self._parse_attributes(expressions, nonexpressions)
+        missing = [r for r in required if r not in self.parsed_attributes]
+        if len(missing):
+            raise exceptions.CompileException(
+                "Missing attribute(s): %s" %
+                ",".join([repr(m) for m in missing]),
+                **self.exception_kwargs)
+        self.parent = None
+        self.nodes = []
+
+    def is_root(self):
+        return self.parent is None
+
+    def get_children(self):
+        return self.nodes
+
+    def _parse_attributes(self, expressions, nonexpressions):
+        undeclared_identifiers = set()
+        self.parsed_attributes = {}
+        for key in self.attributes:
+            if key in expressions:
+                expr = []
+                for x in re.compile(r'(\${.+?})',
+                                    re.S).split(self.attributes[key]):
+                    m = re.compile(r'^\${(.+?)}$', re.S).match(x)
+                    if m:
+                        code = ast.PythonCode(m.group(1).rstrip(),
+                                              **self.exception_kwargs)
+                        # we aren't discarding "declared_identifiers" here,
+                        # which we do so that list comprehension-declared
+                        # variables aren't counted.   As yet can't find a
+                        # condition that requires it here.
+                        undeclared_identifiers = \
+                            undeclared_identifiers.union(
+                                code.undeclared_identifiers)
+                        expr.append('(%s)' % m.group(1))
+                    else:
+                        if x:
+                            expr.append(repr(x))
+                self.parsed_attributes[key] = " + ".join(expr) or repr('')
+            elif key in nonexpressions:
+                if re.search(r'\${.+?}', self.attributes[key]):
+                    raise exceptions.CompileException(
+                        "Attibute '%s' in tag '%s' does not allow embedded "
+                        "expressions" % (key, self.keyword),
+                        **self.exception_kwargs)
+                self.parsed_attributes[key] = repr(self.attributes[key])
+            else:
+                raise exceptions.CompileException(
+                    "Invalid attribute for tag '%s': '%s'" %
+                    (self.keyword, key),
+                    **self.exception_kwargs)
+        self.expression_undeclared_identifiers = undeclared_identifiers
+
+    def declared_identifiers(self):
+        return []
+
+    def undeclared_identifiers(self):
+        return self.expression_undeclared_identifiers
+
+    def __repr__(self):
+        return "%s(%r, %s, %r, %r)" % (self.__class__.__name__,
+                                       self.keyword,
+                                       util.sorted_dict_repr(self.attributes),
+                                       (self.lineno, self.pos),
+                                       self.nodes
+                                       )
+
+
+class IncludeTag(Tag):
+    __keyword__ = 'include'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        super(IncludeTag, self).__init__(
+            keyword,
+            attributes,
+            ('file', 'import', 'args'),
+            (), ('file',), **kwargs)
+        self.page_args = ast.PythonCode(
+            "__DUMMY(%s)" % attributes.get('args', ''),
+            **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return []
+
+    def undeclared_identifiers(self):
+        identifiers = self.page_args.undeclared_identifiers.\
+            difference(set(["__DUMMY"])).\
+            difference(self.page_args.declared_identifiers)
+        return identifiers.union(super(IncludeTag, self).
+                                 undeclared_identifiers())
+
+
+class NamespaceTag(Tag):
+    __keyword__ = 'namespace'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        super(NamespaceTag, self).__init__(
+            keyword, attributes,
+            ('file',),
+            ('name', 'inheritable',
+             'import', 'module'),
+            (), **kwargs)
+
+        self.name = attributes.get('name', '__anon_%s' % hex(abs(id(self))))
+        if 'name' not in attributes and 'import' not in attributes:
+            raise exceptions.CompileException(
+                "'name' and/or 'import' attributes are required "
+                "for <%namespace>",
+                **self.exception_kwargs)
+        if 'file' in attributes and 'module' in attributes:
+            raise exceptions.CompileException(
+                "<%namespace> may only have one of 'file' or 'module'",
+                **self.exception_kwargs
+            )
+
+    def declared_identifiers(self):
+        return []
+
+
+class TextTag(Tag):
+    __keyword__ = 'text'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        super(TextTag, self).__init__(
+            keyword,
+            attributes, (),
+            ('filter'), (), **kwargs)
+        self.filter_args = ast.ArgumentList(
+            attributes.get('filter', ''),
+            **self.exception_kwargs)
+
+    def undeclared_identifiers(self):
+        return self.filter_args.\
+            undeclared_identifiers.\
+            difference(filters.DEFAULT_ESCAPES.keys()).union(
+                self.expression_undeclared_identifiers
+            )
+
+
+class DefTag(Tag):
+    __keyword__ = 'def'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        expressions = ['buffered', 'cached'] + [
+            c for c in attributes if c.startswith('cache_')]
+
+        super(DefTag, self).__init__(
+            keyword,
+            attributes,
+            expressions,
+            ('name', 'filter', 'decorator'),
+            ('name',),
+            **kwargs)
+        name = attributes['name']
+        if re.match(r'^[\w_]+$', name):
+            raise exceptions.CompileException(
+                "Missing parenthesis in %def",
+                **self.exception_kwargs)
+        self.function_decl = ast.FunctionDecl("def " + name + ":pass",
+                                              **self.exception_kwargs)
+        self.name = self.function_decl.funcname
+        self.decorator = attributes.get('decorator', '')
+        self.filter_args = ast.ArgumentList(
+            attributes.get('filter', ''),
+            **self.exception_kwargs)
+
+    is_anonymous = False
+    is_block = False
+
+    @property
+    def funcname(self):
+        return self.function_decl.funcname
+
+    def get_argument_expressions(self, **kw):
+        return self.function_decl.get_argument_expressions(**kw)
+
+    def declared_identifiers(self):
+        return self.function_decl.allargnames
+
+    def undeclared_identifiers(self):
+        res = []
+        for c in self.function_decl.defaults:
+            res += list(ast.PythonCode(c, **self.exception_kwargs).
+                        undeclared_identifiers)
+        return set(res).union(
+            self.filter_args.
+            undeclared_identifiers.
+            difference(filters.DEFAULT_ESCAPES.keys())
+        ).union(
+            self.expression_undeclared_identifiers
+        ).difference(
+            self.function_decl.allargnames
+        )
+
+
+class BlockTag(Tag):
+    __keyword__ = 'block'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        expressions = ['buffered', 'cached', 'args'] + [
+            c for c in attributes if c.startswith('cache_')]
+
+        super(BlockTag, self).__init__(
+            keyword,
+            attributes,
+            expressions,
+            ('name', 'filter', 'decorator'),
+            (),
+            **kwargs)
+        name = attributes.get('name')
+        if name and not re.match(r'^[\w_]+$', name):
+            raise exceptions.CompileException(
+                "%block may not specify an argument signature",
+                **self.exception_kwargs)
+        if not name and attributes.get('args', None):
+            raise exceptions.CompileException(
+                "Only named %blocks may specify args",
+                **self.exception_kwargs
+            )
+        self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+                                          **self.exception_kwargs)
+
+        self.name = name
+        self.decorator = attributes.get('decorator', '')
+        self.filter_args = ast.ArgumentList(
+            attributes.get('filter', ''),
+            **self.exception_kwargs)
+
+    is_block = True
+
+    @property
+    def is_anonymous(self):
+        return self.name is None
+
+    @property
+    def funcname(self):
+        return self.name or "__M_anon_%d" % (self.lineno, )
+
+    def get_argument_expressions(self, **kw):
+        return self.body_decl.get_argument_expressions(**kw)
+
+    def declared_identifiers(self):
+        return self.body_decl.allargnames
+
+    def undeclared_identifiers(self):
+        return (self.filter_args.
+                undeclared_identifiers.
+                difference(filters.DEFAULT_ESCAPES.keys())
+                ).union(self.expression_undeclared_identifiers)
+
+
+class CallTag(Tag):
+    __keyword__ = 'call'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        super(CallTag, self).__init__(keyword, attributes,
+                                      ('args'), ('expr',), ('expr',), **kwargs)
+        self.expression = attributes['expr']
+        self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
+        self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+                                          **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return self.code.declared_identifiers.union(self.body_decl.allargnames)
+
+    def undeclared_identifiers(self):
+        return self.code.undeclared_identifiers.\
+            difference(self.code.declared_identifiers)
+
+
+class CallNamespaceTag(Tag):
+
+    def __init__(self, namespace, defname, attributes, **kwargs):
+        super(CallNamespaceTag, self).__init__(
+            namespace + ":" + defname,
+            attributes,
+            tuple(attributes.keys()) + ('args', ),
+            (),
+            (),
+            **kwargs)
+
+        self.expression = "%s.%s(%s)" % (
+            namespace,
+            defname,
+            ",".join(["%s=%s" % (k, v) for k, v in
+                      self.parsed_attributes.items()
+                      if k != 'args'])
+        )
+        self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
+        self.body_decl = ast.FunctionArgs(
+            attributes.get('args', ''),
+            **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return self.code.declared_identifiers.union(self.body_decl.allargnames)
+
+    def undeclared_identifiers(self):
+        return self.code.undeclared_identifiers.\
+            difference(self.code.declared_identifiers)
+
+
+class InheritTag(Tag):
+    __keyword__ = 'inherit'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        super(InheritTag, self).__init__(
+            keyword, attributes,
+            ('file',), (), ('file',), **kwargs)
+
+
+class PageTag(Tag):
+    __keyword__ = 'page'
+
+    def __init__(self, keyword, attributes, **kwargs):
+        expressions = \
+            ['cached', 'args', 'expression_filter', 'enable_loop'] + \
+            [c for c in attributes if c.startswith('cache_')]
+
+        super(PageTag, self).__init__(
+            keyword,
+            attributes,
+            expressions,
+            (),
+            (),
+            **kwargs)
+        self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+                                          **self.exception_kwargs)
+        self.filter_args = ast.ArgumentList(
+            attributes.get('expression_filter', ''),
+            **self.exception_kwargs)
+
+    def declared_identifiers(self):
+        return self.body_decl.allargnames
diff --git a/mako/pygen.py b/mako/pygen.py
new file mode 100644 (file)
index 0000000..8514e02
--- /dev/null
@@ -0,0 +1,303 @@
+# mako/pygen.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""utilities for generating and formatting literal Python code."""
+
+import re
+from mako import exceptions
+
+
+class PythonPrinter(object):
+
+    def __init__(self, stream):
+        # indentation counter
+        self.indent = 0
+
+        # a stack storing information about why we incremented
+        # the indentation counter, to help us determine if we
+        # should decrement it
+        self.indent_detail = []
+
+        # the string of whitespace multiplied by the indent
+        # counter to produce a line
+        self.indentstring = "    "
+
+        # the stream we are writing to
+        self.stream = stream
+
+        # current line number
+        self.lineno = 1
+
+        # a list of lines that represents a buffered "block" of code,
+        # which can be later printed relative to an indent level
+        self.line_buffer = []
+
+        self.in_indent_lines = False
+
+        self._reset_multi_line_flags()
+
+        # mapping of generated python lines to template
+        # source lines
+        self.source_map = {}
+
+    def _update_lineno(self, num):
+        self.lineno += num
+
+    def start_source(self, lineno):
+        if self.lineno not in self.source_map:
+            self.source_map[self.lineno] = lineno
+
+    def write_blanks(self, num):
+        self.stream.write("\n" * num)
+        self._update_lineno(num)
+
+    def write_indented_block(self, block):
+        """print a line or lines of python which already contain indentation.
+
+        The indentation of the total block of lines will be adjusted to that of
+        the current indent level."""
+        self.in_indent_lines = False
+        for l in re.split(r'\r?\n', block):
+            self.line_buffer.append(l)
+            self._update_lineno(1)
+
+    def writelines(self, *lines):
+        """print a series of lines of python."""
+        for line in lines:
+            self.writeline(line)
+
+    def writeline(self, line):
+        """print a line of python, indenting it according to the current
+        indent level.
+
+        this also adjusts the indentation counter according to the
+        content of the line.
+
+        """
+
+        if not self.in_indent_lines:
+            self._flush_adjusted_lines()
+            self.in_indent_lines = True
+
+        if (
+            line is None or
+            re.match(r"^\s*#", line) or
+            re.match(r"^\s*$", line)
+        ):
+            hastext = False
+        else:
+            hastext = True
+
+        is_comment = line and len(line) and line[0] == '#'
+
+        # see if this line should decrease the indentation level
+        if (
+            not is_comment and
+            (not hastext or self._is_unindentor(line))
+        ):
+
+            if self.indent > 0:
+                self.indent -= 1
+                # if the indent_detail stack is empty, the user
+                # probably put extra closures - the resulting
+                # module wont compile.
+                if len(self.indent_detail) == 0:
+                    raise exceptions.SyntaxException(
+                        "Too many whitespace closures")
+                self.indent_detail.pop()
+
+        if line is None:
+            return
+
+        # write the line
+        self.stream.write(self._indent_line(line) + "\n")
+        self._update_lineno(len(line.split("\n")))
+
+        # see if this line should increase the indentation level.
+        # note that a line can both decrase (before printing) and
+        # then increase (after printing) the indentation level.
+
+        if re.search(r":[ \t]*(?:#.*)?$", line):
+            # increment indentation count, and also
+            # keep track of what the keyword was that indented us,
+            # if it is a python compound statement keyword
+            # where we might have to look for an "unindent" keyword
+            match = re.match(r"^\s*(if|try|elif|while|for|with)", line)
+            if match:
+                # its a "compound" keyword, so we will check for "unindentors"
+                indentor = match.group(1)
+                self.indent += 1
+                self.indent_detail.append(indentor)
+            else:
+                indentor = None
+                # its not a "compound" keyword.  but lets also
+                # test for valid Python keywords that might be indenting us,
+                # else assume its a non-indenting line
+                m2 = re.match(r"^\s*(def|class|else|elif|except|finally)",
+                              line)
+                if m2:
+                    self.indent += 1
+                    self.indent_detail.append(indentor)
+
+    def close(self):
+        """close this printer, flushing any remaining lines."""
+        self._flush_adjusted_lines()
+
+    def _is_unindentor(self, line):
+        """return true if the given line is an 'unindentor',
+        relative to the last 'indent' event received.
+
+        """
+
+        # no indentation detail has been pushed on; return False
+        if len(self.indent_detail) == 0:
+            return False
+
+        indentor = self.indent_detail[-1]
+
+        # the last indent keyword we grabbed is not a
+        # compound statement keyword; return False
+        if indentor is None:
+            return False
+
+        # if the current line doesnt have one of the "unindentor" keywords,
+        # return False
+        match = re.match(r"^\s*(else|elif|except|finally).*\:", line)
+        if not match:
+            return False
+
+        # whitespace matches up, we have a compound indentor,
+        # and this line has an unindentor, this
+        # is probably good enough
+        return True
+
+        # should we decide that its not good enough, heres
+        # more stuff to check.
+        # keyword = match.group(1)
+
+        # match the original indent keyword
+        # for crit in [
+        #   (r'if|elif', r'else|elif'),
+        #   (r'try', r'except|finally|else'),
+        #   (r'while|for', r'else'),
+        # ]:
+        #   if re.match(crit[0], indentor) and re.match(crit[1], keyword):
+        #        return True
+
+        # return False
+
+    def _indent_line(self, line, stripspace=''):
+        """indent the given line according to the current indent level.
+
+        stripspace is a string of space that will be truncated from the
+        start of the line before indenting."""
+
+        return re.sub(r"^%s" % stripspace, self.indentstring
+                      * self.indent, line)
+
+    def _reset_multi_line_flags(self):
+        """reset the flags which would indicate we are in a backslashed
+        or triple-quoted section."""
+
+        self.backslashed, self.triplequoted = False, False
+
+    def _in_multi_line(self, line):
+        """return true if the given line is part of a multi-line block,
+        via backslash or triple-quote."""
+
+        # we are only looking for explicitly joined lines here, not
+        # implicit ones (i.e. brackets, braces etc.).  this is just to
+        # guard against the possibility of modifying the space inside of
+        # a literal multiline string with unfortunately placed
+        # whitespace
+
+        current_state = (self.backslashed or self.triplequoted)
+
+        if re.search(r"\\$", line):
+            self.backslashed = True
+        else:
+            self.backslashed = False
+
+        triples = len(re.findall(r"\"\"\"|\'\'\'", line))
+        if triples == 1 or triples % 2 != 0:
+            self.triplequoted = not self.triplequoted
+
+        return current_state
+
+    def _flush_adjusted_lines(self):
+        stripspace = None
+        self._reset_multi_line_flags()
+
+        for entry in self.line_buffer:
+            if self._in_multi_line(entry):
+                self.stream.write(entry + "\n")
+            else:
+                entry = entry.expandtabs()
+                if stripspace is None and re.search(r"^[ \t]*[^# \t]", entry):
+                    stripspace = re.match(r"^([ \t]*)", entry).group(1)
+                self.stream.write(self._indent_line(entry, stripspace) + "\n")
+
+        self.line_buffer = []
+        self._reset_multi_line_flags()
+
+
+def adjust_whitespace(text):
+    """remove the left-whitespace margin of a block of Python code."""
+
+    state = [False, False]
+    (backslashed, triplequoted) = (0, 1)
+
+    def in_multi_line(line):
+        start_state = (state[backslashed] or state[triplequoted])
+
+        if re.search(r"\\$", line):
+            state[backslashed] = True
+        else:
+            state[backslashed] = False
+
+        def match(reg, t):
+            m = re.match(reg, t)
+            if m:
+                return m, t[len(m.group(0)):]
+            else:
+                return None, t
+
+        while line:
+            if state[triplequoted]:
+                m, line = match(r"%s" % state[triplequoted], line)
+                if m:
+                    state[triplequoted] = False
+                else:
+                    m, line = match(r".*?(?=%s|$)" % state[triplequoted], line)
+            else:
+                m, line = match(r'#', line)
+                if m:
+                    return start_state
+
+                m, line = match(r"\"\"\"|\'\'\'", line)
+                if m:
+                    state[triplequoted] = m.group(0)
+                    continue
+
+                m, line = match(r".*?(?=\"\"\"|\'\'\'|#|$)", line)
+
+        return start_state
+
+    def _indent_line(line, stripspace=''):
+        return re.sub(r"^%s" % stripspace, '', line)
+
+    lines = []
+    stripspace = None
+
+    for line in re.split(r'\r?\n', text):
+        if in_multi_line(line):
+            lines.append(line)
+        else:
+            line = line.expandtabs()
+            if stripspace is None and re.search(r"^[ \t]*[^# \t]", line):
+                stripspace = re.match(r"^([ \t]*)", line).group(1)
+            lines.append(_indent_line(line, stripspace))
+    return "\n".join(lines)
diff --git a/mako/pyparser.py b/mako/pyparser.py
new file mode 100644 (file)
index 0000000..15d0da6
--- /dev/null
@@ -0,0 +1,233 @@
+# mako/pyparser.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Handles parsing of Python code.
+
+Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler
+module is used.
+"""
+
+from mako import exceptions, util, compat
+from mako.compat import arg_stringname
+import operator
+
+if compat.py3k:
+    # words that cannot be assigned to (notably
+    # smaller than the total keys in __builtins__)
+    reserved = set(['True', 'False', 'None', 'print'])
+
+    # the "id" attribute on a function node
+    arg_id = operator.attrgetter('arg')
+else:
+    # words that cannot be assigned to (notably
+    # smaller than the total keys in __builtins__)
+    reserved = set(['True', 'False', 'None'])
+
+    # the "id" attribute on a function node
+    arg_id = operator.attrgetter('id')
+
+import _ast
+util.restore__ast(_ast)
+from mako import _ast_util
+
+
+def parse(code, mode='exec', **exception_kwargs):
+    """Parse an expression into AST"""
+
+    try:
+        return _ast_util.parse(code, '<unknown>', mode)
+    except Exception:
+        raise exceptions.SyntaxException(
+            "(%s) %s (%r)" % (
+                compat.exception_as().__class__.__name__,
+                compat.exception_as(),
+                code[0:50]
+            ), **exception_kwargs)
+
+
+class FindIdentifiers(_ast_util.NodeVisitor):
+
+    def __init__(self, listener, **exception_kwargs):
+        self.in_function = False
+        self.in_assign_targets = False
+        self.local_ident_stack = set()
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
+
+    def _add_declared(self, name):
+        if not self.in_function:
+            self.listener.declared_identifiers.add(name)
+        else:
+            self.local_ident_stack.add(name)
+
+    def visit_ClassDef(self, node):
+        self._add_declared(node.name)
+
+    def visit_Assign(self, node):
+
+        # flip around the visiting of Assign so the expression gets
+        # evaluated first, in the case of a clause like "x=x+5" (x
+        # is undeclared)
+
+        self.visit(node.value)
+        in_a = self.in_assign_targets
+        self.in_assign_targets = True
+        for n in node.targets:
+            self.visit(n)
+        self.in_assign_targets = in_a
+
+    if compat.py3k:
+
+        # ExceptHandler is in Python 2, but this block only works in
+        # Python 3 (and is required there)
+
+        def visit_ExceptHandler(self, node):
+            if node.name is not None:
+                self._add_declared(node.name)
+            if node.type is not None:
+                self.visit(node.type)
+            for statement in node.body:
+                self.visit(statement)
+
+    def visit_Lambda(self, node, *args):
+        self._visit_function(node, True)
+
+    def visit_FunctionDef(self, node):
+        self._add_declared(node.name)
+        self._visit_function(node, False)
+
+    def _expand_tuples(self, args):
+        for arg in args:
+            if isinstance(arg, _ast.Tuple):
+                for n in arg.elts:
+                    yield n
+            else:
+                yield arg
+
+    def _visit_function(self, node, islambda):
+
+        # push function state onto stack.  dont log any more
+        # identifiers as "declared" until outside of the function,
+        # but keep logging identifiers as "undeclared". track
+        # argument names in each function header so they arent
+        # counted as "undeclared"
+
+        inf = self.in_function
+        self.in_function = True
+
+        local_ident_stack = self.local_ident_stack
+        self.local_ident_stack = local_ident_stack.union([
+            arg_id(arg) for arg in self._expand_tuples(node.args.args)
+        ])
+        if islambda:
+            self.visit(node.body)
+        else:
+            for n in node.body:
+                self.visit(n)
+        self.in_function = inf
+        self.local_ident_stack = local_ident_stack
+
+    def visit_For(self, node):
+
+        # flip around visit
+
+        self.visit(node.iter)
+        self.visit(node.target)
+        for statement in node.body:
+            self.visit(statement)
+        for statement in node.orelse:
+            self.visit(statement)
+
+    def visit_Name(self, node):
+        if isinstance(node.ctx, _ast.Store):
+            # this is eqiuvalent to visit_AssName in
+            # compiler
+            self._add_declared(node.id)
+        elif node.id not in reserved and node.id \
+            not in self.listener.declared_identifiers and node.id \
+                not in self.local_ident_stack:
+            self.listener.undeclared_identifiers.add(node.id)
+
+    def visit_Import(self, node):
+        for name in node.names:
+            if name.asname is not None:
+                self._add_declared(name.asname)
+            else:
+                self._add_declared(name.name.split('.')[0])
+
+    def visit_ImportFrom(self, node):
+        for name in node.names:
+            if name.asname is not None:
+                self._add_declared(name.asname)
+            else:
+                if name.name == '*':
+                    raise exceptions.CompileException(
+                        "'import *' is not supported, since all identifier "
+                        "names must be explicitly declared.  Please use the "
+                        "form 'from <modulename> import <name1>, <name2>, "
+                        "...' instead.", **self.exception_kwargs)
+                self._add_declared(name.name)
+
+
+class FindTuple(_ast_util.NodeVisitor):
+
+    def __init__(self, listener, code_factory, **exception_kwargs):
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
+        self.code_factory = code_factory
+
+    def visit_Tuple(self, node):
+        for n in node.elts:
+            p = self.code_factory(n, **self.exception_kwargs)
+            self.listener.codeargs.append(p)
+            self.listener.args.append(ExpressionGenerator(n).value())
+            self.listener.declared_identifiers = \
+                self.listener.declared_identifiers.union(
+                    p.declared_identifiers)
+            self.listener.undeclared_identifiers = \
+                self.listener.undeclared_identifiers.union(
+                    p.undeclared_identifiers)
+
+
+class ParseFunc(_ast_util.NodeVisitor):
+
+    def __init__(self, listener, **exception_kwargs):
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
+
+    def visit_FunctionDef(self, node):
+        self.listener.funcname = node.name
+
+        argnames = [arg_id(arg) for arg in node.args.args]
+        if node.args.vararg:
+            argnames.append(arg_stringname(node.args.vararg))
+
+        if compat.py2k:
+            # kw-only args don't exist in Python 2
+            kwargnames = []
+        else:
+            kwargnames = [arg_id(arg) for arg in node.args.kwonlyargs]
+        if node.args.kwarg:
+            kwargnames.append(arg_stringname(node.args.kwarg))
+        self.listener.argnames = argnames
+        self.listener.defaults = node.args.defaults  # ast
+        self.listener.kwargnames = kwargnames
+        if compat.py2k:
+            self.listener.kwdefaults = []
+        else:
+            self.listener.kwdefaults = node.args.kw_defaults
+        self.listener.varargs = node.args.vararg
+        self.listener.kwargs = node.args.kwarg
+
+
+class ExpressionGenerator(object):
+
+    def __init__(self, astnode):
+        self.generator = _ast_util.SourceGenerator(' ' * 4)
+        self.generator.visit(astnode)
+
+    def value(self):
+        return ''.join(self.generator.result)
diff --git a/mako/runtime.py b/mako/runtime.py
new file mode 100644 (file)
index 0000000..769541c
--- /dev/null
@@ -0,0 +1,918 @@
+# mako/runtime.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides runtime services for templates, including Context,
+Namespace, and various helper functions."""
+
+from mako import exceptions, util, compat
+from mako.compat import compat_builtins
+import sys
+
+
+class Context(object):
+
+    """Provides runtime namespace, output buffer, and various
+    callstacks for templates.
+
+    See :ref:`runtime_toplevel` for detail on the usage of
+    :class:`.Context`.
+
+     """
+
+    def __init__(self, buffer, **data):
+        self._buffer_stack = [buffer]
+
+        self._data = data
+
+        self._kwargs = data.copy()
+        self._with_template = None
+        self._outputting_as_unicode = None
+        self.namespaces = {}
+
+        # "capture" function which proxies to the
+        # generic "capture" function
+        self._data['capture'] = compat.partial(capture, self)
+
+        # "caller" stack used by def calls with content
+        self.caller_stack = self._data['caller'] = CallerStack()
+
+    def _set_with_template(self, t):
+        self._with_template = t
+        illegal_names = t.reserved_names.intersection(self._data)
+        if illegal_names:
+            raise exceptions.NameConflictError(
+                "Reserved words passed to render(): %s" %
+                ", ".join(illegal_names))
+
+    @property
+    def lookup(self):
+        """Return the :class:`.TemplateLookup` associated
+        with this :class:`.Context`.
+
+        """
+        return self._with_template.lookup
+
+    @property
+    def kwargs(self):
+        """Return the dictionary of top level keyword arguments associated
+        with this :class:`.Context`.
+
+        This dictionary only includes the top-level arguments passed to
+        :meth:`.Template.render`.  It does not include names produced within
+        the template execution such as local variable names or special names
+        such as ``self``, ``next``, etc.
+
+        The purpose of this dictionary is primarily for the case that
+        a :class:`.Template` accepts arguments via its ``<%page>`` tag,
+        which are normally expected to be passed via :meth:`.Template.render`,
+        except the template is being called in an inheritance context,
+        using the ``body()`` method.   :attr:`.Context.kwargs` can then be
+        used to propagate these arguments to the inheriting template::
+
+            ${next.body(**context.kwargs)}
+
+        """
+        return self._kwargs.copy()
+
+    def push_caller(self, caller):
+        """Push a ``caller`` callable onto the callstack for
+        this :class:`.Context`."""
+
+        self.caller_stack.append(caller)
+
+    def pop_caller(self):
+        """Pop a ``caller`` callable onto the callstack for this
+        :class:`.Context`."""
+
+        del self.caller_stack[-1]
+
+    def keys(self):
+        """Return a list of all names established in this :class:`.Context`."""
+
+        return list(self._data.keys())
+
+    def __getitem__(self, key):
+        if key in self._data:
+            return self._data[key]
+        else:
+            return compat_builtins.__dict__[key]
+
+    def _push_writer(self):
+        """push a capturing buffer onto this Context and return
+        the new writer function."""
+
+        buf = util.FastEncodingBuffer()
+        self._buffer_stack.append(buf)
+        return buf.write
+
+    def _pop_buffer_and_writer(self):
+        """pop the most recent capturing buffer from this Context
+        and return the current writer after the pop.
+
+        """
+
+        buf = self._buffer_stack.pop()
+        return buf, self._buffer_stack[-1].write
+
+    def _push_buffer(self):
+        """push a capturing buffer onto this Context."""
+
+        self._push_writer()
+
+    def _pop_buffer(self):
+        """pop the most recent capturing buffer from this Context."""
+
+        return self._buffer_stack.pop()
+
+    def get(self, key, default=None):
+        """Return a value from this :class:`.Context`."""
+
+        return self._data.get(key, compat_builtins.__dict__.get(key, default))
+
+    def write(self, string):
+        """Write a string to this :class:`.Context` object's
+        underlying output buffer."""
+
+        self._buffer_stack[-1].write(string)
+
+    def writer(self):
+        """Return the current writer function."""
+
+        return self._buffer_stack[-1].write
+
+    def _copy(self):
+        c = Context.__new__(Context)
+        c._buffer_stack = self._buffer_stack
+        c._data = self._data.copy()
+        c._kwargs = self._kwargs
+        c._with_template = self._with_template
+        c._outputting_as_unicode = self._outputting_as_unicode
+        c.namespaces = self.namespaces
+        c.caller_stack = self.caller_stack
+        return c
+
+    def _locals(self, d):
+        """Create a new :class:`.Context` with a copy of this
+        :class:`.Context`'s current state,
+        updated with the given dictionary.
+
+        The :attr:`.Context.kwargs` collection remains
+        unaffected.
+
+
+        """
+
+        if not d:
+            return self
+        c = self._copy()
+        c._data.update(d)
+        return c
+
+    def _clean_inheritance_tokens(self):
+        """create a new copy of this :class:`.Context`. with
+        tokens related to inheritance state removed."""
+
+        c = self._copy()
+        x = c._data
+        x.pop('self', None)
+        x.pop('parent', None)
+        x.pop('next', None)
+        return c
+
+
+class CallerStack(list):
+
+    def __init__(self):
+        self.nextcaller = None
+
+    def __nonzero__(self):
+        return self.__bool__()
+
+    def __bool__(self):
+        return len(self) and self._get_caller() and True or False
+
+    def _get_caller(self):
+        # this method can be removed once
+        # codegen MAGIC_NUMBER moves past 7
+        return self[-1]
+
+    def __getattr__(self, key):
+        return getattr(self._get_caller(), key)
+
+    def _push_frame(self):
+        frame = self.nextcaller or None
+        self.append(frame)
+        self.nextcaller = None
+        return frame
+
+    def _pop_frame(self):
+        self.nextcaller = self.pop()
+
+
+class Undefined(object):
+
+    """Represents an undefined value in a template.
+
+    All template modules have a constant value
+    ``UNDEFINED`` present which is an instance of this
+    object.
+
+    """
+
+    def __str__(self):
+        raise NameError("Undefined")
+
+    def __nonzero__(self):
+        return self.__bool__()
+
+    def __bool__(self):
+        return False
+
+UNDEFINED = Undefined()
+STOP_RENDERING = ""
+
+
+class LoopStack(object):
+
+    """a stack for LoopContexts that implements the context manager protocol
+    to automatically pop off the top of the stack on context exit
+    """
+
+    def __init__(self):
+        self.stack = []
+
+    def _enter(self, iterable):
+        self._push(iterable)
+        return self._top
+
+    def _exit(self):
+        self._pop()
+        return self._top
+
+    @property
+    def _top(self):
+        if self.stack:
+            return self.stack[-1]
+        else:
+            return self
+
+    def _pop(self):
+        return self.stack.pop()
+
+    def _push(self, iterable):
+        new = LoopContext(iterable)
+        if self.stack:
+            new.parent = self.stack[-1]
+        return self.stack.append(new)
+
+    def __getattr__(self, key):
+        raise exceptions.RuntimeException("No loop context is established")
+
+    def __iter__(self):
+        return iter(self._top)
+
+
+class LoopContext(object):
+
+    """A magic loop variable.
+    Automatically accessible in any ``% for`` block.
+
+    See the section :ref:`loop_context` for usage
+    notes.
+
+    :attr:`parent` -> :class:`.LoopContext` or ``None``
+        The parent loop, if one exists.
+    :attr:`index` -> `int`
+        The 0-based iteration count.
+    :attr:`reverse_index` -> `int`
+        The number of iterations remaining.
+    :attr:`first` -> `bool`
+        ``True`` on the first iteration, ``False`` otherwise.
+    :attr:`last` -> `bool`
+        ``True`` on the last iteration, ``False`` otherwise.
+    :attr:`even` -> `bool`
+        ``True`` when ``index`` is even.
+    :attr:`odd` -> `bool`
+        ``True`` when ``index`` is odd.
+    """
+
+    def __init__(self, iterable):
+        self._iterable = iterable
+        self.index = 0
+        self.parent = None
+
+    def __iter__(self):
+        for i in self._iterable:
+            yield i
+            self.index += 1
+
+    @util.memoized_instancemethod
+    def __len__(self):
+        return len(self._iterable)
+
+    @property
+    def reverse_index(self):
+        return len(self) - self.index - 1
+
+    @property
+    def first(self):
+        return self.index == 0
+
+    @property
+    def last(self):
+        return self.index == len(self) - 1
+
+    @property
+    def even(self):
+        return not self.odd
+
+    @property
+    def odd(self):
+        return bool(self.index % 2)
+
+    def cycle(self, *values):
+        """Cycle through values as the loop progresses.
+        """
+        if not values:
+            raise ValueError("You must provide values to cycle through")
+        return values[self.index % len(values)]
+
+
+class _NSAttr(object):
+
+    def __init__(self, parent):
+        self.__parent = parent
+
+    def __getattr__(self, key):
+        ns = self.__parent
+        while ns:
+            if hasattr(ns.module, key):
+                return getattr(ns.module, key)
+            else:
+                ns = ns.inherits
+        raise AttributeError(key)
+
+
+class Namespace(object):
+
+    """Provides access to collections of rendering methods, which
+      can be local, from other templates, or from imported modules.
+
+      To access a particular rendering method referenced by a
+      :class:`.Namespace`, use plain attribute access:
+
+      .. sourcecode:: mako
+
+        ${some_namespace.foo(x, y, z)}
+
+      :class:`.Namespace` also contains several built-in attributes
+      described here.
+
+      """
+
+    def __init__(self, name, context,
+                 callables=None, inherits=None,
+                 populate_self=True, calling_uri=None):
+        self.name = name
+        self.context = context
+        self.inherits = inherits
+        if callables is not None:
+            self.callables = dict([(c.__name__, c) for c in callables])
+
+    callables = ()
+
+    module = None
+    """The Python module referenced by this :class:`.Namespace`.
+
+    If the namespace references a :class:`.Template`, then
+    this module is the equivalent of ``template.module``,
+    i.e. the generated module for the template.
+
+    """
+
+    template = None
+    """The :class:`.Template` object referenced by this
+        :class:`.Namespace`, if any.
+
+    """
+
+    context = None
+    """The :class:`.Context` object for this :class:`.Namespace`.
+
+    Namespaces are often created with copies of contexts that
+    contain slightly different data, particularly in inheritance
+    scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one
+    can traverse an entire chain of templates that inherit from
+    one-another.
+
+    """
+
+    filename = None
+    """The path of the filesystem file used for this
+    :class:`.Namespace`'s module or template.
+
+    If this is a pure module-based
+    :class:`.Namespace`, this evaluates to ``module.__file__``. If a
+    template-based namespace, it evaluates to the original
+    template file location.
+
+    """
+
+    uri = None
+    """The URI for this :class:`.Namespace`'s template.
+
+    I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
+
+    This is the equivalent of :attr:`.Template.uri`.
+
+    """
+
+    _templateuri = None
+
+    @util.memoized_property
+    def attr(self):
+        """Access module level attributes by name.
+
+        This accessor allows templates to supply "scalar"
+        attributes which are particularly handy in inheritance
+        relationships.
+
+        .. seealso::
+
+            :ref:`inheritance_attr`
+
+            :ref:`namespace_attr_for_includes`
+
+        """
+        return _NSAttr(self)
+
+    def get_namespace(self, uri):
+        """Return a :class:`.Namespace` corresponding to the given ``uri``.
+
+        If the given ``uri`` is a relative URI (i.e. it does not
+        contain a leading slash ``/``), the ``uri`` is adjusted to
+        be relative to the ``uri`` of the namespace itself. This
+        method is therefore mostly useful off of the built-in
+        ``local`` namespace, described in :ref:`namespace_local`.
+
+        In
+        most cases, a template wouldn't need this function, and
+        should instead use the ``<%namespace>`` tag to load
+        namespaces. However, since all ``<%namespace>`` tags are
+        evaluated before the body of a template ever runs,
+        this method can be used to locate namespaces using
+        expressions that were generated within the body code of
+        the template, or to conditionally use a particular
+        namespace.
+
+        """
+        key = (self, uri)
+        if key in self.context.namespaces:
+            return self.context.namespaces[key]
+        else:
+            ns = TemplateNamespace(uri, self.context._copy(),
+                                   templateuri=uri,
+                                   calling_uri=self._templateuri)
+            self.context.namespaces[key] = ns
+            return ns
+
+    def get_template(self, uri):
+        """Return a :class:`.Template` from the given ``uri``.
+
+        The ``uri`` resolution is relative to the ``uri`` of this
+        :class:`.Namespace` object's :class:`.Template`.
+
+        """
+        return _lookup_template(self.context, uri, self._templateuri)
+
+    def get_cached(self, key, **kwargs):
+        """Return a value from the :class:`.Cache` referenced by this
+        :class:`.Namespace` object's :class:`.Template`.
+
+        The advantage to this method versus direct access to the
+        :class:`.Cache` is that the configuration parameters
+        declared in ``<%page>`` take effect here, thereby calling
+        up the same configured backend as that configured
+        by ``<%page>``.
+
+        """
+
+        return self.cache.get(key, **kwargs)
+
+    @property
+    def cache(self):
+        """Return the :class:`.Cache` object referenced
+        by this :class:`.Namespace` object's
+        :class:`.Template`.
+
+        """
+        return self.template.cache
+
+    def include_file(self, uri, **kwargs):
+        """Include a file at the given ``uri``."""
+
+        _include_file(self.context, uri, self._templateuri, **kwargs)
+
+    def _populate(self, d, l):
+        for ident in l:
+            if ident == '*':
+                for (k, v) in self._get_star():
+                    d[k] = v
+            else:
+                d[ident] = getattr(self, ident)
+
+    def _get_star(self):
+        if self.callables:
+            for key in self.callables:
+                yield (key, self.callables[key])
+
+    def __getattr__(self, key):
+        if key in self.callables:
+            val = self.callables[key]
+        elif self.inherits:
+            val = getattr(self.inherits, key)
+        else:
+            raise AttributeError(
+                "Namespace '%s' has no member '%s'" %
+                (self.name, key))
+        setattr(self, key, val)
+        return val
+
+
+class TemplateNamespace(Namespace):
+
+    """A :class:`.Namespace` specific to a :class:`.Template` instance."""
+
+    def __init__(self, name, context, template=None, templateuri=None,
+                 callables=None, inherits=None,
+                 populate_self=True, calling_uri=None):
+        self.name = name
+        self.context = context
+        self.inherits = inherits
+        if callables is not None:
+            self.callables = dict([(c.__name__, c) for c in callables])
+
+        if templateuri is not None:
+            self.template = _lookup_template(context, templateuri,
+                                             calling_uri)
+            self._templateuri = self.template.module._template_uri
+        elif template is not None:
+            self.template = template
+            self._templateuri = template.module._template_uri
+        else:
+            raise TypeError("'template' argument is required.")
+
+        if populate_self:
+            lclcallable, lclcontext = \
+                _populate_self_namespace(context, self.template,
+                                         self_ns=self)
+
+    @property
+    def module(self):
+        """The Python module referenced by this :class:`.Namespace`.
+
+        If the namespace references a :class:`.Template`, then
+        this module is the equivalent of ``template.module``,
+        i.e. the generated module for the template.
+
+        """
+        return self.template.module
+
+    @property
+    def filename(self):
+        """The path of the filesystem file used for this
+        :class:`.Namespace`'s module or template.
+        """
+        return self.template.filename
+
+    @property
+    def uri(self):
+        """The URI for this :class:`.Namespace`'s template.
+
+        I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
+
+        This is the equivalent of :attr:`.Template.uri`.
+
+        """
+        return self.template.uri
+
+    def _get_star(self):
+        if self.callables:
+            for key in self.callables:
+                yield (key, self.callables[key])
+
+        def get(key):
+            callable_ = self.template._get_def_callable(key)
+            return compat.partial(callable_, self.context)
+        for k in self.template.module._exports:
+            yield (k, get(k))
+
+    def __getattr__(self, key):
+        if key in self.callables:
+            val = self.callables[key]
+        elif self.template.has_def(key):
+            callable_ = self.template._get_def_callable(key)
+            val = compat.partial(callable_, self.context)
+        elif self.inherits:
+            val = getattr(self.inherits, key)
+
+        else:
+            raise AttributeError(
+                "Namespace '%s' has no member '%s'" %
+                (self.name, key))
+        setattr(self, key, val)
+        return val
+
+
+class ModuleNamespace(Namespace):
+
+    """A :class:`.Namespace` specific to a Python module instance."""
+
+    def __init__(self, name, context, module,
+                 callables=None, inherits=None,
+                 populate_self=True, calling_uri=None):
+        self.name = name
+        self.context = context
+        self.inherits = inherits
+        if callables is not None:
+            self.callables = dict([(c.__name__, c) for c in callables])
+
+        mod = __import__(module)
+        for token in module.split('.')[1:]:
+            mod = getattr(mod, token)
+        self.module = mod
+
+    @property
+    def filename(self):
+        """The path of the filesystem file used for this
+        :class:`.Namespace`'s module or template.
+        """
+        return self.module.__file__
+
+    def _get_star(self):
+        if self.callables:
+            for key in self.callables:
+                yield (key, self.callables[key])
+        for key in dir(self.module):
+            if key[0] != '_':
+                callable_ = getattr(self.module, key)
+                if compat.callable(callable_):
+                    yield key, compat.partial(callable_, self.context)
+
+    def __getattr__(self, key):
+        if key in self.callables:
+            val = self.callables[key]
+        elif hasattr(self.module, key):
+            callable_ = getattr(self.module, key)
+            val = compat.partial(callable_, self.context)
+        elif self.inherits:
+            val = getattr(self.inherits, key)
+        else:
+            raise AttributeError(
+                "Namespace '%s' has no member '%s'" %
+                (self.name, key))
+        setattr(self, key, val)
+        return val
+
+
+def supports_caller(func):
+    """Apply a caller_stack compatibility decorator to a plain
+    Python function.
+
+    See the example in :ref:`namespaces_python_modules`.
+
+    """
+
+    def wrap_stackframe(context, *args, **kwargs):
+        context.caller_stack._push_frame()
+        try:
+            return func(context, *args, **kwargs)
+        finally:
+            context.caller_stack._pop_frame()
+    return wrap_stackframe
+
+
+def capture(context, callable_, *args, **kwargs):
+    """Execute the given template def, capturing the output into
+    a buffer.
+
+    See the example in :ref:`namespaces_python_modules`.
+
+    """
+
+    if not compat.callable(callable_):
+        raise exceptions.RuntimeException(
+            "capture() function expects a callable as "
+            "its argument (i.e. capture(func, *args, **kwargs))"
+        )
+    context._push_buffer()
+    try:
+        callable_(*args, **kwargs)
+    finally:
+        buf = context._pop_buffer()
+    return buf.getvalue()
+
+
+def _decorate_toplevel(fn):
+    def decorate_render(render_fn):
+        def go(context, *args, **kw):
+            def y(*args, **kw):
+                return render_fn(context, *args, **kw)
+            try:
+                y.__name__ = render_fn.__name__[7:]
+            except TypeError:
+                # < Python 2.4
+                pass
+            return fn(y)(context, *args, **kw)
+        return go
+    return decorate_render
+
+
+def _decorate_inline(context, fn):
+    def decorate_render(render_fn):
+        dec = fn(render_fn)
+
+        def go(*args, **kw):
+            return dec(context, *args, **kw)
+        return go
+    return decorate_render
+
+
+def _include_file(context, uri, calling_uri, **kwargs):
+    """locate the template from the given uri and include it in
+    the current output."""
+
+    template = _lookup_template(context, uri, calling_uri)
+    (callable_, ctx) = _populate_self_namespace(
+        context._clean_inheritance_tokens(),
+        template)
+    kwargs = _kwargs_for_include(callable_, context._data, **kwargs)
+    if template.include_error_handler:
+        try:
+            callable_(ctx, **kwargs)
+        except Exception:
+            result = template.include_error_handler(ctx, compat.exception_as())
+            if not result:
+                compat.reraise(*sys.exc_info())
+    else:
+        callable_(ctx, **kwargs)
+
+
+def _inherit_from(context, uri, calling_uri):
+    """called by the _inherit method in template modules to set
+    up the inheritance chain at the start of a template's
+    execution."""
+
+    if uri is None:
+        return None
+    template = _lookup_template(context, uri, calling_uri)
+    self_ns = context['self']
+    ih = self_ns
+    while ih.inherits is not None:
+        ih = ih.inherits
+    lclcontext = context._locals({'next': ih})
+    ih.inherits = TemplateNamespace("self:%s" % template.uri,
+                                    lclcontext,
+                                    template=template,
+                                    populate_self=False)
+    context._data['parent'] = lclcontext._data['local'] = ih.inherits
+    callable_ = getattr(template.module, '_mako_inherit', None)
+    if callable_ is not None:
+        ret = callable_(template, lclcontext)
+        if ret:
+            return ret
+
+    gen_ns = getattr(template.module, '_mako_generate_namespaces', None)
+    if gen_ns is not None:
+        gen_ns(context)
+    return (template.callable_, lclcontext)
+
+
+def _lookup_template(context, uri, relativeto):
+    lookup = context._with_template.lookup
+    if lookup is None:
+        raise exceptions.TemplateLookupException(
+            "Template '%s' has no TemplateLookup associated" %
+            context._with_template.uri)
+    uri = lookup.adjust_uri(uri, relativeto)
+    try:
+        return lookup.get_template(uri)
+    except exceptions.TopLevelLookupException:
+        raise exceptions.TemplateLookupException(str(compat.exception_as()))
+
+
+def _populate_self_namespace(context, template, self_ns=None):
+    if self_ns is None:
+        self_ns = TemplateNamespace('self:%s' % template.uri,
+                                    context, template=template,
+                                    populate_self=False)
+    context._data['self'] = context._data['local'] = self_ns
+    if hasattr(template.module, '_mako_inherit'):
+        ret = template.module._mako_inherit(template, context)
+        if ret:
+            return ret
+    return (template.callable_, context)
+
+
+def _render(template, callable_, args, data, as_unicode=False):
+    """create a Context and return the string
+    output of the given template and template callable."""
+
+    if as_unicode:
+        buf = util.FastEncodingBuffer(as_unicode=True)
+    elif template.bytestring_passthrough:
+        buf = compat.StringIO()
+    else:
+        buf = util.FastEncodingBuffer(
+            as_unicode=as_unicode,
+            encoding=template.output_encoding,
+            errors=template.encoding_errors)
+    context = Context(buf, **data)
+    context._outputting_as_unicode = as_unicode
+    context._set_with_template(template)
+
+    _render_context(template, callable_, context, *args,
+                    **_kwargs_for_callable(callable_, data))
+    return context._pop_buffer().getvalue()
+
+
+def _kwargs_for_callable(callable_, data):
+    argspec = compat.inspect_func_args(callable_)
+    # for normal pages, **pageargs is usually present
+    if argspec[2]:
+        return data
+
+    # for rendering defs from the top level, figure out the args
+    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
+    kwargs = {}
+    for arg in namedargs:
+        if arg != 'context' and arg in data and arg not in kwargs:
+            kwargs[arg] = data[arg]
+    return kwargs
+
+
+def _kwargs_for_include(callable_, data, **kwargs):
+    argspec = compat.inspect_func_args(callable_)
+    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
+    for arg in namedargs:
+        if arg != 'context' and arg in data and arg not in kwargs:
+            kwargs[arg] = data[arg]
+    return kwargs
+
+
+def _render_context(tmpl, callable_, context, *args, **kwargs):
+    import mako.template as template
+    # create polymorphic 'self' namespace for this
+    # template with possibly updated context
+    if not isinstance(tmpl, template.DefTemplate):
+        # if main render method, call from the base of the inheritance stack
+        (inherit, lclcontext) = _populate_self_namespace(context, tmpl)
+        _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
+    else:
+        # otherwise, call the actual rendering method specified
+        (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
+        _exec_template(callable_, context, args=args, kwargs=kwargs)
+
+
+def _exec_template(callable_, context, args=None, kwargs=None):
+    """execute a rendering callable given the callable, a
+    Context, and optional explicit arguments
+
+    the contextual Template will be located if it exists, and
+    the error handling options specified on that Template will
+    be interpreted here.
+    """
+    template = context._with_template
+    if template is not None and \
+            (template.format_exceptions or template.error_handler):
+        try:
+            callable_(context, *args, **kwargs)
+        except Exception:
+            _render_error(template, context, compat.exception_as())
+        except:
+            e = sys.exc_info()[0]
+            _render_error(template, context, e)
+    else:
+        callable_(context, *args, **kwargs)
+
+
+def _render_error(template, context, error):
+    if template.error_handler:
+        result = template.error_handler(context, error)
+        if not result:
+            compat.reraise(*sys.exc_info())
+    else:
+        error_template = exceptions.html_error_template()
+        if context._outputting_as_unicode:
+            context._buffer_stack[:] = [
+                util.FastEncodingBuffer(as_unicode=True)]
+        else:
+            context._buffer_stack[:] = [util.FastEncodingBuffer(
+                error_template.output_encoding,
+                error_template.encoding_errors)]
+
+        context._set_with_template(error_template)
+        error_template.render_context(context, error=error)
diff --git a/mako/template.py b/mako/template.py
new file mode 100644 (file)
index 0000000..c3e0c25
--- /dev/null
@@ -0,0 +1,746 @@
+# mako/template.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Provides the Template class, a facade for parsing, generating and executing
+template strings, as well as template runtime operations."""
+
+from mako.lexer import Lexer
+from mako import runtime, util, exceptions, codegen, cache, compat
+import os
+import re
+import shutil
+import stat
+import sys
+import tempfile
+import types
+import weakref
+
+
+class Template(object):
+
+    """Represents a compiled template.
+
+    :class:`.Template` includes a reference to the original
+    template source (via the :attr:`.source` attribute)
+    as well as the source code of the
+    generated Python module (i.e. the :attr:`.code` attribute),
+    as well as a reference to an actual Python module.
+
+    :class:`.Template` is constructed using either a literal string
+    representing the template text, or a filename representing a filesystem
+    path to a source file.
+
+    :param text: textual template source.  This argument is mutually
+     exclusive versus the ``filename`` parameter.
+
+    :param filename: filename of the source template.  This argument is
+     mutually exclusive versus the ``text`` parameter.
+
+    :param buffer_filters: string list of filters to be applied
+     to the output of ``%def``\ s which are buffered, cached, or otherwise
+     filtered, after all filters
+     defined with the ``%def`` itself have been applied. Allows the
+     creation of default expression filters that let the output
+     of return-valued ``%def``\ s "opt out" of that filtering via
+     passing special attributes or objects.
+
+    :param bytestring_passthrough: When ``True``, and ``output_encoding`` is
+     set to ``None``, and :meth:`.Template.render` is used to render,
+     the `StringIO` or `cStringIO` buffer will be used instead of the
+     default "fast" buffer.   This allows raw bytestrings in the
+     output stream, such as in expressions, to pass straight
+     through to the buffer.  This flag is forced
+     to ``True`` if ``disable_unicode`` is also configured.
+
+     .. versionadded:: 0.4
+        Added to provide the same behavior as that of the previous series.
+
+    :param cache_args: Dictionary of cache configuration arguments that
+     will be passed to the :class:`.CacheImpl`.   See :ref:`caching_toplevel`.
+
+    :param cache_dir:
+
+     .. deprecated:: 0.6
+        Use the ``'dir'`` argument in the ``cache_args`` dictionary.
+        See :ref:`caching_toplevel`.
+
+    :param cache_enabled: Boolean flag which enables caching of this
+     template.  See :ref:`caching_toplevel`.
+
+    :param cache_impl: String name of a :class:`.CacheImpl` caching
+     implementation to use.   Defaults to ``'beaker'``.
+
+    :param cache_type:
+
+     .. deprecated:: 0.6
+        Use the ``'type'`` argument in the ``cache_args`` dictionary.
+        See :ref:`caching_toplevel`.
+
+    :param cache_url:
+
+     .. deprecated:: 0.6
+        Use the ``'url'`` argument in the ``cache_args`` dictionary.
+        See :ref:`caching_toplevel`.
+
+    :param default_filters: List of string filter names that will
+     be applied to all expressions.  See :ref:`filtering_default_filters`.
+
+    :param disable_unicode: Disables all awareness of Python Unicode
+     objects.  See :ref:`unicode_disabled`.
+
+    :param enable_loop: When ``True``, enable the ``loop`` context variable.
+     This can be set to ``False`` to support templates that may
+     be making usage of the name "``loop``".   Individual templates can
+     re-enable the "loop" context by placing the directive
+     ``enable_loop="True"`` inside the ``<%page>`` tag -- see
+     :ref:`migrating_loop`.
+
+    :param encoding_errors: Error parameter passed to ``encode()`` when
+     string encoding is performed. See :ref:`usage_unicode`.
+
+    :param error_handler: Python callable which is called whenever
+     compile or runtime exceptions occur. The callable is passed
+     the current context as well as the exception. If the
+     callable returns ``True``, the exception is considered to
+     be handled, else it is re-raised after the function
+     completes. Is used to provide custom error-rendering
+     functions.
+
+     .. seealso::
+
+        :paramref:`.Template.include_error_handler` - include-specific
+        error handler function
+
+    :param format_exceptions: if ``True``, exceptions which occur during
+     the render phase of this template will be caught and
+     formatted into an HTML error page, which then becomes the
+     rendered result of the :meth:`.render` call. Otherwise,
+     runtime exceptions are propagated outwards.
+
+    :param imports: String list of Python statements, typically individual
+     "import" lines, which will be placed into the module level
+     preamble of all generated Python modules. See the example
+     in :ref:`filtering_default_filters`.
+
+    :param future_imports: String list of names to import from `__future__`.
+     These will be concatenated into a comma-separated string and inserted
+     into the beginning of the template, e.g. ``futures_imports=['FOO',
+     'BAR']`` results in ``from __future__ import FOO, BAR``.  If you're
+     interested in using features like the new division operator, you must
+     use future_imports to convey that to the renderer, as otherwise the
+     import will not appear as the first executed statement in the generated
+     code and will therefore not have the desired effect.
+
+    :param include_error_handler: An error handler that runs when this template
+     is included within another one via the ``<%include>`` tag, and raises an
+     error.  Compare to the :paramref:`.Template.error_handler` option.
+
+     .. versionadded:: 1.0.6
+
+     .. seealso::
+
+        :paramref:`.Template.error_handler` - top-level error handler function
+
+    :param input_encoding: Encoding of the template's source code.  Can
+     be used in lieu of the coding comment. See
+     :ref:`usage_unicode` as well as :ref:`unicode_toplevel` for
+     details on source encoding.
+
+    :param lookup: a :class:`.TemplateLookup` instance that will be used
+     for all file lookups via the ``<%namespace>``,
+     ``<%include>``, and ``<%inherit>`` tags. See
+     :ref:`usage_templatelookup`.
+
+    :param module_directory: Filesystem location where generated
+     Python module files will be placed.
+
+    :param module_filename: Overrides the filename of the generated
+     Python module file. For advanced usage only.
+
+    :param module_writer: A callable which overrides how the Python
+     module is written entirely.  The callable is passed the
+     encoded source content of the module and the destination
+     path to be written to.   The default behavior of module writing
+     uses a tempfile in conjunction with a file move in order
+     to make the operation atomic.   So a user-defined module
+     writing function that mimics the default behavior would be:
+
+     .. sourcecode:: python
+
+         import tempfile
+         import os
+         import shutil
+
+         def module_writer(source, outputpath):
+             (dest, name) = \\
+                 tempfile.mkstemp(
+                     dir=os.path.dirname(outputpath)
+                 )
+
+             os.write(dest, source)
+             os.close(dest)
+             shutil.move(name, outputpath)
+
+         from mako.template import Template
+         mytemplate = Template(
+                         filename="index.html",
+                         module_directory="/path/to/modules",
+                         module_writer=module_writer
+                     )
+
+     The function is provided for unusual configurations where
+     certain platform-specific permissions or other special
+     steps are needed.
+
+    :param output_encoding: The encoding to use when :meth:`.render`
+     is called.
+     See :ref:`usage_unicode` as well as :ref:`unicode_toplevel`.
+
+    :param preprocessor: Python callable which will be passed
+     the full template source before it is parsed. The return
+     result of the callable will be used as the template source
+     code.
+
+    :param lexer_cls: A :class:`.Lexer` class used to parse
+     the template.   The :class:`.Lexer` class is used by
+     default.
+
+     .. versionadded:: 0.7.4
+
+    :param strict_undefined: Replaces the automatic usage of
+     ``UNDEFINED`` for any undeclared variables not located in
+     the :class:`.Context` with an immediate raise of
+     ``NameError``. The advantage is immediate reporting of
+     missing variables which include the name.
+
+     .. versionadded:: 0.3.6
+
+    :param uri: string URI or other identifier for this template.
+     If not provided, the ``uri`` is generated from the filesystem
+     path, or from the in-memory identity of a non-file-based
+     template. The primary usage of the ``uri`` is to provide a key
+     within :class:`.TemplateLookup`, as well as to generate the
+     file path of the generated Python module file, if
+     ``module_directory`` is specified.
+
+    """
+
+    lexer_cls = Lexer
+
+    def __init__(self,
+                 text=None,
+                 filename=None,
+                 uri=None,
+                 format_exceptions=False,
+                 error_handler=None,
+                 lookup=None,
+                 output_encoding=None,
+                 encoding_errors='strict',
+                 module_directory=None,
+                 cache_args=None,
+                 cache_impl='beaker',
+                 cache_enabled=True,
+                 cache_type=None,
+                 cache_dir=None,
+                 cache_url=None,
+                 module_filename=None,
+                 input_encoding=None,
+                 disable_unicode=False,
+                 module_writer=None,
+                 bytestring_passthrough=False,
+                 default_filters=None,
+                 buffer_filters=(),
+                 strict_undefined=False,
+                 imports=None,
+                 future_imports=None,
+                 enable_loop=True,
+                 preprocessor=None,
+                 lexer_cls=None,
+                 include_error_handler=None):
+        if uri:
+            self.module_id = re.sub(r'\W', "_", uri)
+            self.uri = uri
+        elif filename:
+            self.module_id = re.sub(r'\W', "_", filename)
+            drive, path = os.path.splitdrive(filename)
+            path = os.path.normpath(path).replace(os.path.sep, "/")
+            self.uri = path
+        else:
+            self.module_id = "memory:" + hex(id(self))
+            self.uri = self.module_id
+
+        u_norm = self.uri
+        if u_norm.startswith("/"):
+            u_norm = u_norm[1:]
+        u_norm = os.path.normpath(u_norm)
+        if u_norm.startswith(".."):
+            raise exceptions.TemplateLookupException(
+                "Template uri \"%s\" is invalid - "
+                "it cannot be relative outside "
+                "of the root path." % self.uri)
+
+        self.input_encoding = input_encoding
+        self.output_encoding = output_encoding
+        self.encoding_errors = encoding_errors
+        self.disable_unicode = disable_unicode
+        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
+        self.enable_loop = enable_loop
+        self.strict_undefined = strict_undefined
+        self.module_writer = module_writer
+
+        if compat.py3k and disable_unicode:
+            raise exceptions.UnsupportedError(
+                "Mako for Python 3 does not "
+                "support disabling Unicode")
+        elif output_encoding and disable_unicode:
+            raise exceptions.UnsupportedError(
+                "output_encoding must be set to "
+                "None when disable_unicode is used.")
+        if default_filters is None:
+            if compat.py3k or self.disable_unicode:
+                self.default_filters = ['str']
+            else:
+                self.default_filters = ['unicode']
+        else:
+            self.default_filters = default_filters
+        self.buffer_filters = buffer_filters
+
+        self.imports = imports
+        self.future_imports = future_imports
+        self.preprocessor = preprocessor
+
+        if lexer_cls is not None:
+            self.lexer_cls = lexer_cls
+
+        # if plain text, compile code in memory only
+        if text is not None:
+            (code, module) = _compile_text(self, text, filename)
+            self._code = code
+            self._source = text
+            ModuleInfo(module, None, self, filename, code, text)
+        elif filename is not None:
+            # if template filename and a module directory, load
+            # a filesystem-based module file, generating if needed
+            if module_filename is not None:
+                path = module_filename
+            elif module_directory is not None:
+                path = os.path.abspath(
+                    os.path.join(
+                        os.path.normpath(module_directory),
+                        u_norm + ".py"
+                    )
+                )
+            else:
+                path = None
+            module = self._compile_from_file(path, filename)
+        else:
+            raise exceptions.RuntimeException(
+                "Template requires text or filename")
+
+        self.module = module
+        self.filename = filename
+        self.callable_ = self.module.render_body
+        self.format_exceptions = format_exceptions
+        self.error_handler = error_handler
+        self.include_error_handler = include_error_handler
+        self.lookup = lookup
+
+        self.module_directory = module_directory
+
+        self._setup_cache_args(
+            cache_impl, cache_enabled, cache_args,
+            cache_type, cache_dir, cache_url
+        )
+
+    @util.memoized_property
+    def reserved_names(self):
+        if self.enable_loop:
+            return codegen.RESERVED_NAMES
+        else:
+            return codegen.RESERVED_NAMES.difference(['loop'])
+
+    def _setup_cache_args(self,
+                          cache_impl, cache_enabled, cache_args,
+                          cache_type, cache_dir, cache_url):
+        self.cache_impl = cache_impl
+        self.cache_enabled = cache_enabled
+        if cache_args:
+            self.cache_args = cache_args
+        else:
+            self.cache_args = {}
+
+        # transfer deprecated cache_* args
+        if cache_type:
+            self.cache_args['type'] = cache_type
+        if cache_dir:
+            self.cache_args['dir'] = cache_dir
+        if cache_url:
+            self.cache_args['url'] = cache_url
+
+    def _compile_from_file(self, path, filename):
+        if path is not None:
+            util.verify_directory(os.path.dirname(path))
+            filemtime = os.stat(filename)[stat.ST_MTIME]
+            if not os.path.exists(path) or \
+                    os.stat(path)[stat.ST_MTIME] < filemtime:
+                data = util.read_file(filename)
+                _compile_module_file(
+                    self,
+                    data,
+                    filename,
+                    path,
+                    self.module_writer)
+            module = compat.load_module(self.module_id, path)
+            del sys.modules[self.module_id]
+            if module._magic_number != codegen.MAGIC_NUMBER:
+                data = util.read_file(filename)
+                _compile_module_file(
+                    self,
+                    data,
+                    filename,
+                    path,
+                    self.module_writer)
+                module = compat.load_module(self.module_id, path)
+                del sys.modules[self.module_id]
+            ModuleInfo(module, path, self, filename, None, None)
+        else:
+            # template filename and no module directory, compile code
+            # in memory
+            data = util.read_file(filename)
+            code, module = _compile_text(
+                self,
+                data,
+                filename)
+            self._source = None
+            self._code = code
+            ModuleInfo(module, None, self, filename, code, None)
+        return module
+
+    @property
+    def source(self):
+        """Return the template source code for this :class:`.Template`."""
+
+        return _get_module_info_from_callable(self.callable_).source
+
+    @property
+    def code(self):
+        """Return the module source code for this :class:`.Template`."""
+
+        return _get_module_info_from_callable(self.callable_).code
+
+    @util.memoized_property
+    def cache(self):
+        return cache.Cache(self)
+
+    @property
+    def cache_dir(self):
+        return self.cache_args['dir']
+
+    @property
+    def cache_url(self):
+        return self.cache_args['url']
+
+    @property
+    def cache_type(self):
+        return self.cache_args['type']
+
+    def render(self, *args, **data):
+        """Render the output of this template as a string.
+
+        If the template specifies an output encoding, the string
+        will be encoded accordingly, else the output is raw (raw
+        output uses `cStringIO` and can't handle multibyte
+        characters). A :class:`.Context` object is created corresponding
+        to the given data. Arguments that are explicitly declared
+        by this template's internal rendering method are also
+        pulled from the given ``*args``, ``**data`` members.
+
+        """
+        return runtime._render(self, self.callable_, args, data)
+
+    def render_unicode(self, *args, **data):
+        """Render the output of this template as a unicode object."""
+
+        return runtime._render(self,
+                               self.callable_,
+                               args,
+                               data,
+                               as_unicode=True)
+
+    def render_context(self, context, *args, **kwargs):
+        """Render this :class:`.Template` with the given context.
+
+        The data is written to the context's buffer.
+
+        """
+        if getattr(context, '_with_template', None) is None:
+            context._set_with_template(self)
+        runtime._render_context(self,
+                                self.callable_,
+                                context,
+                                *args,
+                                **kwargs)
+
+    def has_def(self, name):
+        return hasattr(self.module, "render_%s" % name)
+
+    def get_def(self, name):
+        """Return a def of this template as a :class:`.DefTemplate`."""
+
+        return DefTemplate(self, getattr(self.module, "render_%s" % name))
+
+    def list_defs(self):
+        """return a list of defs in the template.
+
+        .. versionadded:: 1.0.4
+
+        """
+        return [i[7:] for i in dir(self.module) if i[:7] == 'render_']
+
+    def _get_def_callable(self, name):
+        return getattr(self.module, "render_%s" % name)
+
+    @property
+    def last_modified(self):
+        return self.module._modified_time
+
+
+class ModuleTemplate(Template):
+
+    """A Template which is constructed given an existing Python module.
+
+        e.g.::
+
+        t = Template("this is a template")
+        f = file("mymodule.py", "w")
+        f.write(t.code)
+        f.close()
+
+        import mymodule
+
+        t = ModuleTemplate(mymodule)
+        print t.render()
+
+    """
+
+    def __init__(self, module,
+                 module_filename=None,
+                 template=None,
+                 template_filename=None,
+                 module_source=None,
+                 template_source=None,
+                 output_encoding=None,
+                 encoding_errors='strict',
+                 disable_unicode=False,
+                 bytestring_passthrough=False,
+                 format_exceptions=False,
+                 error_handler=None,
+                 lookup=None,
+                 cache_args=None,
+                 cache_impl='beaker',
+                 cache_enabled=True,
+                 cache_type=None,
+                 cache_dir=None,
+                 cache_url=None,
+                 include_error_handler=None,
+                 ):
+        self.module_id = re.sub(r'\W', "_", module._template_uri)
+        self.uri = module._template_uri
+        self.input_encoding = module._source_encoding
+        self.output_encoding = output_encoding
+        self.encoding_errors = encoding_errors
+        self.disable_unicode = disable_unicode
+        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
+        self.enable_loop = module._enable_loop
+
+        if compat.py3k and disable_unicode:
+            raise exceptions.UnsupportedError(
+                "Mako for Python 3 does not "
+                "support disabling Unicode")
+        elif output_encoding and disable_unicode:
+            raise exceptions.UnsupportedError(
+                "output_encoding must be set to "
+                "None when disable_unicode is used.")
+
+        self.module = module
+        self.filename = template_filename
+        ModuleInfo(module,
+                   module_filename,
+                   self,
+                   template_filename,
+                   module_source,
+                   template_source)
+
+        self.callable_ = self.module.render_body
+        self.format_exceptions = format_exceptions
+        self.error_handler = error_handler
+        self.include_error_handler = include_error_handler
+        self.lookup = lookup
+        self._setup_cache_args(
+            cache_impl, cache_enabled, cache_args,
+            cache_type, cache_dir, cache_url
+        )
+
+
+class DefTemplate(Template):
+
+    """A :class:`.Template` which represents a callable def in a parent
+    template."""
+
+    def __init__(self, parent, callable_):
+        self.parent = parent
+        self.callable_ = callable_
+        self.output_encoding = parent.output_encoding
+        self.module = parent.module
+        self.encoding_errors = parent.encoding_errors
+        self.format_exceptions = parent.format_exceptions
+        self.error_handler = parent.error_handler
+        self.include_error_handler = parent.include_error_handler
+        self.enable_loop = parent.enable_loop
+        self.lookup = parent.lookup
+        self.bytestring_passthrough = parent.bytestring_passthrough
+
+    def get_def(self, name):
+        return self.parent.get_def(name)
+
+
+class ModuleInfo(object):
+
+    """Stores information about a module currently loaded into
+    memory, provides reverse lookups of template source, module
+    source code based on a module's identifier.
+
+     """
+    _modules = weakref.WeakValueDictionary()
+
+    def __init__(self,
+                 module,
+                 module_filename,
+                 template,
+                 template_filename,
+                 module_source,
+                 template_source):
+        self.module = module
+        self.module_filename = module_filename
+        self.template_filename = template_filename
+        self.module_source = module_source
+        self.template_source = template_source
+        self._modules[module.__name__] = template._mmarker = self
+        if module_filename:
+            self._modules[module_filename] = self
+
+    @classmethod
+    def get_module_source_metadata(cls, module_source, full_line_map=False):
+        source_map = re.search(
+            r"__M_BEGIN_METADATA(.+?)__M_END_METADATA",
+            module_source, re.S).group(1)
+        source_map = compat.json.loads(source_map)
+        source_map['line_map'] = dict(
+            (int(k), int(v))
+            for k, v in source_map['line_map'].items())
+        if full_line_map:
+            f_line_map = source_map['full_line_map'] = []
+            line_map = source_map['line_map']
+
+            curr_templ_line = 1
+            for mod_line in range(1, max(line_map)):
+                if mod_line in line_map:
+                    curr_templ_line = line_map[mod_line]
+                f_line_map.append(curr_templ_line)
+        return source_map
+
+    @property
+    def code(self):
+        if self.module_source is not None:
+            return self.module_source
+        else:
+            return util.read_python_file(self.module_filename)
+
+    @property
+    def source(self):
+        if self.template_source is not None:
+            if self.module._source_encoding and \
+                    not isinstance(self.template_source, compat.text_type):
+                return self.template_source.decode(
+                    self.module._source_encoding)
+            else:
+                return self.template_source
+        else:
+            data = util.read_file(self.template_filename)
+            if self.module._source_encoding:
+                return data.decode(self.module._source_encoding)
+            else:
+                return data
+
+
+def _compile(template, text, filename, generate_magic_comment):
+    lexer = template.lexer_cls(text,
+                               filename,
+                               disable_unicode=template.disable_unicode,
+                               input_encoding=template.input_encoding,
+                               preprocessor=template.preprocessor)
+    node = lexer.parse()
+    source = codegen.compile(node,
+                             template.uri,
+                             filename,
+                             default_filters=template.default_filters,
+                             buffer_filters=template.buffer_filters,
+                             imports=template.imports,
+                             future_imports=template.future_imports,
+                             source_encoding=lexer.encoding,
+                             generate_magic_comment=generate_magic_comment,
+                             disable_unicode=template.disable_unicode,
+                             strict_undefined=template.strict_undefined,
+                             enable_loop=template.enable_loop,
+                             reserved_names=template.reserved_names)
+    return source, lexer
+
+
+def _compile_text(template, text, filename):
+    identifier = template.module_id
+    source, lexer = _compile(template, text, filename,
+                             generate_magic_comment=template.disable_unicode)
+
+    cid = identifier
+    if not compat.py3k and isinstance(cid, compat.text_type):
+        cid = cid.encode()
+    module = types.ModuleType(cid)
+    code = compile(source, cid, 'exec')
+
+    # this exec() works for 2.4->3.3.
+    exec(code, module.__dict__, module.__dict__)
+    return (source, module)
+
+
+def _compile_module_file(template, text, filename, outputpath, module_writer):
+    source, lexer = _compile(template, text, filename,
+                             generate_magic_comment=True)
+
+    if isinstance(source, compat.text_type):
+        source = source.encode(lexer.encoding or 'ascii')
+
+    if module_writer:
+        module_writer(source, outputpath)
+    else:
+        # make tempfiles in the same location as the ultimate
+        # location.   this ensures they're on the same filesystem,
+        # avoiding synchronization issues.
+        (dest, name) = tempfile.mkstemp(dir=os.path.dirname(outputpath))
+
+        os.write(dest, source)
+        os.close(dest)
+        shutil.move(name, outputpath)
+
+
+def _get_module_info_from_callable(callable_):
+    if compat.py3k:
+        return _get_module_info(callable_.__globals__['__name__'])
+    else:
+        return _get_module_info(callable_.func_globals['__name__'])
+
+
+def _get_module_info(filename):
+    return ModuleInfo._modules[filename]
diff --git a/mako/util.py b/mako/util.py
new file mode 100644 (file)
index 0000000..2f089ff
--- /dev/null
@@ -0,0 +1,382 @@
+# mako/util.py
+# Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+import re
+import collections
+import codecs
+import os
+from mako import compat
+import operator
+
+
+def update_wrapper(decorated, fn):
+    decorated.__wrapped__ = fn
+    decorated.__name__ = fn.__name__
+    return decorated
+
+
+class PluginLoader(object):
+
+    def __init__(self, group):
+        self.group = group
+        self.impls = {}
+
+    def load(self, name):
+        if name in self.impls:
+            return self.impls[name]()
+        else:
+            import pkg_resources
+            for impl in pkg_resources.iter_entry_points(
+                    self.group,
+                    name):
+                self.impls[name] = impl.load
+                return impl.load()
+            else:
+                from mako import exceptions
+                raise exceptions.RuntimeException(
+                    "Can't load plugin %s %s" %
+                    (self.group, name))
+
+    def register(self, name, modulepath, objname):
+        def load():
+            mod = __import__(modulepath)
+            for token in modulepath.split(".")[1:]:
+                mod = getattr(mod, token)
+            return getattr(mod, objname)
+        self.impls[name] = load
+
+
+def verify_directory(dir):
+    """create and/or verify a filesystem directory."""
+
+    tries = 0
+
+    while not os.path.exists(dir):
+        try:
+            tries += 1
+            os.makedirs(dir, compat.octal("0775"))
+        except:
+            if tries > 5:
+                raise
+
+
+def to_list(x, default=None):
+    if x is None:
+        return default
+    if not isinstance(x, (list, tuple)):
+        return [x]
+    else:
+        return x
+
+
+class memoized_property(object):
+
+    """A read-only @property that is only evaluated once."""
+
+    def __init__(self, fget, doc=None):
+        self.fget = fget
+        self.__doc__ = doc or fget.__doc__
+        self.__name__ = fget.__name__
+
+    def __get__(self, obj, cls):
+        if obj is None:
+            return self
+        obj.__dict__[self.__name__] = result = self.fget(obj)
+        return result
+
+
+class memoized_instancemethod(object):
+
+    """Decorate a method memoize its return value.
+
+    Best applied to no-arg methods: memoization is not sensitive to
+    argument values, and will always return the same value even when
+    called with different arguments.
+
+    """
+
+    def __init__(self, fget, doc=None):
+        self.fget = fget
+        self.__doc__ = doc or fget.__doc__
+        self.__name__ = fget.__name__
+
+    def __get__(self, obj, cls):
+        if obj is None:
+            return self
+
+        def oneshot(*args, **kw):
+            result = self.fget(obj, *args, **kw)
+            memo = lambda *a, **kw: result
+            memo.__name__ = self.__name__
+            memo.__doc__ = self.__doc__
+            obj.__dict__[self.__name__] = memo
+            return result
+        oneshot.__name__ = self.__name__
+        oneshot.__doc__ = self.__doc__
+        return oneshot
+
+
+class SetLikeDict(dict):
+
+    """a dictionary that has some setlike methods on it"""
+
+    def union(self, other):
+        """produce a 'union' of this dict and another (at the key level).
+
+        values in the second dict take precedence over that of the first"""
+        x = SetLikeDict(**self)
+        x.update(other)
+        return x
+
+
+class FastEncodingBuffer(object):
+
+    """a very rudimentary buffer that is faster than StringIO,
+    but doesn't crash on unicode data like cStringIO."""
+
+    def __init__(self, encoding=None, errors='strict', as_unicode=False):
+        self.data = collections.deque()
+        self.encoding = encoding
+        if as_unicode:
+            self.delim = compat.u('')
+        else:
+            self.delim = ''
+        self.as_unicode = as_unicode
+        self.errors = errors
+        self.write = self.data.append
+
+    def truncate(self):
+        self.data = collections.deque()
+        self.write = self.data.append
+
+    def getvalue(self):
+        if self.encoding:
+            return self.delim.join(self.data).encode(self.encoding,
+                                                     self.errors)
+        else:
+            return self.delim.join(self.data)
+
+
+class LRUCache(dict):
+
+    """A dictionary-like object that stores a limited number of items,
+    discarding lesser used items periodically.
+
+    this is a rewrite of LRUCache from Myghty to use a periodic timestamp-based
+    paradigm so that synchronization is not really needed.  the size management
+    is inexact.
+    """
+
+    class _Item(object):
+
+        def __init__(self, key, value):
+            self.key = key
+            self.value = value
+            self.timestamp = compat.time_func()
+
+        def __repr__(self):
+            return repr(self.value)
+
+    def __init__(self, capacity, threshold=.5):
+        self.capacity = capacity
+        self.threshold = threshold
+
+    def __getitem__(self, key):
+        item = dict.__getitem__(self, key)
+        item.timestamp = compat.time_func()
+        return item.value
+
+    def values(self):
+        return [i.value for i in dict.values(self)]
+
+    def setdefault(self, key, value):
+        if key in self:
+            return self[key]
+        else:
+            self[key] = value
+            return value
+
+    def __setitem__(self, key, value):
+        item = dict.get(self, key)
+        if item is None:
+            item = self._Item(key, value)
+            dict.__setitem__(self, key, item)
+        else:
+            item.value = value
+        self._manage_size()
+
+    def _manage_size(self):
+        while len(self) > self.capacity + self.capacity * self.threshold:
+            bytime = sorted(dict.values(self),
+                            key=operator.attrgetter('timestamp'), reverse=True)
+            for item in bytime[self.capacity:]:
+                try:
+                    del self[item.key]
+                except KeyError:
+                    # if we couldn't find a key, most likely some other thread
+                    # broke in on us. loop around and try again
+                    break
+
+# Regexp to match python magic encoding line
+_PYTHON_MAGIC_COMMENT_re = re.compile(
+    r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)',
+    re.VERBOSE)
+
+
+def parse_encoding(fp):
+    """Deduce the encoding of a Python source file (binary mode) from magic
+    comment.
+
+    It does this in the same way as the `Python interpreter`__
+
+    .. __: http://docs.python.org/ref/encodings.html
+
+    The ``fp`` argument should be a seekable file object in binary mode.
+    """
+    pos = fp.tell()
+    fp.seek(0)
+    try:
+        line1 = fp.readline()
+        has_bom = line1.startswith(codecs.BOM_UTF8)
+        if has_bom:
+            line1 = line1[len(codecs.BOM_UTF8):]
+
+        m = _PYTHON_MAGIC_COMMENT_re.match(line1.decode('ascii', 'ignore'))
+        if not m:
+            try:
+                import parser
+                parser.suite(line1.decode('ascii', 'ignore'))
+            except (ImportError, SyntaxError):
+                # Either it's a real syntax error, in which case the source
+                # is not valid python source, or line2 is a continuation of
+                # line1, in which case we don't want to scan line2 for a magic
+                # comment.
+                pass
+            else:
+                line2 = fp.readline()
+                m = _PYTHON_MAGIC_COMMENT_re.match(
+                    line2.decode('ascii', 'ignore'))
+
+        if has_bom:
+            if m:
+                raise SyntaxError(
+                    "python refuses to compile code with both a UTF8"
+                    " byte-order-mark and a magic encoding comment")
+            return 'utf_8'
+        elif m:
+            return m.group(1)
+        else:
+            return None
+    finally:
+        fp.seek(pos)
+
+
+def sorted_dict_repr(d):
+    """repr() a dictionary with the keys in order.
+
+    Used by the lexer unit test to compare parse trees based on strings.
+
+    """
+    keys = list(d.keys())
+    keys.sort()
+    return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}"
+
+
+def restore__ast(_ast):
+    """Attempt to restore the required classes to the _ast module if it
+    appears to be missing them
+    """
+    if hasattr(_ast, 'AST'):
+        return
+    _ast.PyCF_ONLY_AST = 2 << 9
+    m = compile("""\
+def foo(): pass
+class Bar(object): pass
+if False: pass
+baz = 'mako'
+1 + 2 - 3 * 4 / 5
+6 // 7 % 8 << 9 >> 10
+11 & 12 ^ 13 | 14
+15 and 16 or 17
+-baz + (not +18) - ~17
+baz and 'foo' or 'bar'
+(mako is baz == baz) is not baz != mako
+mako > baz < mako >= baz <= mako
+mako in baz not in mako""", '<unknown>', 'exec', _ast.PyCF_ONLY_AST)
+    _ast.Module = type(m)
+
+    for cls in _ast.Module.__mro__:
+        if cls.__name__ == 'mod':
+            _ast.mod = cls
+        elif cls.__name__ == 'AST':
+            _ast.AST = cls
+
+    _ast.FunctionDef = type(m.body[0])
+    _ast.ClassDef = type(m.body[1])
+    _ast.If = type(m.body[2])
+
+    _ast.Name = type(m.body[3].targets[0])
+    _ast.Store = type(m.body[3].targets[0].ctx)
+    _ast.Str = type(m.body[3].value)
+
+    _ast.Sub = type(m.body[4].value.op)
+    _ast.Add = type(m.body[4].value.left.op)
+    _ast.Div = type(m.body[4].value.right.op)
+    _ast.Mult = type(m.body[4].value.right.left.op)
+
+    _ast.RShift = type(m.body[5].value.op)
+    _ast.LShift = type(m.body[5].value.left.op)
+    _ast.Mod = type(m.body[5].value.left.left.op)
+    _ast.FloorDiv = type(m.body[5].value.left.left.left.op)
+
+    _ast.BitOr = type(m.body[6].value.op)
+    _ast.BitXor = type(m.body[6].value.left.op)
+    _ast.BitAnd = type(m.body[6].value.left.left.op)
+
+    _ast.Or = type(m.body[7].value.op)
+    _ast.And = type(m.body[7].value.values[0].op)
+
+    _ast.Invert = type(m.body[8].value.right.op)
+    _ast.Not = type(m.body[8].value.left.right.op)
+    _ast.UAdd = type(m.body[8].value.left.right.operand.op)
+    _ast.USub = type(m.body[8].value.left.left.op)
+
+    _ast.Or = type(m.body[9].value.op)
+    _ast.And = type(m.body[9].value.values[0].op)
+
+    _ast.IsNot = type(m.body[10].value.ops[0])
+    _ast.NotEq = type(m.body[10].value.ops[1])
+    _ast.Is = type(m.body[10].value.left.ops[0])
+    _ast.Eq = type(m.body[10].value.left.ops[1])
+
+    _ast.Gt = type(m.body[11].value.ops[0])
+    _ast.Lt = type(m.body[11].value.ops[1])
+    _ast.GtE = type(m.body[11].value.ops[2])
+    _ast.LtE = type(m.body[11].value.ops[3])
+
+    _ast.In = type(m.body[12].value.ops[0])
+    _ast.NotIn = type(m.body[12].value.ops[1])
+
+
+def read_file(path, mode='rb'):
+    fp = open(path, mode)
+    try:
+        data = fp.read()
+        return data
+    finally:
+        fp.close()
+
+
+def read_python_file(path):
+    fp = open(path, "rb")
+    try:
+        encoding = parse_encoding(fp)
+        data = fp.read()
+        if encoding:
+            data = data.decode(encoding)
+        return data
+    finally:
+        fp.close()
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..37bb374
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,13 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
+[pytest]
+addopts = --tb native -v -r fxX
+python_files = test/*test_*.py
+
+[upload]
+sign = 1
+identity = C4DAFEE1
+
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..5b64d3f
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,96 @@
+from setuptools import setup, find_packages
+from setuptools.command.test import test as TestCommand
+import os
+import re
+import sys
+
+v = open(os.path.join(os.path.dirname(__file__), 'mako', '__init__.py'))
+VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1)
+v.close()
+
+readme = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
+
+if sys.version_info < (2, 6):
+    raise Exception("Mako requires Python 2.6 or higher.")
+
+markupsafe_installs = (
+    sys.version_info >= (2, 6) and sys.version_info < (3, 0)
+) or sys.version_info >= (3, 3)
+
+install_requires = []
+
+if markupsafe_installs:
+    install_requires.append('MarkupSafe>=0.9.2')
+
+try:
+    import argparse
+except ImportError:
+    install_requires.append('argparse')
+
+
+class PyTest(TestCommand):
+    user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
+
+    def initialize_options(self):
+        TestCommand.initialize_options(self)
+        self.pytest_args = []
+
+    def finalize_options(self):
+        TestCommand.finalize_options(self)
+        self.test_args = []
+        self.test_suite = True
+
+    def run_tests(self):
+        # import here, cause outside the eggs aren't loaded
+        import pytest
+        errno = pytest.main(self.pytest_args)
+        sys.exit(errno)
+
+
+setup(name='Mako',
+      version=VERSION,
+      description="A super-fast templating language that borrows the \
+ best ideas from the existing templating languages.",
+      long_description=readme,
+      classifiers=[
+          'Development Status :: 5 - Production/Stable',
+          'Environment :: Web Environment',
+          'Intended Audience :: Developers',
+          'Programming Language :: Python',
+          'Programming Language :: Python :: 3',
+          "Programming Language :: Python :: Implementation :: CPython",
+          "Programming Language :: Python :: Implementation :: PyPy",
+          'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+      ],
+      keywords='templates',
+      author='Mike Bayer',
+      author_email='mike@zzzcomputing.com',
+      url='http://www.makotemplates.org/',
+      license='MIT',
+      packages=find_packages('.', exclude=['examples*', 'test*']),
+      tests_require=['pytest', 'mock'],
+      cmdclass={'test': PyTest},
+      zip_safe=False,
+      install_requires=install_requires,
+      extras_require={},
+      entry_points="""
+      [python.templating.engines]
+      mako = mako.ext.turbogears:TGPlugin
+
+      [pygments.lexers]
+      mako = mako.ext.pygmentplugin:MakoLexer
+      html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
+      xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
+      js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
+      css+mako = mako.ext.pygmentplugin:MakoCssLexer
+
+      [babel.extractors]
+      mako = mako.ext.babelplugin:extract
+
+      [lingua.extractors]
+      mako = mako.ext.linguaplugin:LinguaMakoExtractor
+
+      [console_scripts]
+      mako-render = mako.cmd:cmdline
+      """
+)
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644 (file)
index 0000000..22d1c83
--- /dev/null
@@ -0,0 +1,168 @@
+from mako.template import Template
+import unittest
+import os
+from mako.compat import py3k, py26, py33
+from mako import compat
+from mako.util import update_wrapper
+import re
+from mako.cache import CacheImpl, register_plugin
+
+try:
+    # unitttest has a SkipTest also but pytest doesn't
+    # honor it unless nose is imported too...
+    from nose import SkipTest
+except ImportError:
+    from _pytest.runner import Skipped as SkipTest
+
+import contextlib
+
+template_base = os.path.join(os.path.dirname(__file__), 'templates')
+module_base = os.path.join(template_base, 'modules')
+
+class TemplateTest(unittest.TestCase):
+
+    def _file_template(self, filename, **kw):
+        filepath = self._file_path(filename)
+        return Template(uri=filename, filename=filepath,
+                            module_directory=module_base, **kw)
+
+    def _file_path(self, filename):
+        name, ext = os.path.splitext(filename)
+
+        if py3k:
+            py3k_path = os.path.join(template_base, name + "_py3k" + ext)
+            if os.path.exists(py3k_path):
+                return py3k_path
+
+        return os.path.join(template_base, filename)
+
+    def _do_file_test(self, filename, expected, filters=None,
+                        unicode_=True, template_args=None, **kw):
+        t1 = self._file_template(filename, **kw)
+        self._do_test(t1, expected, filters=filters,
+                        unicode_=unicode_, template_args=template_args)
+
+    def _do_memory_test(self, source, expected, filters=None,
+                        unicode_=True, template_args=None, **kw):
+        t1 = Template(text=source, **kw)
+        self._do_test(t1, expected, filters=filters,
+                        unicode_=unicode_, template_args=template_args)
+
+    def _do_test(self, template, expected, filters=None, template_args=None,
+                                unicode_=True):
+        if template_args is None:
+            template_args = {}
+        if unicode_:
+            output = template.render_unicode(**template_args)
+        else:
+            output = template.render(**template_args)
+
+        if filters:
+            output = filters(output)
+        eq_(output, expected)
+
+def eq_(a, b, msg=None):
+    """Assert a == b, with repr messaging on failure."""
+    assert a == b, msg or "%r != %r" % (a, b)
+
+def teardown():
+    import shutil
+    shutil.rmtree(module_base, True)
+
+if py33:
+    from unittest import mock
+else:
+    import mock
+
+@contextlib.contextmanager
+def raises(except_cls, message=None):
+    try:
+        yield
+        success = False
+    except except_cls as e:
+        if message:
+            assert re.search(message, compat.text_type(e), re.UNICODE), \
+                            "%r !~ %s" % (message, e)
+            print(compat.text_type(e).encode('utf-8'))
+        success = True
+
+    # assert outside the block so it works for AssertionError too !
+    assert success, "Callable did not raise an exception"
+
+
+def assert_raises(except_cls, callable_, *args, **kw):
+    with raises(except_cls):
+        return callable_(*args, **kw)
+
+def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
+    with raises(except_cls, msg):
+        return callable_(*args, **kwargs)
+
+def skip_if(predicate, reason=None):
+    """Skip a test if predicate is true."""
+    reason = reason or predicate.__name__
+
+    def decorate(fn):
+        fn_name = fn.__name__
+        def maybe(*args, **kw):
+            if predicate():
+                msg = "'%s' skipped: %s" % (
+                    fn_name, reason)
+                raise SkipTest(msg)
+            else:
+                return fn(*args, **kw)
+        return update_wrapper(maybe, fn)
+    return decorate
+
+def requires_python_3(fn):
+    return skip_if(lambda: not py3k, "Requires Python 3.xx")(fn)
+
+def requires_python_2(fn):
+    return skip_if(lambda: py3k, "Requires Python 2.xx")(fn)
+
+def requires_python_26_or_greater(fn):
+    return skip_if(lambda: not py26, "Requires Python 2.6 or greater")(fn)
+
+def requires_pygments_14(fn):
+    try:
+        import pygments
+        version = pygments.__version__
+    except:
+        version = "0"
+    return skip_if(lambda: version < "1.4", "Requires pygments 1.4 or greater")(fn)
+
+def requires_no_pygments_exceptions(fn):
+    def go(*arg, **kw):
+        from mako import exceptions
+        exceptions._install_fallback()
+        try:
+            return fn(*arg, **kw)
+        finally:
+            exceptions._install_highlighting()
+    return update_wrapper(go, fn)
+
+class PlainCacheImpl(CacheImpl):
+    """Simple memory cache impl so that tests which
+    use caching can run without beaker.  """
+
+    def __init__(self, cache):
+        self.cache = cache
+        self.data = {}
+
+    def get_or_create(self, key, creation_function, **kw):
+        if key in self.data:
+            return self.data[key]
+        else:
+            self.data[key] = data = creation_function(**kw)
+            return data
+
+    def put(self, key, value, **kw):
+        self.data[key] = value
+
+    def get(self, key, **kw):
+        return self.data[key]
+
+    def invalidate(self, key, **kw):
+        del self.data[key]
+
+register_plugin("plain", __name__, "PlainCacheImpl")
diff --git a/test/ext/__init__.py b/test/ext/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/ext/test_babelplugin.py b/test/ext/test_babelplugin.py
new file mode 100644 (file)
index 0000000..3658c50
--- /dev/null
@@ -0,0 +1,93 @@
+import io
+import os
+import unittest
+from .. import TemplateTest, template_base, skip_if
+from mako import compat
+
+try:
+    import babel.messages.extract as babel
+    from mako.ext.babelplugin import extract
+    
+except ImportError:
+    babel = None
+
+
+def skip():
+    return skip_if(
+        lambda: not babel,
+        'babel not installed: skipping babelplugin test')
+
+
+class Test_extract(unittest.TestCase):
+    @skip()
+    def test_parse_python_expression(self):
+        input = io.BytesIO(compat.b('<p>${_("Message")}</p>'))
+        messages = list(extract(input, ['_'], [], {}))
+        self.assertEqual(messages, [(1, '_', compat.u('Message'), [])])
+
+    @skip()
+    def test_python_gettext_call(self):
+        input = io.BytesIO(compat.b('<p>${_("Message")}</p>'))
+        messages = list(extract(input, ['_'], [], {}))
+        self.assertEqual(messages, [(1, '_', compat.u('Message'), [])])
+
+    @skip()
+    def test_translator_comment(self):
+        input = io.BytesIO(compat.b('''
+        <p>
+          ## TRANSLATORS: This is a comment.
+          ${_("Message")}
+        </p>'''))
+        messages = list(extract(input, ['_'], ['TRANSLATORS:'], {}))
+        self.assertEqual(
+            messages,
+            [(4, '_', compat.u('Message'),
+                [compat.u('TRANSLATORS: This is a comment.')])])
+
+
+class ExtractMakoTestCase(TemplateTest):
+    @skip()
+    def test_extract(self):
+        mako_tmpl = open(os.path.join(template_base, 'gettext.mako'))
+        messages = list(extract(mako_tmpl, {'_': None, 'gettext': None,
+                                            'ungettext': (1, 2)},
+                                ['TRANSLATOR:'], {}))
+        expected = \
+            [(1, '_', 'Page arg 1', []),
+             (1, '_', 'Page arg 2', []),
+             (10, 'gettext', 'Begin', []),
+             (14, '_', 'Hi there!', ['TRANSLATOR: Hi there!']),
+             (19, '_', 'Hello', []),
+             (22, '_', 'Welcome', []),
+             (25, '_', 'Yo', []),
+             (36, '_', 'The', ['TRANSLATOR: Ensure so and', 'so, thanks']),
+             (36, 'ungettext', ('bunny', 'bunnies', None), []),
+             (41, '_', 'Goodbye', ['TRANSLATOR: Good bye']),
+             (44, '_', 'Babel', []),
+             (45, 'ungettext', ('hella', 'hellas', None), []),
+             (62, '_', 'The', ['TRANSLATOR: Ensure so and', 'so, thanks']),
+             (62, 'ungettext', ('bunny', 'bunnies', None), []),
+             (68, '_', 'Goodbye, really!', ['TRANSLATOR: HTML comment']),
+             (71, '_', 'P.S. byebye', []),
+             (77, '_', 'Top', []),
+             (83, '_', 'foo', []),
+             (83, '_', 'hoho', []),
+             (85, '_', 'bar', []),
+             (92, '_', 'Inside a p tag', ['TRANSLATOR: <p> tag is ok?']),
+             (95, '_', 'Later in a p tag', ['TRANSLATOR: also this']),
+             (99, '_', 'No action at a distance.', []),
+             ]
+        self.assertEqual(expected, messages)
+
+    @skip()
+    def test_extract_utf8(self):
+        mako_tmpl = open(os.path.join(template_base, 'gettext_utf8.mako'), 'rb')
+        message = next(extract(mako_tmpl, set(['_', None]), [], {'encoding': 'utf-8'}))
+        assert message == (1, '_', u'K\xf6ln', [])
+
+    @skip()
+    def test_extract_cp1251(self):
+        mako_tmpl = open(os.path.join(template_base, 'gettext_cp1251.mako'), 'rb')
+        message = next(extract(mako_tmpl, set(['_', None]), [], {'encoding': 'cp1251'}))
+        # "test" in Rusian. File encoding is cp1251 (aka "windows-1251")
+        assert message == (1, '_', u'\u0442\u0435\u0441\u0442', [])
diff --git a/test/ext/test_linguaplugin.py b/test/ext/test_linguaplugin.py
new file mode 100644 (file)
index 0000000..9c46271
--- /dev/null
@@ -0,0 +1,57 @@
+import os
+from .. import TemplateTest, template_base, skip_if
+
+try:
+    import lingua
+except:
+    lingua = None
+
+if lingua is not None:
+    from mako.ext.linguaplugin import LinguaMakoExtractor
+    from lingua.extractors import register_extractors
+
+
+class MockOptions:
+    keywords = []
+    domain = None
+
+
+def skip():
+    return skip_if(
+        lambda: not lingua, 'lingua not installed: skipping linguaplugin test')
+
+
+class ExtractMakoTestCase(TemplateTest):
+    @skip()
+    def test_extract(self):
+        register_extractors()
+        plugin = LinguaMakoExtractor({'comment-tags': 'TRANSLATOR'})
+        messages = list(
+            plugin(os.path.join(template_base, 'gettext.mako'), MockOptions()))
+        msgids = [(m.msgid, m.msgid_plural) for m in messages]
+        self.assertEqual(
+            msgids,
+            [
+                ('Page arg 1', None),
+                ('Page arg 2', None),
+                ('Begin', None),
+                ('Hi there!', None),
+                ('Hello', None),
+                ('Welcome', None),
+                ('Yo', None),
+                ('The', None),
+                ('bunny', 'bunnies'),
+                ('Goodbye', None),
+                ('Babel', None),
+                ('hella', 'hellas'),
+                ('The', None),
+                ('bunny', 'bunnies'),
+                ('Goodbye, really!', None),
+                ('P.S. byebye', None),
+                ('Top', None),
+                (u'foo', None),
+                ('hoho', None),
+                (u'bar', None),
+                ('Inside a p tag', None),
+                ('Later in a p tag', None),
+                ('No action at a distance.', None)])
diff --git a/test/foo/__init__.py b/test/foo/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/foo/test_ns.py b/test/foo/test_ns.py
new file mode 100644 (file)
index 0000000..282447a
--- /dev/null
@@ -0,0 +1,10 @@
+def foo1(context):
+    context.write("this is foo1.")
+    return ''
+
+def foo2(context, x):
+    context.write("this is foo2, x is " + x)
+    return ''
+
+
+foo3 = "I'm not a callable"
\ No newline at end of file
diff --git a/test/sample_module_namespace.py b/test/sample_module_namespace.py
new file mode 100644 (file)
index 0000000..7a2425d
--- /dev/null
@@ -0,0 +1,7 @@
+def foo1(context):
+    context.write("this is foo1.")
+    return ''
+def foo2(context, x):
+    context.write("this is foo2, x is " + x)
+    return ''
\ No newline at end of file
diff --git a/test/templates/badbom.html b/test/templates/badbom.html
new file mode 100644 (file)
index 0000000..2af085b
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: ascii -*-
+Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »
\ No newline at end of file
diff --git a/test/templates/bom.html b/test/templates/bom.html
new file mode 100644 (file)
index 0000000..1259946
--- /dev/null
@@ -0,0 +1 @@
+Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »
\ No newline at end of file
diff --git a/test/templates/bommagic.html b/test/templates/bommagic.html
new file mode 100644 (file)
index 0000000..0e4b587
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »
\ No newline at end of file
diff --git a/test/templates/chs_unicode.html b/test/templates/chs_unicode.html
new file mode 100644 (file)
index 0000000..7b897e9
--- /dev/null
@@ -0,0 +1,11 @@
+## -*- coding:utf-8 -*-
+<%
+ msg = u'新中国的主席'
+%>
+
+<%def name="welcome(who, place=u'北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome(u'你')}
diff --git a/test/templates/chs_unicode_py3k.html b/test/templates/chs_unicode_py3k.html
new file mode 100644 (file)
index 0000000..e4b6a8f
--- /dev/null
@@ -0,0 +1,11 @@
+## -*- coding:utf-8 -*-
+<%
+ msg = '新中国的主席'
+%>
+
+<%def name="welcome(who, place='北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome('你')}
diff --git a/test/templates/chs_utf8.html b/test/templates/chs_utf8.html
new file mode 100644 (file)
index 0000000..5f4733f
--- /dev/null
@@ -0,0 +1,17 @@
+## -*- coding:utf-8 -*-
+<%
+ msg = '新中国的主席'
+%>
+
+<%def name="welcome(who, place='北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+<%def name="welcome_buffered(who, place='北京')" buffered="True">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome('你')}
+${welcome_buffered('你')}
+
diff --git a/test/templates/cmd_good.mako b/test/templates/cmd_good.mako
new file mode 100644 (file)
index 0000000..68ebec4
--- /dev/null
@@ -0,0 +1 @@
+hello world ${x}
\ No newline at end of file
diff --git a/test/templates/cmd_runtime.mako b/test/templates/cmd_runtime.mako
new file mode 100644 (file)
index 0000000..6c2675b
--- /dev/null
@@ -0,0 +1 @@
+${q}
\ No newline at end of file
diff --git a/test/templates/cmd_syntax.mako b/test/templates/cmd_syntax.mako
new file mode 100644 (file)
index 0000000..d2117db
--- /dev/null
@@ -0,0 +1 @@
+${x
\ No newline at end of file
diff --git a/test/templates/crlf.html b/test/templates/crlf.html
new file mode 100644 (file)
index 0000000..d2620db
--- /dev/null
@@ -0,0 +1,19 @@
+<html>\r
+\r
+<%page args="a=['foo',\r
+                'bar']"/>\r
+\r
+like the name says.\r
+\r
+    % for x in [1,2,3]:\r
+        ${x}\\r
+    % endfor\r
+\r
+${trumpeter == 'Miles' and trumpeter or \\r
+      'Dizzy'}\r
+\r
+<%def name="hi()">\r
+    hi!\r
+</%def>\r
+\r
+</html>\r
diff --git a/test/templates/foo/modtest.html.py b/test/templates/foo/modtest.html.py
new file mode 100644 (file)
index 0000000..e6fc8d8
--- /dev/null
@@ -0,0 +1,25 @@
+from mako import runtime, filters, cache
+UNDEFINED = runtime.UNDEFINED
+__M_dict_builtin = dict
+__M_locals_builtin = locals
+_magic_number = 5
+_modified_time = 1267565427.7968459
+_template_filename='/Users/classic/dev/mako/test/templates/modtest.html'
+_template_uri='/modtest.html'
+_template_cache=cache.Cache(__name__, _modified_time)
+_source_encoding=None
+_exports = []
+
+
+def render_body(context,**pageargs):
+    context.caller_stack._push_frame()
+    try:
+        __M_locals = __M_dict_builtin(pageargs=pageargs)
+        __M_writer = context.writer()
+        # SOURCE LINE 1
+        __M_writer('this is a test')
+        return ''
+    finally:
+        context.caller_stack._pop_frame()
+
+
diff --git a/test/templates/gettext.mako b/test/templates/gettext.mako
new file mode 100644 (file)
index 0000000..45b8262
--- /dev/null
@@ -0,0 +1,130 @@
+<%page args="x, y=_('Page arg 1'), z=_('Page arg 2')"/>
+<%!
+import random
+def gettext(message): return message
+_ = gettext
+def ungettext(s, p, c):
+    if c == 1:
+        return s
+    return p
+top = gettext('Begin')
+%>
+<%
+   # TRANSLATOR: Hi there!
+   hithere = _('Hi there!')
+
+   # TRANSLATOR: you should not be seeing this in the .po
+   rows = [[v for v in range(0,10)] for row in range(0,10)]
+
+   hello = _('Hello')
+%>
+<div id="header">
+  ${_('Welcome')}
+</div>
+<table>
+    % for row in (hithere, hello, _('Yo')):
+        ${makerow(row)}
+    % endfor
+    ${makerow(count=2)}
+</table>
+
+
+<div id="main">
+
+## TRANSLATOR: Ensure so and
+## so, thanks
+  ${_('The')} fuzzy ${ungettext('bunny', 'bunnies', random.randint(1, 2))}
+</div>
+
+<div id="footer">
+  ## TRANSLATOR: Good bye
+  ${_('Goodbye')}
+</div>
+
+<%def name="makerow(row=_('Babel'), count=1)">
+    <!-- ${ungettext('hella', 'hellas', count)} -->
+    % for i in range(count):
+      <tr>
+      % for name in row:
+          <td>${name}</td>\
+      % endfor
+      </tr>
+    % endfor
+</%def>
+
+<%def name="comment()">
+  <!-- ${caller.body()} -->
+</%def>
+
+<%block name="foo">
+    ## TRANSLATOR: Ensure so and
+    ## so, thanks
+      ${_('The')} fuzzy ${ungettext('bunny', 'bunnies', random.randint(1, 2))}
+</%block>
+
+<%call expr="comment">
+  P.S.
+  ## TRANSLATOR: HTML comment
+  ${_('Goodbye, really!')}
+</%call>
+
+<!-- ${_('P.S. byebye')} -->
+
+<div id="end">
+  <a href="#top">
+    ## TRANSLATOR: you won't see this either
+
+    ${_('Top')}
+  </a>
+</div>
+
+<%def name="panel()">
+
+${_(u'foo')} <%self:block_tpl title="#123", name="_('baz')" value="${_('hoho')}" something="hi'there" somethingelse='hi"there'>
+
+${_(u'bar')}
+
+</%self:block_tpl>
+
+</%def>
+
+## TRANSLATOR: <p> tag is ok?
+<p>${_("Inside a p tag")}</p>
+
+## TRANSLATOR: also this
+<p>${even_with_other_code_first()} - ${_("Later in a p tag")}</p>
+
+## TRANSLATOR: we still ignore comments too far from the string
+
+<p>${_("No action at a distance.")}</p>
+
+## TRANSLATOR: nothing to extract from these blocks
+
+% if 1==1:
+<p>One is one!</p>
+% elif 1==2:
+<p>One is two!</p>
+% else:
+<p>How much is one?</p>
+% endif
+
+% for i in range(10):
+<p>${i} squared is ${i*i}</p>
+% else:
+<p>Done with squares!</p>
+% endfor
+
+% while random.randint(1,6) != 6:
+<p>Not 6!</p>
+% endwhile
+
+## TRANSLATOR: for now, try/except blocks are ignored
+
+% try:
+<% 1/0 %>
+% except:
+<p>Failed!</p>
+% endtry
+
+## TRANSLATOR: this should not cause a parse error
+${ 1 }
diff --git a/test/templates/gettext_cp1251.mako b/test/templates/gettext_cp1251.mako
new file mode 100644 (file)
index 0000000..9341d93
--- /dev/null
@@ -0,0 +1 @@
+${_("òåñò")}
diff --git a/test/templates/gettext_utf8.mako b/test/templates/gettext_utf8.mako
new file mode 100644 (file)
index 0000000..761f946
--- /dev/null
@@ -0,0 +1 @@
+${_("Köln")}
diff --git a/test/templates/index.html b/test/templates/index.html
new file mode 100644 (file)
index 0000000..591e380
--- /dev/null
@@ -0,0 +1 @@
+this is index
\ No newline at end of file
diff --git a/test/templates/internationalization.html b/test/templates/internationalization.html
new file mode 100644 (file)
index 0000000..da5b61c
--- /dev/null
@@ -0,0 +1,920 @@
+<div class="rst-docs">
+  <h1 class="pudge-member-page-heading">Internationalization, Localization and Unicode</h1>
+  <table rules="none" frame="void" class="docinfo">
+<col class="docinfo-name"></col>
+<col class="docinfo-content"></col>
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>James Gardner</td></tr>
+<tr class="field"><th class="docinfo-name">updated:</th><td class="field-body">2006-12-11</td>
+</tr>
+</tbody>
+</table>
+
+  <div class="note">
+<p class="first admonition-title">Note</p>
+<p>This is a work in progress. We hope the internationalization, localization
+and Unicode support in Pylons is now robust and flexible but we would
+appreciate hearing about any issues we have. Just drop a line to the
+pylons-discuss mailing list on Google Groups.</p>
+<p class="last">This is the first draft of the full document including Unicode. Expect
+some typos and spelling mistakes!</p>
+</div>
+<div class="contents topic">
+<p class="topic-title first"><a id="table-of-contents" name="table-of-contents">Table of Contents</a></p>
+<ul class="auto-toc simple">
+<li><a href="#understanding-unicode" id="id1" name="id1" class="reference">1   Understanding Unicode</a><ul class="auto-toc">
+<li><a href="#what-is-unicode" id="id2" name="id2" class="reference">1.1   What is Unicode?</a></li>
+<li><a href="#unicode-in-python" id="id3" name="id3" class="reference">1.2   Unicode in Python</a></li>
+<li><a href="#unicode-literals-in-python-source-code" id="id4" name="id4" class="reference">1.3   Unicode Literals in Python Source Code</a></li>
+<li><a href="#input-and-output" id="id5" name="id5" class="reference">1.4   Input and Output</a></li>
+<li><a href="#unicode-filenames" id="id6" name="id6" class="reference">1.5   Unicode Filenames</a></li>
+</ul>
+</li>
+<li><a href="#applying-this-to-web-programming" id="id7" name="id7" class="reference">2   Applying this to Web Programming</a><ul class="auto-toc">
+<li><a href="#request-parameters" id="id8" name="id8" class="reference">2.1   Request Parameters</a></li>
+<li><a href="#templating" id="id9" name="id9" class="reference">2.2   Templating</a></li>
+<li><a href="#output-encoding" id="id10" name="id10" class="reference">2.3   Output Encoding</a></li>
+<li><a href="#databases" id="id11" name="id11" class="reference">2.4   Databases</a></li>
+</ul>
+</li>
+<li><a href="#internationalization-and-localization" id="id12" name="id12" class="reference">3   Internationalization and Localization</a><ul class="auto-toc">
+<li><a href="#getting-started" id="id13" name="id13" class="reference">3.1   Getting Started</a></li>
+<li><a href="#testing-the-application" id="id14" name="id14" class="reference">3.2   Testing the Application</a></li>
+<li><a href="#missing-translations" id="id15" name="id15" class="reference">3.3   Missing Translations</a></li>
+<li><a href="#translations-within-templates" id="id16" name="id16" class="reference">3.4   Translations Within Templates</a></li>
+<li><a href="#producing-a-python-egg" id="id17" name="id17" class="reference">3.5   Producing a Python Egg</a></li>
+<li><a href="#plural-forms" id="id18" name="id18" class="reference">3.6   Plural Forms</a></li>
+</ul>
+</li>
+<li><a href="#summary" id="id19" name="id19" class="reference">4   Summary</a></li>
+<li><a href="#further-reading" id="id20" name="id20" class="reference">5   Further Reading</a></li>
+</ul>
+</div>
+<p>Internationalization and localization are means of adapting software for
+non-native environments, especially for other nations and cultures.</p>
+<p>Parts of an application which might need to be localized might include:</p>
+<blockquote>
+<ul class="simple">
+<li>Language</li>
+<li>Date/time format</li>
+<li>Formatting of numbers e.g. decimal points, positioning of separators,
+character used as separator</li>
+<li>Time zones (UTC in internationalized environments)</li>
+<li>Currency</li>
+<li>Weights and measures</li>
+</ul>
+</blockquote>
+<p>The distinction between internationalization and localization is subtle but
+important. Internationalization is the adaptation of products for potential use
+virtually everywhere, while localization is the addition of special features
+for use in a specific locale.</p>
+<p>For example, in terms of language used in software, internationalization is the
+process of marking up all strings that might need to be translated whilst
+localization is the process of producing translations for a particular locale.</p>
+<p>Pylons provides built-in support to enable you to internationalize language but
+leaves you to handle any other aspects of internationalization which might be
+appropriate to your application.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Internationalization is often abbreviated as I18N (or i18n or I18n) where the
+number 18 refers to the number of letters omitted.
+Localization is often abbreviated L10n or l10n in the same manner. These
+abbreviations also avoid picking one spelling (internationalisation vs.
+internationalization, etc.) over the other.</p>
+</div>
+<p>In order to represent characters from multiple languages, you will need to use
+Unicode so this documentation will start with a description of why Unicode is
+useful, its history and how to use Unicode in Python.</p>
+<div class="section">
+<h1><a href="#id1" id="understanding-unicode" name="understanding-unicode" class="toc-backref">1   Understanding Unicode</a></h1>
+<p>If you've ever come across text in a foreign language that contains lots of
+<tt class="docutils literal"><span class="pre">????</span></tt> characters or have written some Python code and received a message
+such as <tt class="docutils literal"><span class="pre">UnicodeDecodeError:</span> <span class="pre">'ascii'</span> <span class="pre">codec</span> <span class="pre">can't</span> <span class="pre">decode</span> <span class="pre">byte</span> <span class="pre">0xff</span> <span class="pre">in</span> <span class="pre">position</span>
+<span class="pre">6:</span> <span class="pre">ordinal</span> <span class="pre">not</span> <span class="pre">in</span> <span class="pre">range(128)</span></tt> then you have run into a problem with character
+sets, encodings, Unicode and the like.</p>
+<p>The truth is that many developers are put off by Unicode because most of the
+time it is possible to muddle through rather than take the time to learn the
+basics. To make the problem worse if you have a system that manages to fudge
+the issues and just about work and then start trying to do things properly with
+Unicode it often highlights problems in other parts of your code.</p>
+<p>The good news is that Python has great Unicode support, so the rest of
+this article will show you how to correctly use Unicode in Pylons to avoid
+unwanted <tt class="docutils literal"><span class="pre">?</span></tt> characters and <tt class="docutils literal"><span class="pre">UnicodeDecodeErrors</span></tt>.</p>
+<div class="section">
+<h2><a href="#id2" id="what-is-unicode" name="what-is-unicode" class="toc-backref">1.1   What is Unicode?</a></h2>
+<p>When computers were first being used the characters that were most important
+were unaccented English letters. Each of these letters could be represented by
+a number between 32 and 127 and thus was born ASCII, a character set where
+space was 32, the letter "A" was 65 and everything could be stored in 7 bits.</p>
+<p>Most computers in those days were using 8-bit bytes so people quickly realized
+that they could use the codes 128-255 for their own purposes. Different people
+used the codes 128-255 to represent different characters and before long these
+different sets of characters were also standardized into <em>code pages</em>. This
+meant that if you needed some non-ASCII characters in a document you could also
+specify a codepage which would define which extra characters were available.
+For example Israel DOS used a code page called 862, while Greek users used 737.
+This just about worked for Western languages provided you didn't want to write
+an Israeli document with Greek characters but it didn't work at all for Asian
+languages where there are many more characters than can be represented in 8
+bits.</p>
+<p>Unicode is a character set that solves these problems by uniquely defining
+<em>every</em> character that is used anywhere in the world. Rather than defining a
+character as a particular combination of bits in the way ASCII does, each
+character is assigned a <em>code point</em>. For example the word <tt class="docutils literal"><span class="pre">hello</span></tt> is made
+from code points <tt class="docutils literal"><span class="pre">U+0048</span> <span class="pre">U+0065</span> <span class="pre">U+006C</span> <span class="pre">U+006C</span> <span class="pre">U+006F</span></tt>. The full list of code
+points can be found at <a href="http://www.unicode.org/charts/" class="reference">http://www.unicode.org/charts/</a>.</p>
+<p>There are lots of different ways of encoding Unicode code points into bits but
+the most popular encoding is UTF-8. Using UTF-8, every code point from 0-127 is
+stored in a single byte. Only code points 128 and above are stored using 2, 3,
+in fact, up to 6 bytes. This has the useful side effect that English text looks
+exactly the same in UTF-8 as it did in ASCII, because for every
+ASCII character with hexadecimal value 0xXY, the corresponding Unicode
+code point is U+00XY. This backwards compatibility is why if you are developing
+an application that is only used by English speakers you can often get away
+without handling characters properly and still expect things to work most of
+the time. Of course, if you use a different encoding such as UTF-16 this
+doesn't apply since none of the code points are encoded to 8 bits.</p>
+<p>The important things to note from the discussion so far are that:</p>
+<ul>
+<li><p class="first">Unicode can represent pretty much any character in any writing system in
+widespread use today</p>
+</li>
+<li><p class="first">Unicode uses code points to represent characters and the way these map to bits
+in memory depends on the encoding</p>
+</li>
+<li><dl class="first docutils">
+<dt>The most popular encoding is UTF-8 which has  several convenient properties:</dt>
+<dd><ol class="first last arabic simple">
+<li>It can handle any Unicode code point</li>
+<li>A Unicode string is turned into a string of bytes containing no embedded
+zero bytes. This avoids byte-ordering issues, and means UTF-8 strings can be
+processed by C functions such as strcpy() and sent through protocols that can't
+handle zero bytes</li>
+<li>A string of ASCII text is also valid UTF-8 text</li>
+<li>UTF-8 is fairly compact; the majority of code points are turned into two
+bytes, and values less than 128 occupy only a single byte.</li>
+<li>If bytes are corrupted or lost, it's possible to determine the start of
+the next UTF-8-encoded code point and resynchronize.</li>
+</ol>
+</dd>
+</dl>
+</li>
+</ul>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Since Unicode 3.1, some extensions have even been defined so that the
+defined range is now U+000000 to U+10FFFF (21 bits), and formally, the
+character set is defined as 31-bits to allow for future expansion. It is a myth
+that there are 65,536 Unicode code points and that every Unicode letter can
+really be squeezed into two bytes. It is also incorrect to think that UTF-8 can
+represent less characters than UTF-16. UTF-8 simply uses a variable number of
+bytes for a character, sometimes just one byte (8 bits).</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id3" id="unicode-in-python" name="unicode-in-python" class="toc-backref">1.2   Unicode in Python</a></h2>
+<p>In Python Unicode strings are expressed as instances of the built-in
+<tt class="docutils literal"><span class="pre">unicode</span></tt> type. Under the hood, Python represents Unicode strings as either
+16 or 32 bit integers, depending on how the Python interpreter was compiled.</p>
+<p>The <tt class="docutils literal"><span class="pre">unicode()</span></tt> constructor has the signature <tt class="docutils literal"><span class="pre">unicode(string[,</span> <span class="pre">encoding,</span>
+<span class="pre">errors])</span></tt>. All of its arguments should be 8-bit strings. The first argument is
+converted to Unicode using the specified encoding; if you leave off the
+encoding argument, the ASCII encoding is used for the conversion, so characters
+greater than 127 will be treated as errors:</p>
+<pre class="literal-block">
+>>> unicode('hello')
+u'hello'
+>>> s = unicode('hello')
+>>> type(s)
+&lt;type 'unicode'>
+>>> unicode('hello' + chr(255))
+Traceback (most recent call last):
+  File "&lt;stdin>", line 1, in ?
+UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6:
+                    ordinal not in range(128)
+</pre>
+<p>The <tt class="docutils literal"><span class="pre">errors</span></tt> argument specifies what to do if the string can't be decoded to
+ascii. Legal values for this argument are <tt class="docutils literal"><span class="pre">'strict'</span></tt> (raise a
+<tt class="docutils literal"><span class="pre">UnicodeDecodeError</span></tt> exception), <tt class="docutils literal"><span class="pre">'replace'</span></tt> (replace the character that
+can't be decoded with another one), or <tt class="docutils literal"><span class="pre">'ignore'</span></tt> (just leave the character
+out of the Unicode result).</p>
+<blockquote>
+<pre class="doctest-block">
+>>> unicode('\x80abc', errors='strict')
+Traceback (most recent call last):
+  File "&lt;stdin>", line 1, in ?
+UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0:
+                    ordinal not in range(128)
+>>> unicode('\x80abc', errors='replace')
+u'\ufffdabc'
+>>> unicode('\x80abc', errors='ignore')
+u'abc'
+</pre>
+</blockquote>
+<p>It is important to understand the difference between <em>encoding</em> and <em>decoding</em>.
+Unicode strings are considered to be the Unicode code points but any
+representation of the Unicode string has to be encoded to something else, for
+example UTF-8 or ASCII. So when you are converting an ASCII or UTF-8 string to
+Unicode you are <em>decoding</em> it and when you are converting from Unicode to UTF-8
+or ASCII you are <em>encoding</em> it. This is why the error in the example above says
+that the ASCII codec cannot decode the byte <tt class="docutils literal"><span class="pre">0x80</span></tt> from ASCII to Unicode
+because it is not in the range(128) or 0-127. In fact <tt class="docutils literal"><span class="pre">0x80</span></tt> is hex for 128
+which the first number outside the ASCII range. However if we tell Python that
+the character <tt class="docutils literal"><span class="pre">0x80</span></tt> is encoded with the <tt class="docutils literal"><span class="pre">'latin-1'</span></tt>, <tt class="docutils literal"><span class="pre">'iso_8859_1'</span></tt> or
+<tt class="docutils literal"><span class="pre">'8859'</span></tt> character sets (which incidentally are different names for the same
+thing) we get the result we expected:</p>
+<textarea name="code" class="python">
+>>> unicode('\x80', encoding='latin-1')
+u'\x80'
+</textarea><div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">The character encodings Python supports are listed at
+<a href="http://docs.python.org/lib/standard-encodings.html" class="reference">http://docs.python.org/lib/standard-encodings.html</a></p>
+</div>
+<p>Unicode objects in Python have most of the same methods that normal Python
+strings provide. Python will try to use the <tt class="docutils literal"><span class="pre">'ascii'</span></tt> codec to convert
+strings to Unicode if you do an operation on both types:</p>
+<textarea name="code" class="python">
+>>> a = 'hello'
+>>> b = unicode(' world!')
+>>> print a + b
+u'hello world!'
+</textarea><p>You can encode a Unicode string using a particular encoding like this:</p>
+<textarea name="code" class="python">
+>>> u'Hello World!'.encode('UTF-8')
+'Hello World!'
+</textarea></div>
+<div class="section">
+<h2><a href="#id4" id="unicode-literals-in-python-source-code" name="unicode-literals-in-python-source-code" class="toc-backref">1.3   Unicode Literals in Python Source Code</a></h2>
+<p>In Python source code, Unicode literals are written as strings prefixed with
+the 'u' or 'U' character:</p>
+<textarea name="code" class="python">
+>>> u'abcdefghijk'
+>>> U'lmnopqrstuv'
+</textarea><p>You can also use <tt class="docutils literal"><span class="pre">"</span></tt>, <tt class="docutils literal"><span class="pre">"""`</span></tt> or <tt class="docutils literal"><span class="pre">'''</span></tt> versions too. For example:</p>
+<textarea name="code" class="python">
+>>> u"""This
+... is a really long
+... Unicode string"""
+</textarea><p>Specific code points can be written using the <tt class="docutils literal"><span class="pre">\u</span></tt> escape sequence, which is
+followed by four hex digits giving the code point. If you use <tt class="docutils literal"><span class="pre">\U</span></tt> instead
+you specify 8 hex digits instead of 4. Unicode literals can also use the same
+escape sequences as 8-bit strings, including <tt class="docutils literal"><span class="pre">\x</span></tt>, but <tt class="docutils literal"><span class="pre">\x</span></tt> only takes two
+hex digits so it can't express all the available code points. You can add
+characters to Unicode strings using the <tt class="docutils literal"><span class="pre">unichr()</span></tt> built-in function and find
+out what the ordinal is with <tt class="docutils literal"><span class="pre">ord()</span></tt>.</p>
+<p>Here is an example demonstrating the different alternatives:</p>
+<textarea name="code" class="python">
+>>> s = u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais"
+>>> #     ^^^^ two-digit hex escape
+>>> #         ^^^^^^ four-digit Unicode escape
+>>> #                     ^^^^^^^^^^ eight-digit Unicode escape
+>>> for c in s:  print ord(c),
+...
+97 102 114 97 110 231 97 105 115
+>>> print s
+franÁais
+</textarea><p>Using escape sequences for code points greater than 127 is fine in small doses
+but Python 2.4 and above support writing Unicode literals in any encoding as
+long as you declare the encoding being used by including a special comment as
+either the first or second line of the source file:</p>
+<textarea name="code" class="python">
+#!/usr/bin/env python
+# -*- coding: latin-1 -*-
+
+u = u'abcdÈ'
+print ord(u[-1])
+</textarea><p>If you don't include such a comment, the default encoding used will be ASCII.
+Versions of Python before 2.4 were Euro-centric and assumed Latin-1 as a
+default encoding for string literals; in Python 2.4, characters greater than
+127 still work but result in a warning. For example, the following program has
+no encoding declaration:</p>
+<textarea name="code" class="python">
+#!/usr/bin/env python
+u = u'abcdÈ'
+print ord(u[-1])
+</textarea><p>When you run it with Python 2.4, it will output the following warning:</p>
+<pre class="literal-block">
+sys:1: DeprecationWarning: Non-ASCII character '\xe9' in file testas.py on line
+2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for de
+tails
+</pre>
+<p>and then the following output:</p>
+<pre class="literal-block">
+233
+</pre>
+<p>For real world use it is recommended that you use the UTF-8 encoding for your
+file but you must be sure that your text editor actually saves the file as
+UTF-8 otherwise the Python interpreter will try to parse UTF-8 characters but
+they will actually be stored as something else.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Windows users who use the <a href="http://www.scintilla.org/SciTE.html" class="reference">SciTE</a>
+editor can specify the encoding of their file from the menu using the
+<tt class="docutils literal"><span class="pre">File->Encoding</span></tt>.</p>
+</div>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">If you are working with Unicode in detail you might also be interested in
+the <tt class="docutils literal"><span class="pre">unicodedata</span></tt> module which can be used to find out Unicode properties
+such as a character's name, category, numeric value and the like.</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id5" id="input-and-output" name="input-and-output" class="toc-backref">1.4   Input and Output</a></h2>
+<p>We now know how to use Unicode in Python source code but input and output can
+also be different using Unicode. Of course, some libraries natively support
+Unicode and if these libraries return Unicode objects you will not have to do
+anything special to support them. XML parsers and SQL databases frequently
+support Unicode for example.</p>
+<p>If you remember from the discussion earlier, Unicode data consists of code
+points. In order to send Unicode data via a socket or write it to a file you
+usually need to encode it to a series of bytes and then decode the data back to
+Unicode when reading it. You can of course perform the encoding manually
+reading a byte at the time but since encodings such as UTF-8 can have variable
+numbers of bytes per character it is usually much easier to use Python's
+built-in support in the form of the <tt class="docutils literal"><span class="pre">codecs</span></tt> module.</p>
+<p>The codecs module includes a version of the <tt class="docutils literal"><span class="pre">open()</span></tt> function that
+returns a file-like object that assumes the file's contents are in a specified
+encoding and accepts Unicode parameters for methods such as <tt class="docutils literal"><span class="pre">.read()</span></tt> and
+<tt class="docutils literal"><span class="pre">.write()</span></tt>.</p>
+<p>The function's parameters are open(filename, mode='rb', encoding=None,
+errors='strict', buffering=1). <tt class="docutils literal"><span class="pre">mode</span></tt> can be 'r', 'w', or 'a', just like the
+corresponding parameter to the regular built-in <tt class="docutils literal"><span class="pre">open()</span></tt> function. You can
+add a <tt class="docutils literal"><span class="pre">+</span></tt> character to update the file. <tt class="docutils literal"><span class="pre">buffering</span></tt> is similar to the
+standard function's parameter. <tt class="docutils literal"><span class="pre">encoding</span></tt> is a string giving the encoding to
+use, if not specified or specified as <tt class="docutils literal"><span class="pre">None</span></tt>, a regular Python file object
+that accepts 8-bit strings is returned.  Otherwise, a wrapper object is
+returned, and data written to or read from the wrapper object will be converted
+as needed. <tt class="docutils literal"><span class="pre">errors</span></tt> specifies the action for encoding errors and can be one
+of the usual values of <tt class="docutils literal"><span class="pre">'strict'</span></tt>, <tt class="docutils literal"><span class="pre">'ignore'</span></tt>, or <tt class="docutils literal"><span class="pre">'replace'</span></tt> which we
+saw right at the begining of this document when we were encoding strings in
+Python source files.</p>
+<p>Here is an example of how to read Unicode from a UTF-8 encoded file:</p>
+<textarea name="code" class="python">
+import codecs
+f = codecs.open('unicode.txt', encoding='utf-8')
+for line in f:
+    print repr(line)
+</textarea><p>It's also possible to open files in update mode, allowing both reading and writing:</p>
+<textarea name="code" class="python">
+f = codecs.open('unicode.txt', encoding='utf-8', mode='w+')
+f.write(u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais")
+f.seek(0)
+print repr(f.readline()[:1])
+f.close()
+</textarea><p>Notice that we used the <tt class="docutils literal"><span class="pre">repr()</span></tt> function to display the Unicode data. This
+is very useful because if you tried to print the Unicode data directly, Python
+would need to encode it before it could be sent the console and depending on
+which characters were present and the character set used by the console, an
+error might be raised. This is avoided if you use <tt class="docutils literal"><span class="pre">repr()</span></tt>.</p>
+<p>The Unicode character <tt class="docutils literal"><span class="pre">U+FEFF</span></tt> is used as a byte-order mark or BOM, and is often
+written as the first character of a file in order to assist with auto-detection
+of the file's byte ordering. Some encodings, such as UTF-16, expect a BOM to be
+present at the start of a file, but with others such as UTF-8 it isn't necessary.</p>
+<p>When such an encoding is used, the BOM will be automatically written as the
+first character and will be silently dropped when the file is read. There are
+variants of these encodings, such as 'utf-16-le' and 'utf-16-be' for
+little-endian and big-endian encodings, that specify one particular byte
+ordering and don't skip the BOM.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Some editors including SciTE will put a byte order mark (BOM) in the text
+file when saved as UTF-8, which is strange because UTF-8 doesn't need BOMs.</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id6" id="unicode-filenames" name="unicode-filenames" class="toc-backref">1.5   Unicode Filenames</a></h2>
+<p>Most modern operating systems support the use of Unicode filenames. The
+filenames are transparently converted to the underlying filesystem encoding.
+The type of encoding depends on the operating system.</p>
+<p>On Windows 9x, the encoding is <tt class="docutils literal"><span class="pre">mbcs</span></tt>.</p>
+<p>On Mac OS X, the encoding is <tt class="docutils literal"><span class="pre">utf-8</span></tt>.</p>
+<p>On Unix, the encoding is the user's preference according to the
+result of nl_langinfo(CODESET), or None if the nl_langinfo(CODESET) failed.</p>
+<p>On Windows NT+, file names are Unicode natively, so no conversion is performed.
+getfilesystemencoding still returns <tt class="docutils literal"><span class="pre">mbcs</span></tt>, as this is the encoding that
+applications should use when they explicitly want to convert Unicode strings to
+byte strings that are equivalent when used as file names.</p>
+<p><tt class="docutils literal"><span class="pre">mbcs</span></tt> is a special encoding for Windows that effectively means "use
+whichever encoding is appropriate". In Python 2.3 and above you can find out
+the system encoding with <tt class="docutils literal"><span class="pre">sys.getfilesystemencoding()</span></tt>.</p>
+<p>Most file and directory functions and methods support Unicode. For example:</p>
+<textarea name="code" class="python">
+filename = u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais"
+f = open(filename, 'w')
+f.write('Some data\n')
+f.close()
+</textarea><p>Other functions such as <tt class="docutils literal"><span class="pre">os.listdir()</span></tt> will return Unicode if you pass a
+Unicode argument and will try to return strings if you pass an ordinary 8 bit
+string. For example running this example as <tt class="docutils literal"><span class="pre">test.py</span></tt>:</p>
+<textarea name="code" class="python">
+filename = u"Sample " + unichar(5000)
+f = open(filename, 'w')
+f.close()
+
+import os
+print os.listdir('.')
+print os.listdir(u'.')
+</textarea><p>will produce the following output:</p>
+<blockquote>
+['Sample?', 'test.py']
+[u'Sampleu1388', u'test.py']</blockquote>
+</div>
+</div>
+<div class="section">
+<h1><a href="#id7" id="applying-this-to-web-programming" name="applying-this-to-web-programming" class="toc-backref">2   Applying this to Web Programming</a></h1>
+<p>So far we've seen how to use encoding in source files and seen how to decode
+text to Unicode and encode it back to text. We've also seen that Unicode
+objects can be manipulated in similar ways to strings and we've seen how to
+perform input and output operations on files. Next we are going to look at how
+best to use Unicode in a web app.</p>
+<p>The main rule is this:</p>
+<pre class="literal-block">
+Your application should use Unicode for all strings internally, decoding
+any input to Unicode as soon as it enters the application and encoding the
+Unicode to UTF-8 or another encoding only on output.
+</pre>
+<p>If you fail to do this you will find that <tt class="docutils literal"><span class="pre">UnicodeDecodeError</span></tt> s will start
+popping up in unexpected places when Unicode strings are used with normal 8-bit
+strings because Python's default encoding is ASCII and it will try to decode
+the text to ASCII and fail. It is always better to do any encoding or decoding
+at the edges of your application otherwise you will end up patching lots of
+different parts of your application unnecessarily as and when errors pop up.</p>
+<p>Unless you have a very good reason not to it is wise to use UTF-8 as the
+default encoding since it is so widely supported.</p>
+<p>The second rule is:</p>
+<pre class="literal-block">
+Always test your application with characters above 127 and above 255
+wherever possible.
+</pre>
+<p>If you fail to do this you might think your application is working fine, but as
+soon as your users do put in non-ASCII characters you will have problems.
+Using arabic is always a good test and www.google.ae is a good source of sample
+text.</p>
+<p>The third rule is:</p>
+<pre class="literal-block">
+Always do any checking of a string for illegal characters once it's in the
+form that will be used or stored, otherwise the illegal characters might be
+disguised.
+</pre>
+<p>For example, let's say you have a content management system that takes a
+Unicode filename, and you want to disallow paths with a '/' character. You
+might write this code:</p>
+<textarea name="code" class="python">
+def read_file(filename, encoding):
+    if '/' in filename:
+        raise ValueError("'/' not allowed in filenames")
+    unicode_name = filename.decode(encoding)
+    f = open(unicode_name, 'r')
+    # ... return contents of file ...
+</textarea><p>This is INCORRECT. If an attacker could specify the 'base64' encoding, they
+could pass <tt class="docutils literal"><span class="pre">L2V0Yy9wYXNzd2Q=</span></tt> which is the base-64 encoded form of the string
+<tt class="docutils literal"><span class="pre">'/etc/passwd'</span></tt> which is a file you clearly don't want an attacker to get
+hold of.  The above code looks for <tt class="docutils literal"><span class="pre">/</span></tt> characters in the encoded form and
+misses the dangerous character in the resulting decoded form.</p>
+<p>Those are the three basic rules so now we will look at some of the places you
+might want to perform Unicode decoding in a Pylons application.</p>
+<div class="section">
+<h2><a href="#id8" id="request-parameters" name="request-parameters" class="toc-backref">2.1   Request Parameters</a></h2>
+<p>Currently the Pylons input values come from <tt class="docutils literal"><span class="pre">request.params</span></tt> but these are
+not decoded to Unicode by default because not all input should be assumed to be
+Unicode data.</p>
+<p>If you would like However you can use the two functions below:</p>
+<textarea name="code" class="python">
+def decode_multi_dict(md, encoding="UTF-8", errors="strict"):
+    """Given a MultiDict, decode all its parts from the given encoding.
+
+    This modifies the MultiDict in place.
+
+    encoding, strict
+      These are passed to the decode function.
+
+    """
+    items = md.items()
+    md.clear()
+    for (k, v) in items:
+        md.add(k.decode(encoding, errors),
+               v.decode(encoding, errors))
+
+
+def decode_request(request, encoding="UTF-8", errors="strict"):
+    """Given a request object, decode GET and POST in place.
+
+    This implicitly takes care of params as well.
+
+    """
+    decode_multi_dict(request.GET, encoding, errors)
+    decode_multi_dict(request.POST, encoding, errors)
+</textarea><p>These can then be used as follows:</p>
+<textarea name="code" class="python">
+unicode_params = decode_request(request.params)
+</textarea><p>This code is discussed in <a href="http://pylonshq.com/project/pylonshq/ticket/135" class="reference">ticket 135</a> but shouldn't be used with
+file uploads since these shouldn't ordinarily be decoded to Unicode.</p>
+</div>
+<div class="section">
+<h2><a href="#id9" id="templating" name="templating" class="toc-backref">2.2   Templating</a></h2>
+<p>Pylons uses Myghty as its default templating language and Myghty 1.1 and above
+fully support Unicode. The Myghty documentation explains how to use Unicode and
+you at <a href="http://www.myghty.org/docs/unicode.myt" class="reference">http://www.myghty.org/docs/unicode.myt</a> but the important idea is that
+you can Unicode literals pretty much anywhere you can use normal 8-bit strings
+including in <tt class="docutils literal"><span class="pre">m.write()</span></tt> and <tt class="docutils literal"><span class="pre">m.comp()</span></tt>. You can also pass Unicode data to
+Pylons' <tt class="docutils literal"><span class="pre">render_response()</span></tt> and <tt class="docutils literal"><span class="pre">Response()</span></tt> callables.</p>
+<p>Any Unicode data output by Myghty is automatically decoded to whichever
+encoding you have chosen. The default is UTF-8 but you can choose which
+encoding to use by editing your project's <tt class="docutils literal"><span class="pre">config/environment.py</span></tt> file and
+adding an option like this:</p>
+<textarea name="code" class="python">
+# Add your own Myghty config options here, note that all config options will override
+# any Pylons config options
+
+myghty['output_encoding'] = 'UTF-8'
+</textarea><p>replacing <tt class="docutils literal"><span class="pre">UTF-8</span></tt> with the encoding you wish to use.</p>
+<p>If you need to disable Unicode support altogether you can set this:</p>
+<textarea name="code" class="python">
+myghty['disable_unicode'] = True
+</textarea><p>but again, you would have to have a good reason to want to do this.</p>
+</div>
+<div class="section">
+<h2><a href="#id10" id="output-encoding" name="output-encoding" class="toc-backref">2.3   Output Encoding</a></h2>
+<p>Web pages should be generated with a specific encoding, most likely UTF-8. At
+the very least, that means you should specify the following in the <tt class="docutils literal"><span class="pre">&lt;head></span></tt>
+section:</p>
+<pre class="literal-block">
+&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</pre>
+<p>You should also set the charset in the <tt class="docutils literal"><span class="pre">Content-Type</span></tt> header:</p>
+<textarea name="code" class="python">
+respones = Response(...)
+response.headers['Content-type'] = 'text/html; charset=utf-8'
+</textarea><p>If you specify that your output is UTF-8, generally the web browser will
+give you UTF-8. If you want the browser to submit data using a different
+character set, you can set the encoding by adding the <tt class="docutils literal"><span class="pre">accept-encoding</span></tt>
+tag to your form. Here is an example:</p>
+<pre class="literal-block">
+&lt;form accept-encoding="US-ASCII" ...>
+</pre>
+<p>However, be forewarned that if the user tries to give you non-ASCII
+text, then:</p>
+<blockquote>
+<ul class="simple">
+<li>Firefox will translate the non-ASCII text into HTML entities.</li>
+<li>IE will ignore your suggested encoding and give you UTF-8 anyway.</li>
+</ul>
+</blockquote>
+<p>The lesson to be learned is that if you output UTF-8, you had better be
+prepared to accept UTF-8 by decoding the data in <tt class="docutils literal"><span class="pre">request.params</span></tt> as
+described in the section above entitled "Request Parameters".</p>
+<p>Another technique which is sometimes used to determine the character set is to
+use an algorithm to analyse the input and guess the encoding based on
+probabilities.</p>
+<p>For instance, if you get a file, and you don't know what encoding it is encoded
+in, you can often rename the file with a .txt extension and then try to open it
+in Firefox.  Then you can use the "View->Character Encoding" menu to try to
+auto-detect the encoding.</p>
+</div>
+<div class="section">
+<h2><a href="#id11" id="databases" name="databases" class="toc-backref">2.4   Databases</a></h2>
+<p>Your database driver should automatically convert from Unicode objects to a
+particular charset when writing and back again when reading. Again it is normal
+to use UTF-8 which is well supported.</p>
+<p>You should check your database's documentation for information on how it handles
+Unicode.</p>
+<p>For example MySQL's Unicode documentation is here
+<a href="http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html" class="reference">http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html</a></p>
+<p>Also note that you need to consider both the encoding of the database
+and the encoding used by the database driver.</p>
+<p>If you're using MySQL together with SQLAlchemy, see the following, as
+there are some bugs in MySQLdb that you'll need to work around:</p>
+<p><a href="http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg00366.html" class="reference">http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg00366.html</a></p>
+</div>
+</div>
+<div class="section">
+<h1><a href="#id12" id="internationalization-and-localization" name="internationalization-and-localization" class="toc-backref">3   Internationalization and Localization</a></h1>
+<p>By now you should have a good idea of what Unicode is, how to use it in Python
+and which areas of you application need to pay specific attention to decoding and
+encoding Unicode data.</p>
+<p>This final section will look at the issue of making your application work with
+multiple languages.</p>
+<div class="section">
+<h2><a href="#id13" id="getting-started" name="getting-started" class="toc-backref">3.1   Getting Started</a></h2>
+<p>Everywhere in your code where you want strings to be available in different
+languages you wrap them in the <tt class="docutils literal"><span class="pre">_()</span></tt> function. There
+are also a number of other translation functions which are documented in the API reference at
+<a href="http://pylonshq.com/docs/module-pylons.i18n.translation.html" class="reference">http://pylonshq.com/docs/module-pylons.i18n.translation.html</a></p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">The <tt class="docutils literal"><span class="pre">_()</span></tt> function is a reference to the <tt class="docutils literal"><span class="pre">ugettext()</span></tt> function.
+<tt class="docutils literal"><span class="pre">_()</span></tt> is a convention for marking text to be translated and saves on keystrokes.
+<tt class="docutils literal"><span class="pre">ugettext()</span></tt> is the Unicode version of <tt class="docutils literal"><span class="pre">gettext()</span></tt>.</p>
+</div>
+<p>In our example we want the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> to appear in three different
+languages: English, French and Spanish. We also want to display the word
+<tt class="docutils literal"><span class="pre">'Hello'</span></tt> in the default language. We'll then go on to use some pural words
+too.</p>
+<p>Lets call our project <tt class="docutils literal"><span class="pre">translate_demo</span></tt>:</p>
+<pre class="literal-block">
+paster create --template=pylons translate_demo
+</pre>
+<p>Now lets add a friendly controller that says hello:</p>
+<pre class="literal-block">
+cd translate_demo
+paster controller hello
+</pre>
+<p>Edit <tt class="docutils literal"><span class="pre">controllers/hello.py</span></tt> controller to look like this making use of the
+<tt class="docutils literal"><span class="pre">_()</span></tt> function everywhere where the string <tt class="docutils literal"><span class="pre">Hello</span></tt> appears:</p>
+<textarea name="code" class="python">
+from translate_demo.lib.base import *
+
+class HelloController(BaseController):
+
+    def index(self):
+        resp = Response()
+        resp.write('Default: %s&lt;br />' % _('Hello'))
+        for lang in ['fr','en','es']:
+            h.set_lang(lang)
+            resp.write("%s: %s&lt;br />" % (h.get_lang(), _('Hello')))
+        return resp
+</textarea><p>When writing your controllers it is important not to piece sentences together manually because
+certain languages might need to invert the grammars. As an example this is bad:</p>
+<textarea name="code" class="python">
+# BAD!
+msg = _("He told her ")
+msg += _("not to go outside.")
+</textarea><p>but this is perfectly acceptable:</p>
+<textarea name="code" class="python">
+# GOOD
+msg = _("He told her not to go outside")
+</textarea><p>The controller has now been internationalized but it will raise a <tt class="docutils literal"><span class="pre">LanguageError</span></tt>
+until we have specified the alternative languages.</p>
+<p>Pylons uses <a href="http://www.gnu.org/software/gettext/" class="reference">GNU gettext</a> to handle
+internationalization. GNU gettext use three types of files in the
+translation framework.</p>
+<p>POT (Portable Object Template) files</p>
+<blockquote>
+The first step in the localization process. A program is used to search through
+your project's source code and pick out every string passed to one of the
+translation functions, such as <tt class="docutils literal"><span class="pre">_()</span></tt>. This list is put together in a
+specially-formatted template file that will form the basis of all
+translations. This is the <tt class="docutils literal"><span class="pre">.pot</span></tt> file.</blockquote>
+<p>PO (Portable Object) files</p>
+<blockquote>
+The second step in the localization process. Using the POT file as a template,
+the list of messages are translated and saved as a <tt class="docutils literal"><span class="pre">.po</span></tt> file.</blockquote>
+<p>MO (Machine Object) files</p>
+<blockquote>
+The final step in the localization process. The PO file is run through a
+program that turns it into an optimized machine-readable binary file, which is
+the <tt class="docutils literal"><span class="pre">.mo</span></tt> file. Compiling the translations to machine code makes the
+localized program much faster in retrieving the translations while it is
+running.</blockquote>
+<p>Versions of Pylons prior to 0.9.4 came with a setuptools extension to help with
+the extraction of strings and production of a <tt class="docutils literal"><span class="pre">.mo</span></tt> file. The implementation
+did not support Unicode nor the ungettext function and was therfore dropped in
+Python 0.9.4.</p>
+<p>You will therefore need to use an external program to perform these tasks.  You
+may use whichever you prefer but <tt class="docutils literal"><span class="pre">xgettext</span></tt> is highly recommended. Python's
+gettext utility has some bugs, especially regarding plurals.</p>
+<p>Here are some compatible tools and projects:</p>
+<p>The Rosetta Project (<a href="https://launchpad.ubuntu.com/rosetta/" class="reference">https://launchpad.ubuntu.com/rosetta/</a>)</p>
+<blockquote>
+The Ubuntu Linux project has a web site that allows you to translate
+messages without even looking at a PO or POT file, and export directly to a MO.</blockquote>
+<p>poEdit (<a href="http://www.poedit.org/" class="reference">http://www.poedit.org/</a>)</p>
+<blockquote>
+An open source program for Windows and UNIX/Linux which provides an easy-to-use
+GUI for editing PO files and generating MO files.</blockquote>
+<p>KBabel (<a href="http://i18n.kde.org/tools/kbabel/" class="reference">http://i18n.kde.org/tools/kbabel/</a>)</p>
+<blockquote>
+Another open source PO editing program for KDE.</blockquote>
+<p>GNU Gettext (<a href="http://www.gnu.org/software/gettext/" class="reference">http://www.gnu.org/software/gettext/</a>)</p>
+<blockquote>
+The official Gettext tools package contains command-line tools for creating
+POTs, manipulating POs, and generating MOs. For those comfortable with a
+command shell.</blockquote>
+<p>As an example we will quickly discuss the use of poEdit which is cross platform
+and has a GUI which makes it easier to get started with.</p>
+<p>To use poEdit with the <tt class="docutils literal"><span class="pre">translate_demo</span></tt> you would do the following:</p>
+<ol class="arabic simple">
+<li>Download and install poEdit.</li>
+<li>A dialog pops up. Fill in <em>all</em> the fields you can on the <tt class="docutils literal"><span class="pre">Project</span> <span class="pre">Info</span></tt> tab, enter the path to your project on the <tt class="docutils literal"><span class="pre">Paths</span></tt> tab (ie <tt class="docutils literal"><span class="pre">/path/to/translate_demo</span></tt>) and enter the following keywords on separate lines on the <tt class="docutils literal"><span class="pre">keywords</span></tt> tab: <tt class="docutils literal"><span class="pre">_</span></tt>, <tt class="docutils literal"><span class="pre">N_</span></tt>, <tt class="docutils literal"><span class="pre">ugettext</span></tt>, <tt class="docutils literal"><span class="pre">gettext</span></tt>, <tt class="docutils literal"><span class="pre">ngettext</span></tt>, <tt class="docutils literal"><span class="pre">ungettext</span></tt>.</li>
+<li>Click OK</li>
+</ol>
+<p>poEdit will search your source tree and find all the strings you have marked
+up. You can then enter your translations in whatever charset you chose in
+the project info tab. UTF-8 is a good choice.</p>
+<p>Finally, after entering your translations you then save the catalog and rename
+the <tt class="docutils literal"><span class="pre">.mo</span></tt> file produced to <tt class="docutils literal"><span class="pre">translate_demo.mo</span></tt> and put it in the
+<tt class="docutils literal"><span class="pre">translate_demo/i18n/es/LC_MESSAGES</span></tt> directory or whatever is appropriate for
+your translation.</p>
+<p>You will need to repeat the process of creating a <tt class="docutils literal"><span class="pre">.mo</span></tt> file for the <tt class="docutils literal"><span class="pre">fr</span></tt>,
+<tt class="docutils literal"><span class="pre">es</span></tt> and <tt class="docutils literal"><span class="pre">en</span></tt> translations.</p>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/en/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "Hello"
+</pre>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/es/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "°Hola!"
+</pre>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/fr/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "Bonjour"
+</pre>
+<p>Whichever tools you use you should end up with an <tt class="docutils literal"><span class="pre">i18n</span></tt> directory that looks
+like this when you have finished:</p>
+<pre class="literal-block">
+i18n/en/LC_MESSAGES/translate_demo.po
+i18n/en/LC_MESSAGES/translate_demo.mo
+i18n/es/LC_MESSAGES/translate_demo.po
+i18n/es/LC_MESSAGES/translate_demo.mo
+i18n/fr/LC_MESSAGES/translate_demo.po
+i18n/fr/LC_MESSAGES/translate_demo.mo
+</pre>
+</div>
+<div class="section">
+<h2><a href="#id14" id="testing-the-application" name="testing-the-application" class="toc-backref">3.2   Testing the Application</a></h2>
+<p>Start the server with the following command:</p>
+<pre class="literal-block">
+paster serve --reload development.ini
+</pre>
+<p>Test your controller by visiting <a href="http://localhost:5000/hello" class="reference">http://localhost:5000/hello</a>. You should see
+the following output:</p>
+<pre class="literal-block">
+Default: Hello
+fr: Bonjour
+en: Hello
+es: °Hola!
+</pre>
+<p>You can now set the language used in a controller on the fly.</p>
+<p>For example this could be used to allow a user to set which language they
+wanted your application to work in. You could save the value to the session
+object:</p>
+<textarea name="code" class="python">
+session['lang'] = 'en'
+</textarea><p>then on each controller call the language to be used could be read from the
+session and set in your controller's <tt class="docutils literal"><span class="pre">__before__()</span></tt> method so that the pages
+remained in the same language that was previously set:</p>
+<textarea name="code" class="python">
+def __before__(self, action):
+    if session.has_key('lang'):
+        h.set_lang(session['lang'])
+</textarea><p>One more useful thing to be able to do is to set the default language to be
+used in the configuration file. Just add a <tt class="docutils literal"><span class="pre">lang</span></tt> variable together with the
+code of the language you wanted to use in your <tt class="docutils literal"><span class="pre">development.ini</span></tt> file. For
+example to set the default language to Spanish you would add <tt class="docutils literal"><span class="pre">lang</span> <span class="pre">=</span> <span class="pre">es</span></tt> to
+your <tt class="docutils literal"><span class="pre">development.ini</span></tt>. The relevant part from the file might look something
+like this:</p>
+<textarea name="code" class="pasteini">
+[app:main]
+use = egg:translate_demo
+lang = es
+</textarea><p>If you are running the server with the <tt class="docutils literal"><span class="pre">--reload</span></tt> option the server will
+automatically restart if you change the <tt class="docutils literal"><span class="pre">development.ini</span></tt> file. Otherwise
+restart the server manually and the output would this time be as follows:</p>
+<pre class="literal-block">
+Default: °Hola!
+fr: Bonjour
+en: Hello
+es: °Hola!
+</pre>
+</div>
+<div class="section">
+<h2><a href="#id15" id="missing-translations" name="missing-translations" class="toc-backref">3.3   Missing Translations</a></h2>
+<p>If your code calls <tt class="docutils literal"><span class="pre">_()</span></tt> with a string that doesn't exist in your language
+catalogue, the string passed to <tt class="docutils literal"><span class="pre">_()</span></tt> is returned instead.</p>
+<p>Modify the last line of the hello controller to look like this:</p>
+<textarea name="code" class="python">
+resp.write("%s: %s %s&lt;br />" % (h.get_lang(), _('Hello'), _('World!')))
+</textarea><div class="warning">
+<p class="first admonition-title">Warning</p>
+<p class="last">Of course, in real life breaking up sentences in this way is very dangerous because some
+grammars might require the order of the words to be different.</p>
+</div>
+<p>If you run the example again the output will be:</p>
+<pre class="literal-block">
+Default: °Hola!
+fr: Bonjour World!
+en: Hello World!
+es: °Hola! World!
+</pre>
+<p>This is because we never provided a translation for the string <tt class="docutils literal"><span class="pre">'World!'</span></tt> so
+the string itself is used.</p>
+</div>
+<div class="section">
+<h2><a href="#id16" id="translations-within-templates" name="translations-within-templates" class="toc-backref">3.4   Translations Within Templates</a></h2>
+<p>You can also use the <tt class="docutils literal"><span class="pre">_()</span></tt> function within templates in exactly the same way
+you do in code. For example:</p>
+<textarea name="code" class="html">
+&lt;% _('Hello') %>
+</textarea><p>would produce the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> in the language you had set.</p>
+<p>There is one complication though. gettext's <tt class="docutils literal"><span class="pre">xgettext</span></tt> command can only extract
+strings that need translating from Python code in <tt class="docutils literal"><span class="pre">.py</span></tt> files. This means
+that if you write <tt class="docutils literal"><span class="pre">_('Hello')</span></tt> in a template such as a Myghty template,
+<tt class="docutils literal"><span class="pre">xgettext</span></tt> will not find the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> as one which needs
+translating.</p>
+<p>As long as <tt class="docutils literal"><span class="pre">xgettext</span></tt> can find a string marked for translation with one
+of the translation functions and defined in Python code in your project
+filesystem it will manage the translation when the same string is defined in a
+Myghty template and marked for translation.</p>
+<p>One solution to ensure all strings are picked up for translation is to create a
+file in <tt class="docutils literal"><span class="pre">lib</span></tt> with an appropriate filename, <tt class="docutils literal"><span class="pre">i18n.py</span></tt> for example, and then
+add a list of all the strings which appear in your templates so that your
+translation tool can then extract the strings in <tt class="docutils literal"><span class="pre">lib/i18n.py</span></tt> for
+translation and use the translated versions in your templates as well.</p>
+<p>For example if you wanted to ensure the translated string <tt class="docutils literal"><span class="pre">'Good</span> <span class="pre">Morning'</span></tt>
+was available in all templates you could create a <tt class="docutils literal"><span class="pre">lib/i18n.py</span></tt> file that
+looked something like this:</p>
+<textarea name="code" class="python">
+from base import _
+_('Good Morning')
+</textarea><p>This approach requires quite a lot of work and is rather fragile. The best
+solution if you are using a templating system such as Myghty or Cheetah which
+uses compiled Python files is to use a Makefile to ensure that every template
+is compiled to Python before running the extraction tool to make sure that
+every template is scanned.</p>
+<p>Of course, if your cache directory is in the default location or elsewhere
+within your project's filesystem, you will probably find that all templates
+have been compiled as Python files during the course of the development process.
+This means that your tool's extraction command will successfully pick up
+strings to translate from the cached files anyway.</p>
+<p>You may also find that your extraction tool is capable of extracting the
+strings correctly from the template anyway, particularly if the templating
+langauge is quite similar to Python. It is best not to rely on this though.</p>
+</div>
+<div class="section">
+<h2><a href="#id17" id="producing-a-python-egg" name="producing-a-python-egg" class="toc-backref">3.5   Producing a Python Egg</a></h2>
+<p>Finally you can produce an egg of your project which includes the translation
+files like this:</p>
+<pre class="literal-block">
+python setup.py bdist_egg
+</pre>
+<p>The <tt class="docutils literal"><span class="pre">setup.py</span></tt> automatically includes the <tt class="docutils literal"><span class="pre">.mo</span></tt> language catalogs your
+application needs so that your application can be distributed as an egg. This
+is done with the following line in your <tt class="docutils literal"><span class="pre">setup.py</span></tt> file:</p>
+<pre class="literal-block">
+package_data={'translate_demo': ['i18n/*/LC_MESSAGES/*.mo']},
+</pre>
+<p>Internationalization support is zip safe so your application can be run
+directly from the egg without the need for <tt class="docutils literal"><span class="pre">easy_install</span></tt> to extract it.</p>
+</div>
+<div class="section">
+<h2><a href="#id18" id="plural-forms" name="plural-forms" class="toc-backref">3.6   Plural Forms</a></h2>
+<p>Pylons also defines <tt class="docutils literal"><span class="pre">ungettext()</span></tt> and <tt class="docutils literal"><span class="pre">ngettext()</span></tt> functions which can be imported
+from <tt class="docutils literal"><span class="pre">pylons.i18n</span></tt>. They are designed for internationalizing plural words and can be
+used as follows:</p>
+<textarea name="code" class="python">
+from pylons.i18n import ungettext
+
+ungettext(
+    'There is %(num)d file here',
+    'There are %(num)d files here',
+    n
+) % {'num': n}
+</textarea><p>If you wish to use plural forms in your application you need to add the appropriate
+headers to the <tt class="docutils literal"><span class="pre">.po</span></tt> files for the language you are using. You can read more about
+this at <a href="http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150" class="reference">http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150</a></p>
+<p>One thing to keep in mind is that other languages don't have the same
+plural forms as English.  While English only has 2 pulral forms, singular and
+plural, Slovenian has 4!  That means that you must use gettext's
+support for pluralization if you hope to get pluralization right.
+Specifically, the following will not work:</p>
+<textarea name="code" class="python">
+# BAD!
+    if n == 1:
+        msg = _("There was no dog.")
+    else:
+        msg = _("There were no dogs.")
+</textarea></div>
+</div>
+<div class="section">
+<h1><a href="#id19" id="summary" name="summary" class="toc-backref">4   Summary</a></h1>
+<p>Hopefully you now understand the history of Unicode, how to use it in Python
+and where to apply Unicode encoding and decoding in a Pylons application. You
+should also be able to use Unicode in your web app remembering the basic rule to
+use UTF-8 to talk to the world, do the encode and decode at the edge of your
+application.</p>
+<p>You should also be able to internationalize and then localize your application
+using Pylons' support for GNU gettext.</p>
+</div>
+<div class="section">
+<h1><a href="#id20" id="further-reading" name="further-reading" class="toc-backref">5   Further Reading</a></h1>
+<p>This information is based partly on the following articles which can be
+consulted for further information.:</p>
+<p><a href="http://www.joelonsoftware.com/articles/Unicode.html" class="reference">http://www.joelonsoftware.com/articles/Unicode.html</a></p>
+<p><a href="http://www.amk.ca/python/howto/unicode" class="reference">http://www.amk.ca/python/howto/unicode</a></p>
+<p><a href="http://en.wikipedia.org/wiki/Internationalization" class="reference">http://en.wikipedia.org/wiki/Internationalization</a></p>
+<p>Please feel free to report any mistakes to the Pylons mailing list or to the
+author. Any corrections or clarifications would be gratefully received.</p>
+</div>
+
+</div>
\ No newline at end of file
diff --git a/test/templates/modtest.html b/test/templates/modtest.html
new file mode 100644 (file)
index 0000000..a8a9406
--- /dev/null
@@ -0,0 +1 @@
+this is a test
\ No newline at end of file
diff --git a/test/templates/othersubdir/foo.html b/test/templates/othersubdir/foo.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/templates/read_unicode.html b/test/templates/read_unicode.html
new file mode 100644 (file)
index 0000000..50f00c3
--- /dev/null
@@ -0,0 +1,10 @@
+<% 
+try:
+    file_content = open(path)
+except:
+    raise "Should never execute here"
+doc_content = ''.join(file_content.readlines())
+file_content.close()
+%>
+
+${unicode(doc_content, encoding='utf-8')}
diff --git a/test/templates/read_unicode_py3k.html b/test/templates/read_unicode_py3k.html
new file mode 100644 (file)
index 0000000..c94399e
--- /dev/null
@@ -0,0 +1,10 @@
+<% 
+try:
+    file_content = open(path, encoding='utf-8', errors='ignore')
+except:
+    raise "Should never execute here"
+doc_content = ''.join(file_content.readlines())
+file_content.close()
+%>
+
+${bytes(doc_content, encoding='utf-8')}
diff --git a/test/templates/runtimeerr.html b/test/templates/runtimeerr.html
new file mode 100644 (file)
index 0000000..6b36b95
--- /dev/null
@@ -0,0 +1,4 @@
+<%
+    print y
+    y = 10
+%>
\ No newline at end of file
diff --git a/test/templates/runtimeerr_py3k.html b/test/templates/runtimeerr_py3k.html
new file mode 100644 (file)
index 0000000..d2569e9
--- /dev/null
@@ -0,0 +1,4 @@
+<%
+    print(y)
+    y = 10
+%>
\ No newline at end of file
diff --git a/test/templates/subdir/foo/modtest.html.py b/test/templates/subdir/foo/modtest.html.py
new file mode 100644 (file)
index 0000000..b0f50c7
--- /dev/null
@@ -0,0 +1,25 @@
+from mako import runtime, filters, cache
+UNDEFINED = runtime.UNDEFINED
+__M_dict_builtin = dict
+__M_locals_builtin = locals
+_magic_number = 5
+_modified_time = 1267565427.799504
+_template_filename='/Users/classic/dev/mako/test/templates/subdir/modtest.html'
+_template_uri='/subdir/modtest.html'
+_template_cache=cache.Cache(__name__, _modified_time)
+_source_encoding=None
+_exports = []
+
+
+def render_body(context,**pageargs):
+    context.caller_stack._push_frame()
+    try:
+        __M_locals = __M_dict_builtin(pageargs=pageargs)
+        __M_writer = context.writer()
+        # SOURCE LINE 1
+        __M_writer('this is a test')
+        return ''
+    finally:
+        context.caller_stack._pop_frame()
+
+
diff --git a/test/templates/subdir/incl.html b/test/templates/subdir/incl.html
new file mode 100644 (file)
index 0000000..6505b7c
--- /dev/null
@@ -0,0 +1,2 @@
+
+    this is include 2
diff --git a/test/templates/subdir/index.html b/test/templates/subdir/index.html
new file mode 100644 (file)
index 0000000..5b878b8
--- /dev/null
@@ -0,0 +1,3 @@
+
+    this is sub index
+    <%include file="incl.html"/>
diff --git a/test/templates/subdir/modtest.html b/test/templates/subdir/modtest.html
new file mode 100644 (file)
index 0000000..a8a9406
--- /dev/null
@@ -0,0 +1 @@
+this is a test
\ No newline at end of file
diff --git a/test/templates/unicode.html b/test/templates/unicode.html
new file mode 100644 (file)
index 0000000..8713f7f
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »
\ No newline at end of file
diff --git a/test/templates/unicode_arguments.html b/test/templates/unicode_arguments.html
new file mode 100644 (file)
index 0000000..b363cb6
--- /dev/null
@@ -0,0 +1,10 @@
+# coding: utf-8
+
+<%def name="my_def(x)">
+    x is: ${x}
+</%def>
+
+${my_def(u'drôle de petite voix m’a réveillé')}
+<%self:my_def x='drôle de petite voix m’a réveillé'/>
+<%self:my_def x="${u'drôle de petite voix m’a réveillé'}"/>
+<%call expr="my_def(u'drôle de petite voix m’a réveillé')"/>
diff --git a/test/templates/unicode_arguments_py3k.html b/test/templates/unicode_arguments_py3k.html
new file mode 100644 (file)
index 0000000..47d918a
--- /dev/null
@@ -0,0 +1,10 @@
+# coding: utf-8
+
+<%def name="my_def(x)">
+    x is: ${x}
+</%def>
+
+${my_def('drôle de petite voix m’a réveillé')}
+<%self:my_def x='drôle de petite voix m’a réveillé'/>
+<%self:my_def x="${'drôle de petite voix m’a réveillé'}"/>
+<%call expr="my_def('drôle de petite voix m’a réveillé')"/>
diff --git a/test/templates/unicode_code.html b/test/templates/unicode_code.html
new file mode 100644 (file)
index 0000000..700c043
--- /dev/null
@@ -0,0 +1,7 @@
+## -*- coding: utf-8 -*-
+<%
+    x = u"drôle de petite voix m’a réveillé."
+%>
+% if x==u"drôle de petite voix m’a réveillé.":
+    hi, ${x}
+% endif
diff --git a/test/templates/unicode_code_py3k.html b/test/templates/unicode_code_py3k.html
new file mode 100644 (file)
index 0000000..8835b25
--- /dev/null
@@ -0,0 +1,7 @@
+## -*- coding: utf-8 -*-
+<%
+    x = "drôle de petite voix m’a réveillé."
+%>
+% if x=="drôle de petite voix m’a réveillé.":
+    hi, ${x}
+% endif
diff --git a/test/templates/unicode_expr.html b/test/templates/unicode_expr.html
new file mode 100644 (file)
index 0000000..cad7522
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+${u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"}
diff --git a/test/templates/unicode_expr_py3k.html b/test/templates/unicode_expr_py3k.html
new file mode 100644 (file)
index 0000000..f9b292d
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+${"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"}
diff --git a/test/templates/unicode_runtime_error.html b/test/templates/unicode_runtime_error.html
new file mode 100644 (file)
index 0000000..862dce5
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+<% print 'Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »' + int(5/0) %>
\ No newline at end of file
diff --git a/test/templates/unicode_syntax_error.html b/test/templates/unicode_syntax_error.html
new file mode 100644 (file)
index 0000000..982af33
--- /dev/null
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+<% print 'Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! » %>
\ No newline at end of file
diff --git a/test/test_ast.py b/test/test_ast.py
new file mode 100644 (file)
index 0000000..32a1d74
--- /dev/null
@@ -0,0 +1,377 @@
+import unittest
+
+from mako import ast, exceptions, pyparser, util, compat
+from test import eq_, requires_python_2, requires_python_3, \
+            requires_python_26_or_greater
+
+exception_kwargs = {
+    'source': '',
+    'lineno': 0,
+    'pos': 0,
+    'filename': ''}
+
+class AstParseTest(unittest.TestCase):
+
+    def test_locate_identifiers(self):
+        """test the location of identifiers in a python code string"""
+        code = """
+a = 10
+b = 5
+c = x * 5 + a + b + q
+(g,h,i) = (1,2,3)
+[u,k,j] = [4,5,6]
+foo.hoho.lala.bar = 7 + gah.blah + u + blah
+for lar in (1,2,3):
+    gh = 5
+    x = 12
+("hello world, ", a, b)
+("Another expr", c)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(
+            parsed.declared_identifiers,
+            set(['a', 'b', 'c', 'g', 'h', 'i', 'u',
+                'k', 'j', 'gh', 'lar', 'x'])
+        )
+        eq_(
+            parsed.undeclared_identifiers,
+            set(['x', 'q', 'foo', 'gah', 'blah'])
+        )
+
+        parsed = ast.PythonCode("x + 5 * (y-z)", **exception_kwargs)
+        assert parsed.undeclared_identifiers == set(['x', 'y', 'z'])
+        assert parsed.declared_identifiers == set()
+
+    def test_locate_identifiers_2(self):
+        code = """
+import foobar
+from lala import hoho, yaya
+import bleep as foo
+result = []
+data = get_data()
+for x in data:
+    result.append(x+7)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['get_data']))
+        eq_(
+            parsed.declared_identifiers,
+            set(['result', 'data', 'x', 'hoho', 'foobar', 'foo', 'yaya'])
+        )
+
+    def test_locate_identifiers_3(self):
+        """test that combination assignment/expressions
+        of the same identifier log the ident as 'undeclared'"""
+        code = """
+x = x + 5
+for y in range(1, y):
+    ("hi",)
+[z for z in range(1, z)]
+(q for q in range (1, q))
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(
+            parsed.undeclared_identifiers,
+            set(['x', 'y', 'z', 'q', 'range'])
+        )
+
+    def test_locate_identifiers_4(self):
+        code = """
+x = 5
+(y, )
+def mydef(mydefarg):
+    print("mda is", mydefarg)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['y']))
+        eq_(parsed.declared_identifiers, set(['mydef', 'x']))
+
+    def test_locate_identifiers_5(self):
+        code = """
+try:
+    print(x)
+except:
+    print(y)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['x', 'y']))
+
+    def test_locate_identifiers_6(self):
+        code = """
+def foo():
+    return bar()
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['bar']))
+
+        code = """
+def lala(x, y):
+    return x, y, z
+print(x)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['z', 'x']))
+        eq_(parsed.declared_identifiers, set(['lala']))
+
+        code = """
+def lala(x, y):
+    def hoho():
+        def bar():
+            z = 7
+print(z)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['z']))
+        eq_(parsed.declared_identifiers, set(['lala']))
+
+    def test_locate_identifiers_7(self):
+        code = """
+import foo.bar
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['foo']))
+        eq_(parsed.undeclared_identifiers, set())
+
+    def test_locate_identifiers_8(self):
+        code = """
+class Hi(object):
+    foo = 7
+    def hoho(self):
+        x = 5
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['Hi']))
+        eq_(parsed.undeclared_identifiers, set())
+
+    def test_locate_identifiers_9(self):
+        code = """
+    ",".join([t for t in ("a", "b", "c")])
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['t']))
+        eq_(parsed.undeclared_identifiers, set(['t']))
+
+        code = """
+    [(val, name) for val, name in x]
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['val', 'name']))
+        eq_(parsed.undeclared_identifiers, set(['val', 'name', 'x']))
+
+    def test_locate_identifiers_10(self):
+        code = """
+lambda q: q + 5
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set())
+        eq_(parsed.undeclared_identifiers, set())
+
+    def test_locate_identifiers_11(self):
+        code = """
+def x(q):
+    return q + 5
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['x']))
+        eq_(parsed.undeclared_identifiers, set())
+
+
+    def test_locate_identifiers_12(self):
+        code = """
+def foo():
+    s = 1
+    def bar():
+        t = s
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['foo']))
+        eq_(parsed.undeclared_identifiers, set())
+
+    def test_locate_identifiers_13(self):
+        code = """
+def foo():
+    class Bat(object):
+        pass
+    Bat
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['foo']))
+        eq_(parsed.undeclared_identifiers, set())
+
+    def test_locate_identifiers_14(self):
+        code = """
+def foo():
+    class Bat(object):
+        pass
+    Bat
+
+print(Bat)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['foo']))
+        eq_(parsed.undeclared_identifiers, set(['Bat']))
+
+    @requires_python_2
+    def test_locate_identifiers_15(self):
+        code = """
+def t1((x,y)):
+    return x+5, y+4
+
+t2 = lambda (x,y):(x+5, y+4)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['t1', 't2']))
+        eq_(parsed.undeclared_identifiers, set())
+
+    @requires_python_26_or_greater
+    def test_locate_identifiers_16(self):
+        code = """
+try:
+    print(x)
+except Exception as e:
+    print(y)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['x', 'y', 'Exception']))
+
+    @requires_python_26_or_greater
+    def test_locate_identifiers_17(self):
+        code = """
+try:
+    print(x)
+except (Foo, Bar) as e:
+    print(y)
+"""
+        parsed = ast.PythonCode(code, **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['x', 'y', 'Foo', 'Bar']))
+
+    def test_no_global_imports(self):
+        code = """
+from foo import *
+import x as bar
+"""
+        self.assertRaises(exceptions.CompileException,
+            ast.PythonCode, code, **exception_kwargs)
+
+    def test_python_fragment(self):
+        parsed = ast.PythonFragment("for x in foo:", **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['x']))
+        eq_(parsed.undeclared_identifiers, set(['foo']))
+
+        parsed = ast.PythonFragment("try:", **exception_kwargs)
+
+        if compat.py3k:
+            parsed = ast.PythonFragment(
+                        "except MyException as e:", **exception_kwargs)
+        else:
+            parsed = ast.PythonFragment(
+                        "except MyException, e:", **exception_kwargs)
+        eq_(parsed.declared_identifiers, set(['e']))
+        eq_(parsed.undeclared_identifiers, set(['MyException']))
+
+    def test_argument_list(self):
+        parsed = ast.ArgumentList("3, 5, 'hi', x+5, "
+                    "context.get('lala')", **exception_kwargs)
+        eq_(parsed.undeclared_identifiers, set(['x', 'context']))
+        eq_([x for x in parsed.args],
+            ["3", "5", "'hi'", "(x + 5)", "context.get('lala')"])
+
+        parsed = ast.ArgumentList("h", **exception_kwargs)
+        eq_(parsed.args, ["h"])
+
+    def test_function_decl(self):
+        """test getting the arguments from a function"""
+        code = "def foo(a, b, c=None, d='hi', e=x, f=y+7):pass"
+        parsed = ast.FunctionDecl(code, **exception_kwargs)
+        eq_(parsed.funcname, 'foo')
+        eq_(parsed.argnames,
+            ['a', 'b', 'c', 'd', 'e', 'f'])
+        eq_(parsed.kwargnames,
+            [])
+
+    def test_function_decl_2(self):
+        """test getting the arguments from a function"""
+        code = "def foo(a, b, c=None, *args, **kwargs):pass"
+        parsed = ast.FunctionDecl(code, **exception_kwargs)
+        eq_(parsed.funcname, 'foo')
+        eq_(parsed.argnames,
+            ['a', 'b', 'c', 'args'])
+        eq_(parsed.kwargnames,
+            ['kwargs'])
+
+    @requires_python_3
+    def test_function_decl_3(self):
+        """test getting the arguments from a fancy py3k function"""
+        code = "def foo(a, b, *c, d, e, **f):pass"
+        parsed = ast.FunctionDecl(code, **exception_kwargs)
+        eq_(parsed.funcname, 'foo')
+        eq_(parsed.argnames,
+            ['a', 'b', 'c'])
+        eq_(parsed.kwargnames,
+            ['d', 'e', 'f'])
+
+    def test_expr_generate(self):
+        """test the round trip of expressions to AST back to python source"""
+        x = 1
+        y = 2
+
+        class F(object):
+            def bar(self, a,b):
+                return a + b
+
+        def lala(arg):
+            return "blah" + arg
+
+        local_dict = dict(x=x, y=y, foo=F(), lala=lala)
+
+        code = "str((x+7*y) / foo.bar(5,6)) + lala('ho')"
+        astnode = pyparser.parse(code)
+        newcode = pyparser.ExpressionGenerator(astnode).value()
+        eq_(eval(code, local_dict), eval(newcode, local_dict))
+
+        a = ["one", "two", "three"]
+        hoho = {'somevalue': "asdf"}
+        g = [1, 2, 3, 4, 5]
+        local_dict = dict(a=a, hoho=hoho, g=g)
+        code = "a[2] + hoho['somevalue'] + "\
+                "repr(g[3:5]) + repr(g[3:]) + repr(g[:5])"
+        astnode = pyparser.parse(code)
+        newcode = pyparser.ExpressionGenerator(astnode).value()
+        eq_(eval(code, local_dict), eval(newcode, local_dict))
+
+        local_dict = {'f': lambda: 9, 'x': 7}
+        code = "x+f()"
+        astnode = pyparser.parse(code)
+        newcode = pyparser.ExpressionGenerator(astnode).value()
+        eq_(eval(code, local_dict), eval(newcode, local_dict))
+
+        for code in ["repr({'x':7,'y':18})",
+                        "repr([])",
+                        "repr({})",
+                        "repr([{3:[]}])",
+                        "repr({'x':37*2 + len([6,7,8])})",
+                        "repr([1, 2, {}, {'x':'7'}])",
+                        "repr({'x':-1})", "repr(((1,2,3), (4,5,6)))",
+                        "repr(1 and 2 and 3 and 4)",
+                        "repr(True and False or 55)",
+                        "repr(lambda x, y: (x + y))",
+                        "repr(lambda *arg, **kw: arg, kw)",
+                        "repr(1 & 2 | 3)",
+                        "repr(3//5)",
+                        "repr(3^5)",
+                        "repr([q.endswith('e') for q in "
+                            "['one', 'two', 'three']])",
+                        "repr([x for x in (5,6,7) if x == 6])",
+                        "repr(not False)"]:
+            local_dict = {}
+            astnode = pyparser.parse(code)
+            newcode = pyparser.ExpressionGenerator(astnode).value()
+            if "lambda" in code:
+                eq_(code, newcode)
+            else:
+                eq_(eval(code, local_dict),
+                    eval(newcode, local_dict)
+                )
+
+
+
diff --git a/test/test_block.py b/test/test_block.py
new file mode 100644 (file)
index 0000000..da3de15
--- /dev/null
@@ -0,0 +1,569 @@
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako import exceptions
+from test import TemplateTest, assert_raises, assert_raises_message
+from test.util import flatten_result, result_lines
+
+
+
+class BlockTest(TemplateTest):
+    def test_anonymous_block_namespace_raises(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "Can't put anonymous blocks inside <%namespace>",
+            Template, """
+                <%namespace name="foo">
+                    <%block>
+                        block
+                    </%block>
+                </%namespace>
+            """
+        )
+
+    def test_anonymous_block_in_call(self):
+        template = Template("""
+
+            <%self:foo x="5">
+                <%block>
+                    this is the block x
+                </%block>
+            </%self:foo>
+
+            <%def name="foo(x)">
+                foo:
+                ${caller.body()}
+            </%def>
+        """)
+        self._do_test(
+            template,
+            ["foo:", "this is the block x"],
+            filters=result_lines
+        )
+
+    def test_named_block_in_call(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "Named block 'y' not allowed inside of <%call> tag",
+            Template,"""
+
+            <%self:foo x="5">
+                <%block name="y">
+                    this is the block
+                </%block>
+            </%self:foo>
+
+            <%def name="foo(x)">
+                foo:
+                ${caller.body()}
+                ${caller.y()}
+            </%def>
+        """)
+
+    def test_name_collision_blocks_toplevel(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "%def or %block named 'x' already exists in this template",
+            Template,
+            """
+                <%block name="x">
+                    block
+                </%block>
+
+                foob
+
+                <%block name="x">
+                    block
+                </%block>
+            """
+        )
+
+    def test_name_collision_blocks_nested_block(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "%def or %block named 'x' already exists in this template",
+            Template,
+            """
+                <%block>
+                <%block name="x">
+                    block
+                </%block>
+
+                foob
+
+                <%block name="x">
+                    block
+                </%block>
+                </%block>
+            """
+        )
+
+    def test_name_collision_blocks_nested_def(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "Named block 'x' not allowed inside of def 'foo'",
+            Template,
+            """
+                <%def name="foo()">
+                <%block name="x">
+                    block
+                </%block>
+
+                foob
+
+                <%block name="x">
+                    block
+                </%block>
+                </%def>
+            """
+        )
+
+    def test_name_collision_block_def_toplevel(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "%def or %block named 'x' already exists in this template",
+            Template,
+            """
+                <%block name="x">
+                    block
+                </%block>
+
+                foob
+
+                <%def name="x()">
+                    block
+                </%def>
+            """
+        )
+
+    def test_name_collision_def_block_toplevel(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "%def or %block named 'x' already exists in this template",
+            Template,
+            """
+                <%def name="x()">
+                    block
+                </%def>
+
+                foob
+
+                <%block name="x">
+                    block
+                </%block>
+
+            """
+        )
+
+    def test_named_block_renders(self):
+        template = Template("""
+            above
+            <%block name="header">
+                the header
+            </%block>
+            below
+        """)
+        self._do_test(template, ["above", "the header", "below"],
+                filters=result_lines)
+
+    def test_inherited_block_no_render(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block name="header">
+                    index header
+                </%block>
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                the header
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "index header", "below"],
+                filters=result_lines)
+
+    def test_no_named_in_def(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "Named block 'y' not allowed inside of def 'q'",
+            Template,
+            """
+            <%def name="q()">
+                <%block name="y">
+                </%block>
+            </%def>
+        """)
+
+    def test_inherited_block_nested_both(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block name="title">
+                    index title
+                </%block>
+
+                <%block name="header">
+                    index header
+                    ${parent.header()}
+                </%block>
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                base header
+                <%block name="title">
+                    the title
+                </%block>
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "index header", "base header", "index title", "below"],
+                filters=result_lines)
+
+    def test_inherited_block_nested_inner_only(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block name="title">
+                    index title
+                </%block>
+
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                base header
+                <%block name="title">
+                    the title
+                </%block>
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "base header", "index title", "below"],
+                filters=result_lines)
+
+    def test_noninherited_block_no_render(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block name="some_thing">
+                    some thing
+                </%block>
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                the header
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "the header", "some thing", "below"],
+                filters=result_lines)
+
+    def test_no_conflict_nested_one(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block>
+                    <%block name="header">
+                        inner header
+                    </%block>
+                </%block>
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                the header
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "inner header", "below"],
+                filters=result_lines)
+
+    def test_nested_dupe_names_raise(self):
+        assert_raises_message(
+            exceptions.CompileException,
+            "%def or %block named 'header' already exists in this template.",
+            Template,
+            """
+                <%inherit file="base"/>
+                <%block name="header">
+                    <%block name="header">
+                        inner header
+                    </%block>
+                </%block>
+            """
+        )
+
+    def test_two_levels_one(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="middle"/>
+                <%block name="header">
+                    index header
+                </%block>
+                <%block>
+                    index anon
+                </%block>
+            """
+        )
+        l.put_string("middle", """
+            <%inherit file="base"/>
+            <%block>
+                middle anon
+            </%block>
+            ${next.body()}
+        """)
+        l.put_string("base","""
+            above
+            <%block name="header">
+                the header
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "index header", "middle anon",
+                "index anon", "below"],
+                filters=result_lines)
+
+    def test_filter(self):
+        template = Template("""
+            <%block filter="h">
+                <html>
+            </%block>
+        """)
+        self._do_test(template, ['&lt;html&gt;'],
+                    filters=result_lines)
+
+    def test_anon_in_named(self):
+        template = Template("""
+            <%block name="x">
+                outer above
+                <%block>
+                    inner
+                </%block>
+                outer below
+            </%block>
+        """)
+        self._test_block_in_block(template)
+
+    def test_named_in_anon(self):
+        template = Template("""
+            <%block>
+                outer above
+                <%block name="x">
+                    inner
+                </%block>
+                outer below
+            </%block>
+        """)
+        self._test_block_in_block(template)
+
+    def test_anon_in_anon(self):
+        template = Template("""
+            <%block>
+                outer above
+                <%block>
+                    inner
+                </%block>
+                outer below
+            </%block>
+        """)
+        self._test_block_in_block(template)
+
+    def test_named_in_named(self):
+        template = Template("""
+            <%block name="x">
+                outer above
+                <%block name="y">
+                    inner
+                </%block>
+                outer below
+            </%block>
+        """)
+        self._test_block_in_block(template)
+
+    def _test_block_in_block(self, template):
+        self._do_test(template,
+            ["outer above", "inner", "outer below"],
+            filters=result_lines
+        )
+
+    def test_iteration(self):
+        t = Template("""
+            % for i in (1, 2, 3):
+                <%block>${i}</%block>
+            % endfor
+        """)
+        self._do_test(t,
+            ["1", "2", "3"],
+            filters=result_lines
+        )
+
+    def test_conditional(self):
+        t = Template("""
+            % if True:
+                <%block>true</%block>
+            % endif
+
+            % if False:
+                <%block>false</%block>
+            % endif
+        """)
+        self._do_test(t,
+            ["true"],
+            filters=result_lines
+        )
+
+    def test_block_overridden_by_def(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%def name="header()">
+                    inner header
+                </%def>
+            """
+        )
+        l.put_string("base","""
+            above
+            <%block name="header">
+                the header
+            </%block>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "inner header", "below"],
+                filters=result_lines)
+
+    def test_def_overridden_by_block(self):
+        l = TemplateLookup()
+        l.put_string("index",
+            """
+                <%inherit file="base"/>
+                <%block name="header">
+                    inner header
+                </%block>
+            """
+        )
+        l.put_string("base","""
+            above
+            ${self.header()}
+            <%def name="header()">
+                the header
+            </%def>
+
+            ${next.body()}
+            below
+        """)
+        self._do_test(l.get_template("index"),
+                ["above", "inner header", "below"],
+                filters=result_lines)
+
+    def test_block_args(self):
+        l = TemplateLookup()
+        l.put_string("caller", """
+
+            <%include file="callee" args="val1='3', val2='4'"/>
+
+        """)
+        l.put_string("callee", """
+            <%page args="val1, val2"/>
+            <%block name="foob" args="val1, val2">
+                foob, ${val1}, ${val2}
+            </%block>
+        """)
+        self._do_test(
+            l.get_template("caller"),
+            ['foob, 3, 4'],
+            filters=result_lines
+        )
+
+    def test_block_variables_contextual(self):
+        t = Template("""
+            <%block name="foob" >
+                foob, ${val1}, ${val2}
+            </%block>
+        """)
+        self._do_test(
+            t,
+            ['foob, 3, 4'],
+            template_args={'val1':3, 'val2':4},
+            filters=result_lines
+        )
+
+    def test_block_args_contextual(self):
+        t = Template("""
+            <%page args="val1"/>
+            <%block name="foob" args="val1">
+                foob, ${val1}, ${val2}
+            </%block>
+        """)
+        self._do_test(
+            t,
+            ['foob, 3, 4'],
+            template_args={'val1':3, 'val2':4},
+            filters=result_lines
+        )
+
+    def test_block_pageargs_contextual(self):
+        t = Template("""
+            <%block name="foob">
+                foob, ${pageargs['val1']}, ${pageargs['val2']}
+            </%block>
+        """)
+        self._do_test(
+            t,
+            ['foob, 3, 4'],
+            template_args={'val1':3, 'val2':4},
+            filters=result_lines
+        )
+
+    def test_block_pageargs(self):
+        l = TemplateLookup()
+        l.put_string("caller", """
+
+            <%include file="callee" args="val1='3', val2='4'"/>
+
+        """)
+        l.put_string("callee", """
+            <%block name="foob">
+                foob, ${pageargs['val1']}, ${pageargs['val2']}
+            </%block>
+        """)
+        self._do_test(
+            l.get_template("caller"),
+            ['foob, 3, 4'],
+            filters=result_lines
+        )
\ No newline at end of file
diff --git a/test/test_cache.py b/test/test_cache.py
new file mode 100644 (file)
index 0000000..990a088
--- /dev/null
@@ -0,0 +1,664 @@
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako import lookup
+import time
+from test.util import result_lines
+from test import TemplateTest, module_base
+from test import eq_, SkipTest
+from mako.compat import py27
+
+from mako.ext import beaker_cache
+
+if beaker_cache.has_beaker:
+    import beaker
+
+from mako.cache import register_plugin, CacheImpl
+
+
+class SimpleBackend(object):
+    def __init__(self):
+        self.cache = {}
+
+    def get(self, key, **kw):
+        return self.cache[key]
+
+    def invalidate(self, key, **kw):
+        self.cache.pop(key, None)
+
+    def put(self, key, value, **kw):
+        self.cache[key] = value
+
+    def get_or_create(self, key, creation_function, **kw):
+        if key in self.cache:
+            return self.cache[key]
+        else:
+            self.cache[key] = value = creation_function()
+            return value
+
+
+class MockCacheImpl(CacheImpl):
+    realcacheimpl = None
+
+    def __init__(self, cache):
+        self.cache = cache
+
+    def set_backend(self, cache, backend):
+        if backend == 'simple':
+            self.realcacheimpl = SimpleBackend()
+        else:
+            self.realcacheimpl = cache._load_impl(backend)
+
+    def _setup_kwargs(self, kw):
+        self.kwargs = kw.copy()
+        self.kwargs.pop('regions', None)
+        self.kwargs.pop('manager', None)
+        if self.kwargs.get('region') != 'myregion':
+            self.kwargs.pop('region', None)
+
+    def get_or_create(self, key, creation_function, **kw):
+        self.key = key
+        self._setup_kwargs(kw)
+        return self.realcacheimpl.\
+            get_or_create(key, creation_function, **kw)
+
+    def put(self, key, value, **kw):
+        self.key = key
+        self._setup_kwargs(kw)
+        self.realcacheimpl.put(key, value, **kw)
+
+    def get(self, key, **kw):
+        self.key = key
+        self._setup_kwargs(kw)
+        return self.realcacheimpl.get(key, **kw)
+
+    def invalidate(self, key, **kw):
+        self.key = key
+        self._setup_kwargs(kw)
+        self.realcacheimpl.invalidate(key, **kw)
+
+
+register_plugin("mock", __name__, "MockCacheImpl")
+
+
+class CacheTest(TemplateTest):
+
+    real_backend = 'simple'
+
+    def _install_mock_cache(self, template, implname=None):
+        template.cache_impl = 'mock'
+        impl = template.cache.impl
+        impl.set_backend(template.cache, implname or self.real_backend)
+        return impl
+
+    def test_def(self):
+        t = Template("""
+        <%!
+            callcount = [0]
+        %>
+        <%def name="foo()" cached="True">
+            this is foo
+            <%
+            callcount[0] += 1
+            %>
+        </%def>
+
+        ${foo()}
+        ${foo()}
+        ${foo()}
+        callcount: ${callcount}
+""")
+        m = self._install_mock_cache(t)
+        assert result_lines(t.render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        assert m.kwargs == {}
+
+    def test_cache_enable(self):
+        t = Template("""
+            <%!
+                callcount = [0]
+            %>
+            <%def name="foo()" cached="True">
+                <% callcount[0] += 1 %>
+            </%def>
+            ${foo()}
+            ${foo()}
+            callcount: ${callcount}
+        """, cache_enabled=False)
+        self._install_mock_cache(t)
+
+        eq_(t.render().strip(), "callcount: [2]")
+
+    def test_nested_def(self):
+        t = Template("""
+        <%!
+            callcount = [0]
+        %>
+        <%def name="foo()">
+            <%def name="bar()" cached="True">
+                this is foo
+                <%
+                callcount[0] += 1
+                %>
+            </%def>
+            ${bar()}
+        </%def>
+
+        ${foo()}
+        ${foo()}
+        ${foo()}
+        callcount: ${callcount}
+""")
+        m = self._install_mock_cache(t)
+        assert result_lines(t.render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        assert m.kwargs == {}
+
+    def test_page(self):
+        t = Template("""
+        <%!
+            callcount = [0]
+        %>
+        <%page cached="True"/>
+        this is foo
+        <%
+        callcount[0] += 1
+        %>
+        callcount: ${callcount}
+""")
+        m = self._install_mock_cache(t)
+        t.render()
+        t.render()
+        assert result_lines(t.render()) == [
+            "this is foo",
+            "callcount: [1]"
+        ]
+        assert m.kwargs == {}
+
+    def test_dynamic_key_with_context(self):
+        t = Template("""
+            <%block name="foo" cached="True" cache_key="${mykey}">
+                some block
+            </%block>
+        """)
+        m = self._install_mock_cache(t)
+        t.render(mykey="thekey")
+        t.render(mykey="thekey")
+        eq_(
+            result_lines(t.render(mykey="thekey")),
+            ["some block"]
+        )
+        eq_(m.key, "thekey")
+
+        t = Template("""
+            <%def name="foo()" cached="True" cache_key="${mykey}">
+                some def
+            </%def>
+            ${foo()}
+        """)
+        m = self._install_mock_cache(t)
+        t.render(mykey="thekey")
+        t.render(mykey="thekey")
+        eq_(
+            result_lines(t.render(mykey="thekey")),
+            ["some def"]
+        )
+        eq_(m.key, "thekey")
+
+    def test_dynamic_key_with_funcargs(self):
+        t = Template("""
+            <%def name="foo(num=5)" cached="True" cache_key="foo_${str(num)}">
+             hi
+            </%def>
+
+            ${foo()}
+        """)
+        m = self._install_mock_cache(t)
+        t.render()
+        t.render()
+        assert result_lines(t.render()) == ['hi']
+        assert m.key == "foo_5"
+
+        t = Template("""
+            <%def name="foo(*args, **kwargs)" cached="True"
+             cache_key="foo_${kwargs['bar']}">
+             hi
+            </%def>
+
+            ${foo(1, 2, bar='lala')}
+        """)
+        m = self._install_mock_cache(t)
+        t.render()
+        assert result_lines(t.render()) == ['hi']
+        assert m.key == "foo_lala"
+
+        t = Template('''
+        <%page args="bar='hi'" cache_key="foo_${bar}" cached="True"/>
+         hi
+        ''')
+        m = self._install_mock_cache(t)
+        t.render()
+        assert result_lines(t.render()) == ['hi']
+        assert m.key == "foo_hi"
+
+    def test_dynamic_key_with_imports(self):
+        lookup = TemplateLookup()
+        lookup.put_string("foo.html", """
+        <%!
+            callcount = [0]
+        %>
+        <%namespace file="ns.html" import="*"/>
+        <%page cached="True" cache_key="${foo}"/>
+        this is foo
+        <%
+        callcount[0] += 1
+        %>
+        callcount: ${callcount}
+""")
+        lookup.put_string("ns.html", """""")
+        t = lookup.get_template("foo.html")
+        m = self._install_mock_cache(t)
+        t.render(foo='somekey')
+        t.render(foo='somekey')
+        assert result_lines(t.render(foo='somekey')) == [
+            "this is foo",
+            "callcount: [1]"
+        ]
+        assert m.kwargs == {}
+
+    def test_fileargs_implicit(self):
+        l = lookup.TemplateLookup(module_directory=module_base)
+        l.put_string("test", """
+                <%!
+                    callcount = [0]
+                %>
+                <%def name="foo()" cached="True" cache_type='dbm'>
+                    this is foo
+                    <%
+                    callcount[0] += 1
+                    %>
+                </%def>
+
+                ${foo()}
+                ${foo()}
+                ${foo()}
+                callcount: ${callcount}
+        """)
+
+        m = self._install_mock_cache(l.get_template('test'))
+        assert result_lines(l.get_template('test').render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        eq_(m.kwargs, {'type': 'dbm'})
+
+    def test_fileargs_deftag(self):
+        t = Template("""
+        <%%!
+            callcount = [0]
+        %%>
+        <%%def name="foo()" cached="True" cache_type='file' cache_dir='%s'>
+            this is foo
+            <%%
+            callcount[0] += 1
+            %%>
+        </%%def>
+
+        ${foo()}
+        ${foo()}
+        ${foo()}
+        callcount: ${callcount}
+""" % module_base)
+        m = self._install_mock_cache(t)
+        assert result_lines(t.render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        assert m.kwargs == {'type': 'file', 'dir': module_base}
+
+    def test_fileargs_pagetag(self):
+        t = Template("""
+        <%%page cache_dir='%s' cache_type='dbm'/>
+        <%%!
+            callcount = [0]
+        %%>
+        <%%def name="foo()" cached="True">
+            this is foo
+            <%%
+            callcount[0] += 1
+            %%>
+        </%%def>
+
+        ${foo()}
+        ${foo()}
+        ${foo()}
+        callcount: ${callcount}
+""" % module_base)
+        m = self._install_mock_cache(t)
+        assert result_lines(t.render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        eq_(m.kwargs, {'dir': module_base, 'type': 'dbm'})
+
+    def test_args_complete(self):
+        t = Template("""
+        <%%def name="foo()" cached="True" cache_timeout="30" cache_dir="%s"
+         cache_type="file" cache_key='somekey'>
+            this is foo
+        </%%def>
+
+        ${foo()}
+""" % module_base)
+        m = self._install_mock_cache(t)
+        t.render()
+        eq_(m.kwargs, {'dir': module_base, 'type': 'file', 'timeout': 30})
+
+        t2 = Template("""
+        <%%page cached="True" cache_timeout="30" cache_dir="%s"
+         cache_type="file" cache_key='somekey'/>
+        hi
+        """ % module_base)
+        m = self._install_mock_cache(t2)
+        t2.render()
+        eq_(m.kwargs, {'dir': module_base, 'type': 'file', 'timeout': 30})
+
+    def test_fileargs_lookup(self):
+        l = lookup.TemplateLookup(cache_dir=module_base, cache_type='file')
+        l.put_string("test", """
+                <%!
+                    callcount = [0]
+                %>
+                <%def name="foo()" cached="True">
+                    this is foo
+                    <%
+                    callcount[0] += 1
+                    %>
+                </%def>
+
+                ${foo()}
+                ${foo()}
+                ${foo()}
+                callcount: ${callcount}
+        """)
+
+        t = l.get_template('test')
+        m = self._install_mock_cache(t)
+        assert result_lines(l.get_template('test').render()) == [
+            'this is foo',
+            'this is foo',
+            'this is foo',
+            'callcount: [1]',
+        ]
+        eq_(m.kwargs, {'dir': module_base, 'type': 'file'})
+
+    def test_buffered(self):
+        t = Template("""
+        <%!
+            def a(text):
+                return "this is a " + text.strip()
+        %>
+        ${foo()}
+        ${foo()}
+        <%def name="foo()" cached="True" buffered="True">
+            this is a test
+        </%def>
+        """, buffer_filters=["a"])
+        self._install_mock_cache(t)
+        eq_(
+            result_lines(t.render()),
+            ["this is a this is a test", "this is a this is a test"]
+        )
+
+    def test_load_from_expired(self):
+        """test that the cache callable can be called safely after the
+        originating template has completed rendering.
+
+        """
+        t = Template("""
+        ${foo()}
+        <%def name="foo()" cached="True" cache_timeout="1">
+            foo
+        </%def>
+        """)
+        self._install_mock_cache(t)
+
+        x1 = t.render()
+        time.sleep(1.2)
+        x2 = t.render()
+        assert x1.strip() == x2.strip() == "foo"
+
+    def test_namespace_access(self):
+        t = Template("""
+            <%def name="foo(x)" cached="True">
+                foo: ${x}
+            </%def>
+
+            <%
+                foo(1)
+                foo(2)
+                local.cache.invalidate_def('foo')
+                foo(3)
+                foo(4)
+            %>
+        """)
+        self._install_mock_cache(t)
+        eq_(
+            result_lines(t.render()),
+            ['foo: 1', 'foo: 1', 'foo: 3', 'foo: 3']
+        )
+
+    def test_lookup(self):
+        l = TemplateLookup(cache_impl='mock')
+        l.put_string("x", """
+            <%page cached="True" />
+            ${y}
+        """)
+        t = l.get_template("x")
+        self._install_mock_cache(t)
+        assert result_lines(t.render(y=5)) == ["5"]
+        assert result_lines(t.render(y=7)) == ["5"]
+        assert isinstance(t.cache.impl, MockCacheImpl)
+
+    def test_invalidate(self):
+        t = Template("""
+            <%%def name="foo()" cached="True">
+                foo: ${x}
+            </%%def>
+
+            <%%def name="bar()" cached="True" cache_type='dbm' cache_dir='%s'>
+                bar: ${x}
+            </%%def>
+            ${foo()} ${bar()}
+        """ % module_base)
+        self._install_mock_cache(t)
+        assert result_lines(t.render(x=1)) == ["foo: 1", "bar: 1"]
+        assert result_lines(t.render(x=2)) == ["foo: 1", "bar: 1"]
+        t.cache.invalidate_def('foo')
+        assert result_lines(t.render(x=3)) == ["foo: 3", "bar: 1"]
+        t.cache.invalidate_def('bar')
+        assert result_lines(t.render(x=4)) == ["foo: 3", "bar: 4"]
+
+        t = Template("""
+            <%%page cached="True" cache_type="dbm" cache_dir="%s"/>
+
+            page: ${x}
+        """ % module_base)
+        self._install_mock_cache(t)
+        assert result_lines(t.render(x=1)) == ["page: 1"]
+        assert result_lines(t.render(x=2)) == ["page: 1"]
+        t.cache.invalidate_body()
+        assert result_lines(t.render(x=3)) == ["page: 3"]
+        assert result_lines(t.render(x=4)) == ["page: 3"]
+
+    def test_custom_args_def(self):
+        t = Template("""
+            <%def name="foo()" cached="True" cache_region="myregion"
+                    cache_timeout="50" cache_foo="foob">
+            </%def>
+            ${foo()}
+        """)
+        m = self._install_mock_cache(t, 'simple')
+        t.render()
+        eq_(
+            m.kwargs,
+            {'region': 'myregion',
+             'timeout': 50, 'foo': 'foob'})
+
+    def test_custom_args_block(self):
+        t = Template("""
+            <%block name="foo" cached="True" cache_region="myregion"
+                    cache_timeout="50" cache_foo="foob">
+            </%block>
+        """)
+        m = self._install_mock_cache(t, "simple")
+        t.render()
+        eq_(
+            m.kwargs,
+            {'region': 'myregion',
+             'timeout': 50, 'foo': 'foob'})
+
+    def test_custom_args_page(self):
+        t = Template("""
+            <%page cached="True" cache_region="myregion"
+                    cache_timeout="50" cache_foo="foob"/>
+        """)
+        m = self._install_mock_cache(t, "simple")
+        t.render()
+        eq_(
+            m.kwargs,
+            {'region': 'myregion',
+             'timeout': 50, 'foo': 'foob'})
+
+    def test_pass_context(self):
+        t = Template("""
+            <%page cached="True"/>
+        """)
+        m = self._install_mock_cache(t)
+        t.render()
+        assert 'context' not in m.kwargs
+
+        m.pass_context = True
+        t.render(x="bar")
+        assert 'context' in m.kwargs
+        assert m.kwargs['context'].get('x') == 'bar'
+
+
+class RealBackendTest(object):
+    def test_cache_uses_current_context(self):
+        t = Template("""
+        ${foo()}
+        <%def name="foo()" cached="True" cache_timeout="1">
+            foo: ${x}
+        </%def>
+        """)
+        self._install_mock_cache(t)
+
+        x1 = t.render(x=1)
+        time.sleep(1.2)
+        x2 = t.render(x=2)
+        eq_(x1.strip(), "foo: 1")
+        eq_(x2.strip(), "foo: 2")
+
+    def test_region(self):
+        t = Template(
+            """
+            <%block name="foo" cached="True" cache_region="short">
+                short term ${x}
+            </%block>
+            <%block name="bar" cached="True" cache_region="long">
+                long term ${x}
+            </%block>
+            <%block name="lala">
+                none ${x}
+            </%block>
+        """)
+
+        self._install_mock_cache(t)
+        r1 = result_lines(t.render(x=5))
+        time.sleep(1.2)
+        r2 = result_lines(t.render(x=6))
+        r3 = result_lines(t.render(x=7))
+        eq_(r1, ["short term 5", "long term 5", "none 5"])
+        eq_(r2, ["short term 6", "long term 5", "none 6"])
+        eq_(r3, ["short term 6", "long term 5", "none 7"])
+
+
+class BeakerCacheTest(RealBackendTest, CacheTest):
+    real_backend = 'beaker'
+
+    def setUp(self):
+        if not beaker_cache.has_beaker:
+            raise SkipTest("Beaker is required for these tests.")
+        if not py27:
+            raise SkipTest("newer beakers not working w/ py26")
+
+    def _install_mock_cache(self, template, implname=None):
+        template.cache_args['manager'] = self._regions()
+        impl = super(BeakerCacheTest, self)._install_mock_cache(
+            template, implname)
+        return impl
+
+    def _regions(self):
+        return beaker.cache.CacheManager(
+            cache_regions={
+                'short': {
+                    'expire': 1,
+                    'type': 'memory'
+                },
+                'long': {
+                    'expire': 60,
+                    'type': 'memory'
+                }
+            }
+        )
+
+
+class DogpileCacheTest(RealBackendTest, CacheTest):
+    real_backend = 'dogpile.cache'
+
+    def setUp(self):
+        try:
+            import dogpile.cache  # noqa
+        except ImportError:
+            raise SkipTest("dogpile.cache is required to run these tests")
+
+    def _install_mock_cache(self, template, implname=None):
+        template.cache_args['regions'] = self._regions()
+        template.cache_args.setdefault('region', 'short')
+        impl = super(DogpileCacheTest, self)._install_mock_cache(
+            template, implname)
+        return impl
+
+    def _regions(self):
+        from dogpile.cache import make_region
+
+        my_regions = {
+            "short": make_region().configure(
+                "dogpile.cache.memory",
+                expiration_time=1
+            ),
+            "long": make_region().configure(
+                "dogpile.cache.memory",
+                expiration_time=60
+            ),
+            "myregion": make_region().configure(
+                "dogpile.cache.memory",
+                expiration_time=60
+                )
+        }
+
+        return my_regions
diff --git a/test/test_call.py b/test/test_call.py
new file mode 100644 (file)
index 0000000..5071222
--- /dev/null
@@ -0,0 +1,514 @@
+from mako.template import Template
+from mako import util
+from test.util import result_lines, flatten_result
+from test import TemplateTest, eq_
+
+class CallTest(TemplateTest):
+    def test_call(self):
+        t = Template("""
+        <%def name="foo()">
+            hi im foo ${caller.body(y=5)}
+        </%def>
+
+        <%call expr="foo()" args="y, **kwargs">
+            this is the body, y is ${y}
+        </%call>
+""")
+        assert result_lines(t.render()) == ['hi im foo', 'this is the body, y is 5']
+
+
+    def test_compound_call(self):
+        t = Template("""
+
+        <%def name="bar()">
+            this is bar
+        </%def>
+
+        <%def name="comp1()">
+            this comp1 should not be called
+        </%def>
+
+        <%def name="foo()">
+            foo calling comp1: ${caller.comp1(x=5)}
+            foo calling body: ${caller.body()}
+        </%def>
+
+        <%call expr="foo()">
+            <%def name="comp1(x)">
+                this is comp1, ${x}
+            </%def>
+            this is the body, ${comp1(6)}
+        </%call>
+        ${bar()}
+
+""")
+        assert result_lines(t.render()) == ['foo calling comp1:', 'this is comp1, 5', 'foo calling body:', 'this is the body,', 'this is comp1, 6', 'this is bar']
+
+    def test_new_syntax(self):
+        """test foo:bar syntax, including multiline args and expression eval."""
+
+        # note the trailing whitespace in the bottom ${} expr, need to strip
+        # that off < python 2.7
+
+        t = Template("""
+            <%def name="foo(x, y, q, z)">
+                ${x}
+                ${y}
+                ${q}
+                ${",".join("%s->%s" % (a, b) for a, b in z)}
+            </%def>
+
+            <%self:foo x="this is x" y="${'some ' + 'y'}" q="
+                this
+                is
+                q"
+
+                z="${[
+                (1, 2),
+                (3, 4),
+                (5, 6)
+            ]
+
+            }"/>
+        """)
+
+        eq_(
+            result_lines(t.render()),
+             ['this is x', 'some y', 'this', 'is', 'q', '1->2,3->4,5->6']
+        )
+
+    def test_ccall_caller(self):
+        t = Template("""
+        <%def name="outer_func()">
+        OUTER BEGIN
+            <%call expr="caller.inner_func()">
+                INNER CALL
+            </%call>
+        OUTER END
+        </%def>
+
+        <%call expr="outer_func()">
+            <%def name="inner_func()">
+                INNER BEGIN
+                ${caller.body()}
+                INNER END
+            </%def>
+        </%call>
+
+        """)
+        #print t.code
+        assert result_lines(t.render()) == [
+            "OUTER BEGIN",
+            "INNER BEGIN",
+            "INNER CALL",
+            "INNER END",
+            "OUTER END",
+        ]
+
+    def test_stack_pop(self):
+        t = Template("""
+        <%def name="links()" buffered="True">
+           Some links
+        </%def>
+
+        <%def name="wrapper(links)">
+           <h1>${caller.body()}</h1>
+           ${links}
+        </%def>
+
+        ## links() pushes a stack frame on.  when complete,
+        ## 'nextcaller' must be restored
+        <%call expr="wrapper(links())">
+           Some title
+        </%call>
+
+        """)
+
+        assert result_lines(t.render()) == [
+        "<h1>",
+        "Some title",
+        "</h1>",
+        "Some links"
+        ]
+
+    def test_conditional_call(self):
+        """test that 'caller' is non-None only if the immediate <%def> was called via <%call>"""
+
+        t = Template("""
+        <%def name="a()">
+        % if caller:
+        ${ caller.body() } \\
+        % endif
+        AAA
+        ${ b() }
+        </%def>
+
+        <%def name="b()">
+        % if caller:
+        ${ caller.body() } \\
+        % endif
+        BBB
+        ${ c() }
+        </%def>
+
+        <%def name="c()">
+        % if caller:
+        ${ caller.body() } \\
+        % endif
+        CCC
+        </%def>
+
+        <%call expr="a()">
+        CALL
+        </%call>
+
+        """)
+        assert result_lines(t.render()) == [
+            "CALL",
+            "AAA",
+            "BBB",
+            "CCC"
+        ]
+
+    def test_chained_call(self):
+        """test %calls that are chained through their targets"""
+        t = Template("""
+            <%def name="a()">
+                this is a.
+                <%call expr="b()">
+                    this is a's ccall.  heres my body: ${caller.body()}
+                </%call>
+            </%def>
+            <%def name="b()">
+                this is b.  heres  my body: ${caller.body()}
+                whats in the body's caller's body ?
+                ${context.caller_stack[-2].body()}
+            </%def>
+
+            <%call expr="a()">
+                heres the main templ call
+            </%call>
+
+""")
+        assert result_lines(t.render()) == [
+            'this is a.',
+            'this is b. heres my body:',
+            "this is a's ccall. heres my body:",
+            'heres the main templ call',
+            "whats in the body's caller's body ?",
+            'heres the main templ call'
+        ]
+
+    def test_nested_call(self):
+        """test %calls that are nested inside each other"""
+        t = Template("""
+            <%def name="foo()">
+                ${caller.body(x=10)}
+            </%def>
+
+            x is ${x}
+            <%def name="bar()">
+                bar: ${caller.body()}
+            </%def>
+
+            <%call expr="foo()" args="x">
+                this is foo body: ${x}
+
+                <%call expr="bar()">
+                    this is bar body: ${x}
+                </%call>
+            </%call>
+""")
+        assert result_lines(t.render(x=5)) == [
+            "x is 5",
+            "this is foo body: 10",
+            "bar:",
+            "this is bar body: 10"
+        ]
+
+    def test_nested_call_2(self):
+        t = Template("""
+            x is ${x}
+            <%def name="foo()">
+                ${caller.foosub(x=10)}
+            </%def>
+
+            <%def name="bar()">
+                bar: ${caller.barsub()}
+            </%def>
+
+            <%call expr="foo()">
+                <%def name="foosub(x)">
+                this is foo body: ${x}
+
+                <%call expr="bar()">
+                    <%def name="barsub()">
+                    this is bar body: ${x}
+                    </%def>
+                </%call>
+
+                </%def>
+
+            </%call>
+""")
+        assert result_lines(t.render(x=5)) == [
+            "x is 5",
+            "this is foo body: 10",
+            "bar:",
+            "this is bar body: 10"
+        ]
+
+    def test_nested_call_3(self):
+        template = Template('''\
+        <%def name="A()">
+          ${caller.body()}
+        </%def>
+
+        <%def name="B()">
+          ${caller.foo()}
+        </%def>
+
+        <%call expr="A()">
+          <%call expr="B()">
+            <%def name="foo()">
+              foo
+            </%def>
+          </%call>
+        </%call>
+
+        ''')
+        assert flatten_result(template.render()) == "foo"
+
+    def test_nested_call_4(self):
+        base = """
+        <%def name="A()">
+        A_def
+        ${caller.body()}
+        </%def>
+
+        <%def name="B()">
+        B_def
+        ${caller.body()}
+        </%def>
+        """
+
+        template = Template(base + """
+        <%def name="C()">
+         C_def
+         <%self:B>
+           <%self:A>
+              A_body
+           </%self:A>
+            B_body
+           ${caller.body()}
+         </%self:B>
+        </%def>
+
+        <%self:C>
+        C_body
+        </%self:C>
+        """)
+
+        eq_(
+            flatten_result(template.render()),
+            "C_def B_def A_def A_body B_body C_body"
+        )
+
+        template = Template(base + """
+        <%def name="C()">
+         C_def
+         <%self:B>
+            B_body
+           ${caller.body()}
+           <%self:A>
+              A_body
+           </%self:A>
+         </%self:B>
+        </%def>
+
+        <%self:C>
+        C_body
+        </%self:C>
+        """)
+
+        eq_(
+            flatten_result(template.render()),
+            "C_def B_def B_body C_body A_def A_body"
+        )
+
+    def test_chained_call_in_nested(self):
+        t = Template("""
+            <%def name="embedded()">
+            <%def name="a()">
+                this is a.
+                <%call expr="b()">
+                    this is a's ccall.  heres my body: ${caller.body()}
+                </%call>
+            </%def>
+            <%def name="b()">
+                this is b.  heres  my body: ${caller.body()}
+                whats in the body's caller's body ? ${context.caller_stack[-2].body()}
+            </%def>
+
+            <%call expr="a()">
+                heres the main templ call
+            </%call>
+            </%def>
+            ${embedded()}
+""")
+        #print t.code
+        #print result_lines(t.render())
+        assert result_lines(t.render()) == [
+            'this is a.',
+            'this is b. heres my body:',
+            "this is a's ccall. heres my body:",
+            'heres the main templ call',
+            "whats in the body's caller's body ?",
+            'heres the main templ call'
+        ]
+
+    def test_call_in_nested(self):
+        t = Template("""
+            <%def name="a()">
+                this is a ${b()}
+                <%def name="b()">
+                    this is b
+                    <%call expr="c()">
+                        this is the body in b's call
+                    </%call>
+                </%def>
+                <%def name="c()">
+                    this is c: ${caller.body()}
+                </%def>
+            </%def>
+        ${a()}
+""")
+        assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call"]
+
+    def test_composed_def(self):
+        t = Template("""
+            <%def name="f()"><f>${caller.body()}</f></%def>
+            <%def name="g()"><g>${caller.body()}</g></%def>
+            <%def name="fg()">
+                <%self:f><%self:g>${caller.body()}</%self:g></%self:f>
+            </%def>
+            <%self:fg>fgbody</%self:fg>
+            """)
+        assert result_lines(t.render()) == ['<f><g>fgbody</g></f>']
+
+    def test_regular_defs(self):
+        t = Template("""
+        <%!
+            @runtime.supports_caller
+            def a(context):
+                context.write("this is a")
+                if context['caller']:
+                    context['caller'].body()
+                context.write("a is done")
+                return ''
+        %>
+
+        <%def name="b()">
+            this is b
+            our body: ${caller.body()}
+            ${a(context)}
+        </%def>
+        test 1
+        <%call expr="a(context)">
+            this is the body
+        </%call>
+        test 2
+        <%call expr="b()">
+            this is the body
+        </%call>
+        test 3
+        <%call expr="b()">
+            this is the body
+            <%call expr="b()">
+                this is the nested body
+            </%call>
+        </%call>
+
+
+        """)
+        assert result_lines(t.render()) == [
+            "test 1",
+            "this is a",
+            "this is the body",
+            "a is done",
+            "test 2",
+            "this is b",
+            "our body:",
+            "this is the body",
+            "this is aa is done",
+            "test 3",
+            "this is b",
+            "our body:",
+            "this is the body",
+            "this is b",
+            "our body:",
+            "this is the nested body",
+            "this is aa is done",
+            "this is aa is done"
+        ]
+
+    def test_call_in_nested_2(self):
+        t = Template("""
+            <%def name="a()">
+                <%def name="d()">
+                    not this d
+                </%def>
+                this is a ${b()}
+                <%def name="b()">
+                    <%def name="d()">
+                        not this d either
+                    </%def>
+                    this is b
+                    <%call expr="c()">
+                        <%def name="d()">
+                            this is d
+                        </%def>
+                        this is the body in b's call
+                    </%call>
+                </%def>
+                <%def name="c()">
+                    this is c: ${caller.body()}
+                    the embedded "d" is: ${caller.d()}
+                </%def>
+            </%def>
+        ${a()}
+""")
+        assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call", 'the embedded "d" is:', 'this is d']
+
+class SelfCacheTest(TemplateTest):
+    """this test uses a now non-public API."""
+
+    def test_basic(self):
+        t = Template("""
+        <%!
+            cached = None
+        %>
+        <%def name="foo()">
+            <%
+                global cached
+                if cached:
+                    return "cached: " + cached
+                __M_writer = context._push_writer()
+            %>
+            this is foo
+            <%
+                buf, __M_writer = context._pop_buffer_and_writer()
+                cached = buf.getvalue()
+                return cached
+            %>
+        </%def>
+
+        ${foo()}
+        ${foo()}
+""")
+        assert result_lines(t.render()) == [
+            "this is foo",
+            "cached:",
+            "this is foo"
+        ]
+
diff --git a/test/test_cmd.py b/test/test_cmd.py
new file mode 100644 (file)
index 0000000..a2adbf9
--- /dev/null
@@ -0,0 +1,72 @@
+from __future__ import with_statement
+from contextlib import contextmanager
+from test import TemplateTest, eq_, raises, template_base, mock
+import os
+from mako.cmd import cmdline
+
+class CmdTest(TemplateTest):
+    @contextmanager
+    def _capture_output_fixture(self, stream="stdout"):
+        with mock.patch("sys.%s" % stream) as stdout:
+            yield stdout
+
+    def test_stdin_success(self):
+        with self._capture_output_fixture() as stdout:
+            with mock.patch("sys.stdin", mock.Mock(
+                            read=mock.Mock(return_value="hello world ${x}"))):
+                cmdline(["--var", "x=5", "-"])
+
+        eq_(stdout.write.mock_calls[0][1][0], "hello world 5")
+
+    def test_stdin_syntax_err(self):
+        with mock.patch("sys.stdin", mock.Mock(
+                            read=mock.Mock(return_value="${x"))):
+            with self._capture_output_fixture("stderr") as stderr:
+                with raises(SystemExit):
+                    cmdline(["--var", "x=5", "-"])
+
+            assert "SyntaxException: Expected" in \
+                        stderr.write.mock_calls[0][1][0]
+            assert "Traceback" in stderr.write.mock_calls[0][1][0]
+
+
+    def test_stdin_rt_err(self):
+        with mock.patch("sys.stdin", mock.Mock(
+                            read=mock.Mock(return_value="${q}"))):
+            with self._capture_output_fixture("stderr") as stderr:
+                with raises(SystemExit):
+                    cmdline(["--var", "x=5", "-"])
+
+            assert "NameError: Undefined" in stderr.write.mock_calls[0][1][0]
+            assert "Traceback" in stderr.write.mock_calls[0][1][0]
+
+    def test_file_success(self):
+        with self._capture_output_fixture() as stdout:
+            cmdline(["--var", "x=5",
+                            os.path.join(template_base, "cmd_good.mako")])
+
+        eq_(stdout.write.mock_calls[0][1][0], "hello world 5")
+
+    def test_file_syntax_err(self):
+        with self._capture_output_fixture("stderr") as stderr:
+            with raises(SystemExit):
+                cmdline(["--var", "x=5",
+                            os.path.join(template_base, "cmd_syntax.mako")])
+
+        assert "SyntaxException: Expected" in stderr.write.mock_calls[0][1][0]
+        assert "Traceback" in stderr.write.mock_calls[0][1][0]
+
+    def test_file_rt_err(self):
+        with self._capture_output_fixture("stderr") as stderr:
+            with raises(SystemExit):
+                cmdline(["--var", "x=5",
+                            os.path.join(template_base, "cmd_runtime.mako")])
+
+        assert "NameError: Undefined" in stderr.write.mock_calls[0][1][0]
+        assert "Traceback" in stderr.write.mock_calls[0][1][0]
+
+
+    def test_file_notfound(self):
+        with raises(SystemExit, "error: can't find fake.lalala"):
+            cmdline(["--var", "x=5", "fake.lalala"])
+
diff --git a/test/test_decorators.py b/test/test_decorators.py
new file mode 100644 (file)
index 0000000..a3fa8f5
--- /dev/null
@@ -0,0 +1,110 @@
+from mako.template import Template
+from mako import lookup
+import unittest
+from test.util import flatten_result, result_lines
+
+class DecoratorTest(unittest.TestCase):
+    def test_toplevel(self):
+        template = Template("""
+            <%!
+                def bar(fn):
+                    def decorate(context, *args, **kw):
+                        return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR"
+                    return decorate
+            %>
+
+            <%def name="foo(y, x)" decorator="bar">
+                this is foo ${y} ${x}
+            </%def>
+
+            ${foo(1, x=5)}
+        """)
+
+        assert flatten_result(template.render()) == "BAR this is foo 1 5 BAR"
+
+    def test_toplevel_contextual(self):
+        template = Template("""
+            <%!
+                def bar(fn):
+                    def decorate(context):
+                        context.write("BAR")
+                        fn()
+                        context.write("BAR")
+                        return ''
+                    return decorate
+            %>
+
+            <%def name="foo()" decorator="bar">
+                this is foo
+            </%def>
+
+            ${foo()}
+        """)
+
+        assert flatten_result(template.render()) == "BAR this is foo BAR"
+
+        assert flatten_result(template.get_def('foo').render()) == "BAR this is foo BAR"
+
+
+    def test_nested(self):
+        template = Template("""
+            <%!
+                def bat(fn):
+                    def decorate(context):
+                        return "BAT" + runtime.capture(context, fn) + "BAT"
+                    return decorate
+            %>
+
+            <%def name="foo()">
+
+                <%def name="bar()" decorator="bat">
+                    this is bar
+                </%def>
+                ${bar()}
+            </%def>
+
+            ${foo()}
+        """)
+
+        assert flatten_result(template.render()) == "BAT this is bar BAT"
+
+    def test_toplevel_decorated_name(self):
+        template = Template("""
+            <%!
+                def bar(fn):
+                    def decorate(context, *args, **kw):
+                        return "function " + fn.__name__ + " " + runtime.capture(context, fn, *args, **kw)
+                    return decorate
+            %>
+
+            <%def name="foo(y, x)" decorator="bar">
+                this is foo ${y} ${x}
+            </%def>
+
+            ${foo(1, x=5)}
+        """)
+
+        assert flatten_result(template.render()) == "function foo this is foo 1 5"
+
+    def test_nested_decorated_name(self):
+        template = Template("""
+            <%!
+                def bat(fn):
+                    def decorate(context):
+                        return "function " + fn.__name__ + " " + runtime.capture(context, fn)
+                    return decorate
+            %>
+
+            <%def name="foo()">
+
+                <%def name="bar()" decorator="bat">
+                    this is bar
+                </%def>
+                ${bar()}
+            </%def>
+
+            ${foo()}
+        """)
+
+        assert flatten_result(template.render()) == "function bar this is bar"
+
diff --git a/test/test_def.py b/test/test_def.py
new file mode 100644 (file)
index 0000000..19142c8
--- /dev/null
@@ -0,0 +1,731 @@
+from mako.template import Template
+from mako import lookup
+from test import TemplateTest
+from test.util import flatten_result, result_lines
+from test import eq_, assert_raises, requires_python_3
+from mako import compat
+
+class DefTest(TemplateTest):
+    def test_def_noargs(self):
+        template = Template("""
+
+        ${mycomp()}
+
+        <%def name="mycomp()">
+            hello mycomp ${variable}
+        </%def>
+
+        """)
+        eq_(
+            template.render(variable='hi').strip(),
+            """hello mycomp hi"""
+        )
+
+    def test_def_blankargs(self):
+        template = Template("""
+        <%def name="mycomp()">
+            hello mycomp ${variable}
+        </%def>
+
+        ${mycomp()}""")
+        eq_(
+            template.render(variable='hi').strip(),
+            "hello mycomp hi"
+        )
+
+    def test_def_args(self):
+        template = Template("""
+        <%def name="mycomp(a, b)">
+            hello mycomp ${variable}, ${a}, ${b}
+        </%def>
+
+        ${mycomp(5, 6)}""")
+        eq_(
+            template.render(variable='hi', a=5, b=6).strip(),
+            """hello mycomp hi, 5, 6"""
+        )
+
+    @requires_python_3
+    def test_def_py3k_args(self):
+        template = Template("""
+        <%def name="kwonly(one, two, *three, four, five=5, **six)">
+            look at all these args: ${one} ${two} ${three[0]} ${four} ${five} ${six['seven']}
+        </%def>
+
+        ${kwonly('one', 'two', 'three', four='four', seven='seven')}""")
+        eq_(
+            template.render(one=1, two=2, three=(3,), six=6).strip(),
+            """look at all these args: one two three four 5 seven"""
+        )
+
+    def test_inter_def(self):
+        """test defs calling each other"""
+        template = Template("""
+        ${b()}
+
+        <%def name="a()">\
+        im a
+        </%def>
+
+        <%def name="b()">
+        im b
+        and heres a:  ${a()}
+        </%def>
+
+        <%def name="c()">
+        im c
+        </%def>
+""")
+        # check that "a" is declared in "b", but not in "c"
+        if compat.py3k:
+            assert "a" not in template.module.render_c.__code__.co_varnames
+            assert "a" in template.module.render_b.__code__.co_varnames
+        else:
+            assert "a" not in template.module.render_c.func_code.co_varnames
+            assert "a" in template.module.render_b.func_code.co_varnames
+
+        # then test output
+        eq_(
+            flatten_result(template.render()),
+            "im b and heres a: im a"
+        )
+
+    def test_toplevel(self):
+        """test calling a def from the top level"""
+
+        template = Template("""
+
+            this is the body
+
+            <%def name="a()">
+                this is a
+            </%def>
+
+            <%def name="b(x, y)">
+                this is b, ${x} ${y}
+            </%def>
+
+        """)
+
+        self._do_test(template.get_def("a"),
+                    "this is a",
+                    filters=flatten_result)
+        self._do_test(template.get_def("b"),
+                    "this is b, 10 15",
+                    template_args={'x': 10, 'y': 15},
+                    filters=flatten_result)
+        self._do_test(template.get_def("body"),
+                    "this is the body",
+                    filters=flatten_result)
+
+        # test that args outside of the dict can be used
+        self._do_test(template.get_def("a"), "this is a",
+                        filters=flatten_result,
+                        template_args={'q': 5, 'zq': 'test'})
+
+    def test_def_operations(self):
+        """test get/list/has def"""
+
+        template = Template("""
+
+            this is the body
+
+            <%def name="a()">
+                this is a
+            </%def>
+
+            <%def name="b(x, y)">
+                this is b, ${x} ${y}
+            </%def>
+
+        """)
+
+        assert template.get_def("a")
+        assert template.get_def("b")
+        assert_raises(AttributeError,
+                      template.get_def,
+                      ("c")
+                      )
+
+        assert template.has_def("a")
+        assert template.has_def("b")
+        assert not template.has_def("c")
+
+        defs = template.list_defs()
+        assert "a" in defs
+        assert "b" in defs
+        assert "body" in defs
+        assert "c" not in defs
+
+
+class ScopeTest(TemplateTest):
+    """test scoping rules.  The key is, enclosing
+    scope always takes precedence over contextual scope."""
+
+    def test_scope_one(self):
+        self._do_memory_test("""
+        <%def name="a()">
+            this is a, and y is ${y}
+        </%def>
+
+        ${a()}
+
+        <%
+            y = 7
+        %>
+
+        ${a()}
+
+""",
+            "this is a, and y is None this is a, and y is 7",
+            filters=flatten_result,
+            template_args={'y': None}
+        )
+
+    def test_scope_two(self):
+        t = Template("""
+        y is ${y}
+
+        <%
+            y = 7
+        %>
+
+        y is ${y}
+""")
+        try:
+            t.render(y=None)
+            assert False
+        except UnboundLocalError:
+            assert True
+
+    def test_scope_four(self):
+        """test that variables are pulled
+        from 'enclosing' scope before context."""
+        t = Template("""
+            <%
+                x = 5
+            %>
+            <%def name="a()">
+                this is a. x is ${x}.
+            </%def>
+
+            <%def name="b()">
+                <%
+                    x = 9
+                %>
+                this is b. x is ${x}.
+                calling a. ${a()}
+            </%def>
+
+            ${b()}
+""")
+        eq_(
+            flatten_result(t.render()),
+            "this is b. x is 9. calling a. this is a. x is 5."
+        )
+
+    def test_scope_five(self):
+        """test that variables are pulled from
+        'enclosing' scope before context."""
+        # same as test four, but adds a scope around it.
+        t = Template("""
+            <%def name="enclosing()">
+            <%
+                x = 5
+            %>
+            <%def name="a()">
+                this is a. x is ${x}.
+            </%def>
+
+            <%def name="b()">
+                <%
+                    x = 9
+                %>
+                this is b. x is ${x}.
+                calling a. ${a()}
+            </%def>
+
+            ${b()}
+            </%def>
+            ${enclosing()}
+""")
+        eq_(
+            flatten_result(t.render()),
+            "this is b. x is 9. calling a. this is a. x is 5."
+        )
+
+    def test_scope_six(self):
+        """test that the initial context counts
+        as 'enclosing' scope, for plain defs"""
+        t = Template("""
+
+        <%def name="a()">
+            a: x is ${x}
+        </%def>
+
+        <%def name="b()">
+            <%
+                x = 10
+            %>
+            b. x is ${x}.  ${a()}
+        </%def>
+
+        ${b()}
+    """)
+        eq_(
+            flatten_result(t.render(x=5)),
+            "b. x is 10. a: x is 5"
+        )
+
+    def test_scope_seven(self):
+        """test that the initial context counts
+        as 'enclosing' scope, for nested defs"""
+        t = Template("""
+        <%def name="enclosing()">
+            <%def name="a()">
+                a: x is ${x}
+            </%def>
+
+            <%def name="b()">
+                <%
+                    x = 10
+                %>
+                b. x is ${x}.  ${a()}
+            </%def>
+
+            ${b()}
+        </%def>
+        ${enclosing()}
+    """)
+        eq_(
+            flatten_result(t.render(x=5)),
+            "b. x is 10. a: x is 5"
+        )
+
+    def test_scope_eight(self):
+        """test that the initial context counts
+        as 'enclosing' scope, for nested defs"""
+        t = Template("""
+        <%def name="enclosing()">
+            <%def name="a()">
+                a: x is ${x}
+            </%def>
+
+            <%def name="b()">
+                <%
+                    x = 10
+                %>
+
+                b. x is ${x}.  ${a()}
+            </%def>
+
+            ${b()}
+        </%def>
+        ${enclosing()}
+    """)
+        eq_(
+            flatten_result(t.render(x=5)),
+            "b. x is 10. a: x is 5"
+        )
+
+    def test_scope_nine(self):
+        """test that 'enclosing scope' doesnt
+        get exported to other templates"""
+
+        l = lookup.TemplateLookup()
+        l.put_string('main', """
+        <%
+            x = 5
+        %>
+        this is main.  <%include file="secondary"/>
+""")
+
+        l.put_string('secondary', """
+        this is secondary.  x is ${x}
+""")
+
+        eq_(
+            flatten_result(l.get_template('main').render(x=2)),
+            "this is main. this is secondary. x is 2"
+        )
+
+    def test_scope_ten(self):
+        t = Template("""
+            <%def name="a()">
+                <%def name="b()">
+                    <%
+                        y = 19
+                    %>
+                    b/c: ${c()}
+                    b/y: ${y}
+                </%def>
+                <%def name="c()">
+                    c/y: ${y}
+                </%def>
+
+                <%
+                    # we assign to "y".  but the 'enclosing
+                    # scope' of "b" and "c" is from
+                    # the "y" on the outside
+                    y = 10
+                %>
+                a/y: ${y}
+                a/b: ${b()}
+            </%def>
+
+            <%
+                y = 7
+            %>
+            main/a: ${a()}
+            main/y: ${y}
+    """)
+        eq_(
+            flatten_result(t.render()),
+            "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7"
+        )
+
+    def test_scope_eleven(self):
+        t = Template("""
+            x is ${x}
+            <%def name="a(x)">
+                this is a, ${b()}
+                <%def name="b()">
+                    this is b, x is ${x}
+                </%def>
+            </%def>
+
+            ${a(x=5)}
+""")
+        eq_(
+            result_lines(t.render(x=10)),
+        [
+            "x is 10",
+            "this is a,",
+            "this is b, x is 5"
+        ])
+
+    def test_unbound_scope(self):
+        t = Template("""
+            <%
+                y = 10
+            %>
+            <%def name="a()">
+                y is: ${y}
+                <%
+                    # should raise error ?
+                    y = 15
+                %>
+                y is ${y}
+            </%def>
+            ${a()}
+""")
+        assert_raises(
+            UnboundLocalError,
+            t.render
+            )
+
+    def test_unbound_scope_two(self):
+        t = Template("""
+            <%def name="enclosing()">
+            <%
+                y = 10
+            %>
+            <%def name="a()">
+                y is: ${y}
+                <%
+                    # should raise error ?
+                    y = 15
+                %>
+                y is ${y}
+            </%def>
+            ${a()}
+            </%def>
+            ${enclosing()}
+""")
+        try:
+            print(t.render())
+            assert False
+        except UnboundLocalError:
+            assert True
+
+    def test_canget_kwargs(self):
+        """test that arguments passed to the body()
+        function are accessible by top-level defs"""
+        l = lookup.TemplateLookup()
+        l.put_string("base", """
+
+        ${next.body(x=12)}
+
+        """)
+
+        l.put_string("main", """
+            <%inherit file="base"/>
+            <%page args="x"/>
+            this is main.  x is ${x}
+
+            ${a()}
+
+            <%def name="a(**args)">
+                this is a, x is ${x}
+            </%def>
+        """)
+
+        # test via inheritance
+        eq_(
+            result_lines(l.get_template("main").render()),
+            [
+            "this is main. x is 12",
+            "this is a, x is 12"
+        ])
+
+        l.put_string("another", """
+            <%namespace name="ns" file="main"/>
+
+            ${ns.body(x=15)}
+        """)
+        # test via namespace
+        eq_(
+            result_lines(l.get_template("another").render()),
+        [
+            "this is main. x is 15",
+            "this is a, x is 15"
+        ])
+
+    def test_inline_expression_from_arg_one(self):
+        """test that cache_key=${foo} gets its value from
+        the 'foo' argument in the <%def> tag,
+        and strict_undefined doesn't complain.
+
+        this is #191.
+
+        """
+        t = Template("""
+        <%def name="layout(foo)" cached="True" cache_key="${foo}">
+        foo: ${foo}
+        </%def>
+
+        ${layout(3)}
+        """, strict_undefined=True,
+            cache_impl="plain")
+
+        eq_(
+            result_lines(t.render()),
+            ["foo: 3"]
+        )
+
+    def test_interpret_expression_from_arg_two(self):
+        """test that cache_key=${foo} gets its value from
+        the 'foo' argument regardless of it being passed
+        from the context.
+
+        This is here testing that there's no change
+        to existing behavior before and after #191.
+
+        """
+        t = Template("""
+        <%def name="layout(foo)" cached="True" cache_key="${foo}">
+        foo: ${value}
+        </%def>
+
+        ${layout(3)}
+        """, cache_impl="plain")
+
+        eq_(
+            result_lines(t.render(foo='foo', value=1)),
+            ["foo: 1"]
+        )
+        eq_(
+            result_lines(t.render(foo='bar', value=2)),
+            ["foo: 1"]
+        )
+
+class NestedDefTest(TemplateTest):
+    def test_nested_def(self):
+        t = Template("""
+
+        ${hi()}
+
+        <%def name="hi()">
+            hey, im hi.
+            and heres ${foo()}, ${bar()}
+
+            <%def name="foo()">
+                this is foo
+            </%def>
+
+            <%def name="bar()">
+                this is bar
+            </%def>
+        </%def>
+""")
+        eq_(
+            flatten_result(t.render()),
+            "hey, im hi. and heres this is foo , this is bar"
+        )
+
+    def test_nested_2(self):
+        t = Template("""
+            x is ${x}
+            <%def name="a()">
+                this is a, x is ${x}
+                ${b()}
+                <%def name="b()">
+                    this is b: ${x}
+                </%def>
+            </%def>
+            ${a()}
+""")
+
+        eq_(
+            flatten_result(t.render(x=10)),
+            "x is 10 this is a, x is 10 this is b: 10"
+        )
+
+    def test_nested_with_args(self):
+        t = Template("""
+        ${a()}
+        <%def name="a()">
+            <%def name="b(x, y=2)">
+                b x is ${x} y is ${y}
+            </%def>
+            a ${b(5)}
+        </%def>
+""")
+        eq_(
+            flatten_result(t.render()),
+            "a b x is 5 y is 2"
+        )
+
+    def test_nested_def_2(self):
+        template = Template("""
+        ${a()}
+        <%def name="a()">
+            <%def name="b()">
+                <%def name="c()">
+                    comp c
+                </%def>
+                ${c()}
+            </%def>
+            ${b()}
+        </%def>
+""")
+        eq_(
+            flatten_result(template.render()),
+            "comp c"
+        )
+
+    def test_nested_nested_def(self):
+        t = Template("""
+
+        ${a()}
+        <%def name="a()">
+            a
+            <%def name="b1()">
+                a_b1
+            </%def>
+            <%def name="b2()">
+                a_b2 ${c1()}
+                <%def name="c1()">
+                    a_b2_c1
+                </%def>
+            </%def>
+            <%def name="b3()">
+                a_b3 ${c1()}
+                <%def name="c1()">
+                    a_b3_c1 heres x: ${x}
+                    <%
+                        y = 7
+                    %>
+                    y is ${y}
+                </%def>
+                <%def name="c2()">
+                    a_b3_c2
+                    y is ${y}
+                    c1 is ${c1()}
+                </%def>
+                ${c2()}
+            </%def>
+
+            ${b1()} ${b2()}  ${b3()}
+        </%def>
+""")
+        eq_(
+            flatten_result(t.render(x=5, y=None)),
+            "a a_b1 a_b2 a_b2_c1 a_b3 a_b3_c1 "
+            "heres x: 5 y is 7 a_b3_c2 y is "
+            "None c1 is a_b3_c1 heres x: 5 y is 7"
+        )
+
+    def test_nested_nested_def_2(self):
+        t = Template("""
+        <%def name="a()">
+            this is a ${b()}
+            <%def name="b()">
+                this is b
+                ${c()}
+            </%def>
+
+            <%def name="c()">
+                this is c
+            </%def>
+        </%def>
+        ${a()}
+""")
+        eq_(
+            flatten_result(t.render()),
+            "this is a this is b this is c"
+        )
+
+    def test_outer_scope(self):
+        t = Template("""
+        <%def name="a()">
+            a: x is ${x}
+        </%def>
+
+        <%def name="b()">
+            <%def name="c()">
+            <%
+                x = 10
+            %>
+            c. x is ${x}.  ${a()}
+            </%def>
+
+            b. ${c()}
+        </%def>
+
+        ${b()}
+
+        x is ${x}
+""")
+        eq_(
+            flatten_result(t.render(x=5)),
+            "b. c. x is 10. a: x is 5 x is 5"
+        )
+
+class ExceptionTest(TemplateTest):
+    def test_raise(self):
+        template = Template("""
+            <%
+                raise Exception("this is a test")
+            %>
+    """, format_exceptions=False)
+        assert_raises(
+            Exception,
+            template.render
+            )
+
+    def test_handler(self):
+        def handle(context, error):
+            context.write("error message is " + str(error))
+            return True
+
+        template = Template("""
+            <%
+                raise Exception("this is a test")
+            %>
+    """, error_handler=handle)
+        eq_(
+            template.render().strip(),
+            "error message is this is a test"
+        )
+
diff --git a/test/test_exceptions.py b/test/test_exceptions.py
new file mode 100644 (file)
index 0000000..8321b25
--- /dev/null
@@ -0,0 +1,289 @@
+# -*- coding: utf-8 -*-
+import sys
+
+from mako import exceptions, compat
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako.compat import u
+from test.util import result_lines
+from test import TemplateTest
+from test import requires_pygments_14, requires_no_pygments_exceptions
+
+class ExceptionsTest(TemplateTest):
+    def test_html_error_template(self):
+        """test the html_error_template"""
+        code = """
+% i = 0
+"""
+        try:
+            template = Template(code)
+            template.render_unicode()
+            assert False
+        except exceptions.CompileException:
+            html_error = exceptions.html_error_template().render_unicode()
+            assert ("CompileException: Fragment &#39;i = 0&#39; is not "
+                    "a partial control statement at line: 2 char: 1") in html_error
+            assert '<style>' in html_error
+            html_error_stripped = html_error.strip()
+            assert html_error_stripped.startswith('<html>')
+            assert html_error_stripped.endswith('</html>')
+
+            not_full = exceptions.html_error_template().\
+                                    render_unicode(full=False)
+            assert '<html>' not in not_full
+            assert '<style>' in not_full
+
+            no_css = exceptions.html_error_template().\
+                                    render_unicode(css=False)
+            assert '<style>' not in no_css
+        else:
+            assert False, ("This function should trigger a CompileException, "
+                           "but didn't")
+
+    def test_text_error_template(self):
+        code = """
+% i = 0
+"""
+        try:
+            template = Template(code)
+            template.render_unicode()
+            assert False
+        except exceptions.CompileException:
+            text_error = exceptions.text_error_template().render_unicode()
+            assert 'Traceback (most recent call last):' in text_error
+            assert ("CompileException: Fragment 'i = 0' is not a partial "
+                    "control statement") in text_error
+
+    @requires_pygments_14
+    def test_utf8_html_error_template_pygments(self):
+        """test the html_error_template with a Template containing UTF-8
+        chars"""
+
+        if compat.py3k:
+            code = """# -*- coding: utf-8 -*-
+% if 2 == 2: /an error
+${'привет'}
+% endif
+"""
+        else:
+            code = """# -*- coding: utf-8 -*-
+% if 2 == 2: /an error
+${u'привет'}
+% endif
+"""
+        try:
+            template = Template(code)
+            template.render_unicode()
+        except exceptions.CompileException:
+            html_error = exceptions.html_error_template().render()
+            if compat.py3k:
+                assert ("CompileException: Fragment &#39;if 2 == 2: /an "
+                    "error&#39; is not a partial control statement "
+                    "at line: 2 char: 1").encode(sys.getdefaultencoding(), 'htmlentityreplace') in \
+                    html_error
+            else:
+                assert ("CompileException: Fragment &#39;if 2 == 2: /an "
+                        "error&#39; is not a partial control statement "
+                        "at line: 2 char: 1") in \
+                        html_error
+
+            if compat.py3k:
+                assert "".encode(sys.getdefaultencoding(),
+                                        'htmlentityreplace') in html_error
+            else:
+                assert 'u&#39;'\
+                        '&#x43F;&#x440;&#x438;&#x432;&#x435;&#x442;'\
+                        '&#39;</span><span class="cp">}</span>'.encode(
+                                sys.getdefaultencoding(),
+                                'htmlentityreplace') in html_error
+        else:
+            assert False, ("This function should trigger a CompileException, "
+                           "but didn't")
+
+    @requires_no_pygments_exceptions
+    def test_utf8_html_error_template_no_pygments(self):
+        """test the html_error_template with a Template containing UTF-8
+        chars"""
+
+        if compat.py3k:
+            code = """# -*- coding: utf-8 -*-
+% if 2 == 2: /an error
+${'привет'}
+% endif
+"""
+        else:
+            code = """# -*- coding: utf-8 -*-
+% if 2 == 2: /an error
+${u'привет'}
+% endif
+"""
+        try:
+            template = Template(code)
+            template.render_unicode()
+        except exceptions.CompileException:
+            html_error = exceptions.html_error_template().render()
+            if compat.py3k:
+                assert ("CompileException: Fragment &#39;if 2 == 2: /an "
+                    "error&#39; is not a partial control statement "
+                    "at line: 2 char: 1").encode(sys.getdefaultencoding(),
+                            'htmlentityreplace') in \
+                    html_error
+            else:
+                assert ("CompileException: Fragment &#39;if 2 == 2: /an "
+                        "error&#39; is not a partial control statement "
+                        "at line: 2 char: 1") in \
+                        html_error
+
+            if compat.py3k:
+                assert "${&#39;привет&#39;}".encode(sys.getdefaultencoding(),
+                                 'htmlentityreplace') in html_error
+            else:
+                assert u("${u&#39;привет&#39;}").encode(sys.getdefaultencoding(),
+                                    'htmlentityreplace') in html_error
+        else:
+            assert False, ("This function should trigger a CompileException, "
+                           "but didn't")
+
+    def test_format_closures(self):
+        try:
+            exec("def foo():"\
+                 "    raise RuntimeError('test')", locals())
+            foo()
+        except:
+            html_error = exceptions.html_error_template().render()
+            assert "RuntimeError: test" in str(html_error)
+
+    def test_py_utf8_html_error_template(self):
+        try:
+            foo = u('日本')
+            raise RuntimeError('test')
+        except:
+            html_error = exceptions.html_error_template().render()
+            if compat.py3k:
+                assert 'RuntimeError: test' in html_error.decode('utf-8')
+                assert "foo = u(&#39;日本&#39;)" in html_error.decode('utf-8')
+            else:
+                assert 'RuntimeError: test' in html_error
+                assert "foo = u(&#39;&#x65E5;&#x672C;&#39;)" in html_error
+
+    def test_py_unicode_error_html_error_template(self):
+        try:
+            raise RuntimeError(u('日本'))
+        except:
+            html_error = exceptions.html_error_template().render()
+            assert u("RuntimeError: 日本").encode('ascii', 'ignore') in html_error
+
+    @requires_pygments_14
+    def test_format_exceptions_pygments(self):
+        l = TemplateLookup(format_exceptions=True)
+
+        l.put_string("foo.html", """
+<%inherit file="base.html"/>
+${foobar}
+        """)
+
+        l.put_string("base.html", """
+        ${self.body()}
+        """)
+
+        assert '<div class="sourceline"><table class="syntax-highlightedtable">' in \
+            l.get_template("foo.html").render_unicode()
+
+    @requires_no_pygments_exceptions
+    def test_format_exceptions_no_pygments(self):
+        l = TemplateLookup(format_exceptions=True)
+
+        l.put_string("foo.html", """
+<%inherit file="base.html"/>
+${foobar}
+        """)
+
+        l.put_string("base.html", """
+        ${self.body()}
+        """)
+
+        assert '<div class="sourceline">${foobar}</div>' in \
+            result_lines(l.get_template("foo.html").render_unicode())
+
+    @requires_pygments_14
+    def test_utf8_format_exceptions_pygments(self):
+        """test that htmlentityreplace formatting is applied to
+           exceptions reported with format_exceptions=True"""
+
+        l = TemplateLookup(format_exceptions=True)
+        if compat.py3k:
+            l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""")
+        else:
+            l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""")
+
+        if compat.py3k:
+            assert '&#39;привет&#39;</span>' in \
+                l.get_template("foo.html").render().decode('utf-8')
+        else:
+            assert 'u&#39;&#x43F;&#x440;&#x438;&#x432;'\
+                    '&#x435;&#x442;&#39;</span>' in \
+                l.get_template("foo.html").render().decode('utf-8')
+
+    @requires_no_pygments_exceptions
+    def test_utf8_format_exceptions_no_pygments(self):
+        """test that htmlentityreplace formatting is applied to
+           exceptions reported with format_exceptions=True"""
+
+        l = TemplateLookup(format_exceptions=True)
+        if compat.py3k:
+            l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""")
+        else:
+            l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""")
+
+        if compat.py3k:
+            assert '<div class="sourceline">${&#39;привет&#39; + foobar}</div>'\
+                in result_lines(l.get_template("foo.html").render().decode('utf-8'))
+        else:
+            assert '${u&#39;&#x43F;&#x440;&#x438;&#x432;&#x435;'\
+                   '&#x442;&#39; + foobar}' in \
+                result_lines(l.get_template("foo.html").render().decode('utf-8'))
+
+
+    def test_custom_tback(self):
+        try:
+            raise RuntimeError("error 1")
+            foo('bar')
+        except:
+            t, v, tback = sys.exc_info()
+
+        try:
+            raise RuntimeError("error 2")
+        except:
+            html_error = exceptions.html_error_template().\
+                        render_unicode(error=v, traceback=tback)
+
+        # obfuscate the text so that this text
+        # isn't in the 'wrong' exception
+        assert "".join(reversed(");93#&rab;93#&(oof")) in html_error
+
+    def test_tback_no_trace_from_py_file(self):
+        try:
+            t = self._file_template("runtimeerr.html")
+            t.render()
+        except:
+            t, v, tback = sys.exc_info()
+
+        if not compat.py3k:
+            # blow away tracebaack info
+            sys.exc_clear()
+
+        # and don't even send what we have.
+        html_error = exceptions.html_error_template().\
+                    render_unicode(error=v, traceback=None)
+        assert "local variable &#39;y&#39; referenced before assignment" in html_error
+
+    def test_tback_trace_from_py_file(self):
+        t = self._file_template("runtimeerr.html")
+        try:
+            t.render()
+            assert False
+        except:
+            html_error = exceptions.html_error_template().\
+                        render_unicode()
+
+        assert "local variable &#39;y&#39; referenced before assignment" in html_error
diff --git a/test/test_filters.py b/test/test_filters.py
new file mode 100644 (file)
index 0000000..64f36f6
--- /dev/null
@@ -0,0 +1,390 @@
+# -*- coding: utf-8 -*-
+
+from mako.template import Template
+import unittest
+from test import TemplateTest, eq_, requires_python_2
+from test.util import result_lines, flatten_result
+from mako.compat import u
+from mako import compat
+
+class FilterTest(TemplateTest):
+    def test_basic(self):
+        t = Template("""
+        ${x | myfilter}
+""")
+        assert flatten_result(t.render(x="this is x", myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)) == "MYFILTER->this is x<-MYFILTER"
+
+    def test_expr(self):
+        """test filters that are themselves expressions"""
+        t = Template("""
+        ${x | myfilter(y)}
+""")
+        def myfilter(y):
+            return lambda x: "MYFILTER->%s<-%s" % (x, y)
+        assert flatten_result(t.render(x="this is x", myfilter=myfilter, y="this is y")) == "MYFILTER->this is x<-this is y"
+
+    def test_convert_str(self):
+        """test that string conversion happens in expressions before sending to filters"""
+        t = Template("""
+            ${x | trim}
+        """)
+        assert flatten_result(t.render(x=5)) == "5"
+
+    def test_quoting(self):
+        t = Template("""
+            foo ${bar | h}
+        """)
+
+        eq_(
+            flatten_result(t.render(bar="<'some bar'>")),
+            "foo &lt;&#39;some bar&#39;&gt;"
+        )
+
+    def test_url_escaping(self):
+        t = Template("""
+            http://example.com/?bar=${bar | u}&v=1
+        """)
+
+        eq_(
+            flatten_result(t.render(bar=u"酒吧bar")),
+            "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1"
+        )
+
+    def test_entity(self):
+        t = Template("foo ${bar | entity}")
+        eq_(
+            flatten_result(t.render(bar="<'some bar'>")),
+            "foo &lt;'some bar'&gt;"
+        )
+
+    @requires_python_2
+    def test_quoting_non_unicode(self):
+        t = Template("""
+            foo ${bar | h}
+        """, disable_unicode=True,
+        output_encoding=None)
+
+        eq_(
+            flatten_result(t.render(bar="<'привет'>")),
+            "foo &lt;&#39;привет&#39;&gt;"
+        )
+
+    @requires_python_2
+    def test_url_escaping_non_unicode(self):
+        t = Template("""
+            http://example.com/?bar=${bar | u}&v=1
+        """, disable_unicode=True,
+        output_encoding=None)
+
+        eq_(
+            flatten_result(t.render(bar="酒吧bar")),
+            "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1"
+        )
+
+
+    def test_def(self):
+        t = Template("""
+            <%def name="foo()" filter="myfilter">
+                this is foo
+            </%def>
+            ${foo()}
+""")
+
+        eq_(
+            flatten_result(t.render(x="this is x",
+                        myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)),
+            "MYFILTER-> this is foo <-MYFILTER"
+        )
+
+    def test_import(self):
+        t = Template("""
+        <%!
+            from mako import filters
+        %>\
+        trim this string: ${"  some string to trim   " | filters.trim} continue\
+        """)
+
+        assert t.render().strip()=="trim this string: some string to trim continue"
+
+    def test_import_2(self):
+        t = Template("""
+        trim this string: ${"  some string to trim   " | filters.trim} continue\
+        """, imports=["from mako import filters"])
+        #print t.code
+        assert t.render().strip()=="trim this string: some string to trim continue"
+
+    def test_encode_filter(self):
+        t = Template("""# coding: utf-8
+            some stuff.... ${x}
+        """, default_filters=['decode.utf8'])
+        eq_(
+            t.render_unicode(x=u("voix m’a réveillé")).strip(),
+            u("some stuff.... voix m’a réveillé")
+        )
+
+    def test_encode_filter_non_str(self):
+        t = Template("""# coding: utf-8
+            some stuff.... ${x}
+        """, default_filters=['decode.utf8'])
+        eq_(
+            t.render_unicode(x=3).strip(),
+            u("some stuff.... 3")
+        )
+
+    @requires_python_2
+    def test_encode_filter_non_str_we_return_bytes(self):
+        class Foo(object):
+            def __str__(self):
+                return compat.b("å")
+        t = Template("""# coding: utf-8
+            some stuff.... ${x}
+        """, default_filters=['decode.utf8'])
+        eq_(
+            t.render_unicode(x=Foo()).strip(),
+            u("some stuff.... å")
+        )
+
+    def test_custom_default(self):
+        t = Template("""
+        <%!
+            def myfilter(x):
+                return "->" + x + "<-"
+        %>
+
+            hi ${'there'}
+        """, default_filters=['myfilter'])
+        assert t.render().strip()=="hi ->there<-"
+
+    def test_global(self):
+        t = Template("""
+            <%page expression_filter="h"/>
+            ${"<tag>this is html</tag>"}
+        """)
+        assert t.render().strip()  == "&lt;tag&gt;this is html&lt;/tag&gt;"
+
+    def test_block_via_context(self):
+        t = Template("""
+            <%block name="foo" filter="myfilter">
+                some text
+            </%block>
+        """)
+        def myfilter(text):
+            return "MYTEXT" + text
+        eq_(
+            result_lines(t.render(myfilter=myfilter)),
+            ["MYTEXT", "some text"]
+        )
+
+    def test_def_via_context(self):
+        t = Template("""
+            <%def name="foo()" filter="myfilter">
+                some text
+            </%def>
+            ${foo()}
+        """)
+        def myfilter(text):
+            return "MYTEXT" + text
+        eq_(
+            result_lines(t.render(myfilter=myfilter)),
+            ["MYTEXT", "some text"]
+        )
+
+    def test_text_via_context(self):
+        t = Template("""
+            <%text filter="myfilter">
+                some text
+            </%text>
+        """)
+        def myfilter(text):
+            return "MYTEXT" + text
+        eq_(
+            result_lines(t.render(myfilter=myfilter)),
+            ["MYTEXT", "some text"]
+        )
+
+
+    def test_nflag(self):
+        t = Template("""
+            ${"<tag>this is html</tag>" | n}
+        """, default_filters=['h', 'unicode'])
+        assert t.render().strip()  == "<tag>this is html</tag>"
+
+        t = Template("""
+            <%page expression_filter="h"/>
+            ${"<tag>this is html</tag>" | n}
+        """)
+        assert t.render().strip()  == "<tag>this is html</tag>"
+
+        t = Template("""
+            <%page expression_filter="h"/>
+            ${"<tag>this is html</tag>" | n, h}
+        """)
+        assert t.render().strip()  == "&lt;tag&gt;this is html&lt;/tag&gt;"
+
+    def test_non_expression(self):
+        t = Template("""
+        <%!
+            def a(text):
+                return "this is a"
+            def b(text):
+                return "this is b"
+        %>
+
+        ${foo()}
+        <%def name="foo()" buffered="True">
+            this is text
+        </%def>
+        """, buffer_filters=['a'])
+        assert t.render().strip() == "this is a"
+
+        t = Template("""
+        <%!
+            def a(text):
+                return "this is a"
+            def b(text):
+                return "this is b"
+        %>
+
+        ${'hi'}
+        ${foo()}
+        <%def name="foo()" buffered="True">
+            this is text
+        </%def>
+        """, buffer_filters=['a'], default_filters=['b'])
+        assert flatten_result(t.render()) == "this is b this is b"
+
+        t = Template("""
+        <%!
+            class Foo(object):
+                foo = True
+                def __str__(self):
+                    return "this is a"
+            def a(text):
+                return Foo()
+            def b(text):
+                if hasattr(text, 'foo'):
+                    return str(text)
+                else:
+                    return "this is b"
+        %>
+
+        ${'hi'}
+        ${foo()}
+        <%def name="foo()" buffered="True">
+            this is text
+        </%def>
+        """, buffer_filters=['a'], default_filters=['b'])
+        assert flatten_result(t.render()) == "this is b this is a"
+
+        t = Template("""
+        <%!
+            def a(text):
+                return "this is a"
+            def b(text):
+                return "this is b"
+        %>
+
+        ${foo()}
+        ${bar()}
+        <%def name="foo()" filter="b">
+            this is text
+        </%def>
+        <%def name="bar()" filter="b" buffered="True">
+            this is text
+        </%def>
+        """, buffer_filters=['a'])
+        assert flatten_result(t.render()) == "this is b this is a"
+
+
+    def test_builtins(self):
+        t = Template("""
+            ${"this is <text>" | h}
+""")
+        assert flatten_result(t.render()) == "this is &lt;text&gt;"
+
+        t = Template("""
+            http://foo.com/arg1=${"hi! this is a string." | u}
+""")
+        assert flatten_result(t.render()) == "http://foo.com/arg1=hi%21+this+is+a+string."
+
+class BufferTest(unittest.TestCase):
+    def test_buffered_def(self):
+        t = Template("""
+            <%def name="foo()" buffered="True">
+                this is foo
+            </%def>
+            ${"hi->" + foo() + "<-hi"}
+""")
+        assert flatten_result(t.render()) == "hi-> this is foo <-hi"
+
+    def test_unbuffered_def(self):
+        t = Template("""
+            <%def name="foo()" buffered="False">
+                this is foo
+            </%def>
+            ${"hi->" + foo() + "<-hi"}
+""")
+        assert flatten_result(t.render()) == "this is foo hi-><-hi"
+
+    def test_capture(self):
+        t = Template("""
+            <%def name="foo()" buffered="False">
+                this is foo
+            </%def>
+            ${"hi->" + capture(foo) + "<-hi"}
+""")
+        assert flatten_result(t.render()) == "hi-> this is foo <-hi"
+
+    def test_capture_exception(self):
+        template = Template("""
+            <%def name="a()">
+                this is a
+                <%
+                    raise TypeError("hi")
+                %>
+            </%def>
+            <%
+                c = capture(a)
+            %>
+            a->${c}<-a
+        """)
+        try:
+            template.render()
+            assert False
+        except TypeError:
+            assert True
+
+    def test_buffered_exception(self):
+        template = Template("""
+            <%def name="a()" buffered="True">
+                <%
+                    raise TypeError("hi")
+                %>
+            </%def>
+
+            ${a()}
+
+""")
+        try:
+            print(template.render())
+            assert False
+        except TypeError:
+            assert True
+
+    def test_capture_ccall(self):
+        t = Template("""
+            <%def name="foo()">
+                <%
+                    x = capture(caller.body)
+                %>
+                this is foo.  body: ${x}
+            </%def>
+
+            <%call expr="foo()">
+                ccall body
+            </%call>
+""")
+
+        #print t.render()
+        assert flatten_result(t.render()) == "this is foo. body: ccall body"
+
diff --git a/test/test_inheritance.py b/test/test_inheritance.py
new file mode 100644 (file)
index 0000000..08a46b3
--- /dev/null
@@ -0,0 +1,349 @@
+from mako import lookup, compat
+import unittest
+from test.util import result_lines
+
+class InheritanceTest(unittest.TestCase):
+    def test_basic(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main', """
+<%inherit file="base"/>
+
+<%def name="header()">
+    main header.
+</%def>
+
+this is the content.
+""")
+
+        collection.put_string('base', """
+This is base.
+
+header: ${self.header()}
+
+body: ${self.body()}
+
+footer: ${self.footer()}
+
+<%def name="footer()">
+    this is the footer. header again ${next.header()}
+</%def>
+""")
+
+        assert result_lines(collection.get_template('main').render()) == [
+            'This is base.',
+             'header:',
+             'main header.',
+             'body:',
+             'this is the content.',
+             'footer:',
+             'this is the footer. header again',
+             'main header.'
+        ]
+
+    def test_multilevel_nesting(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main', """
+<%inherit file="layout"/>
+<%def name="d()">main_d</%def>
+main_body ${parent.d()}
+full stack from the top:
+    ${self.name} ${parent.name} ${parent.context['parent'].name} ${parent.context['parent'].context['parent'].name}
+""")
+
+        collection.put_string('layout', """
+<%inherit file="general"/>
+<%def name="d()">layout_d</%def>
+layout_body
+parent name: ${parent.name}
+${parent.d()}
+${parent.context['parent'].d()}
+${next.body()}
+""")
+
+        collection.put_string('general', """
+<%inherit file="base"/>
+<%def name="d()">general_d</%def>
+general_body
+${next.d()}
+${next.context['next'].d()}
+${next.body()}
+""")
+        collection.put_string('base', """
+base_body
+full stack from the base:
+    ${self.name} ${self.context['parent'].name} ${self.context['parent'].context['parent'].name} ${self.context['parent'].context['parent'].context['parent'].name}
+${next.body()}
+<%def name="d()">base_d</%def>
+""")
+
+        assert result_lines(collection.get_template('main').render()) == [
+            'base_body',
+             'full stack from the base:',
+             'self:main self:layout self:general self:base',
+             'general_body',
+             'layout_d',
+             'main_d',
+             'layout_body',
+             'parent name: self:general',
+             'general_d',
+             'base_d',
+             'main_body layout_d',
+             'full stack from the top:',
+             'self:main self:layout self:general self:base'
+        ]
+
+    def test_includes(self):
+        """test that an included template also has its full hierarchy invoked."""
+        collection = lookup.TemplateLookup()
+
+        collection.put_string("base", """
+        <%def name="a()">base_a</%def>
+        This is the base.
+        ${next.body()}
+        End base.
+""")
+
+        collection.put_string("index","""
+        <%inherit file="base"/>
+        this is index.
+        a is: ${self.a()}
+        <%include file="secondary"/>
+""")
+
+        collection.put_string("secondary","""
+        <%inherit file="base"/>
+        this is secondary.
+        a is: ${self.a()}
+""")
+
+        assert result_lines(collection.get_template("index").render()) == [
+            'This is the base.',
+            'this is index.',
+             'a is: base_a',
+             'This is the base.',
+             'this is secondary.',
+             'a is: base_a',
+             'End base.',
+             'End base.'
+            ]
+
+    def test_namespaces(self):
+        """test that templates used via <%namespace> have access to an inheriting 'self', and that
+        the full 'self' is also exported."""
+        collection = lookup.TemplateLookup()
+
+        collection.put_string("base", """
+        <%def name="a()">base_a</%def>
+        <%def name="b()">base_b</%def>
+        This is the base.
+        ${next.body()}
+""")
+
+        collection.put_string("layout", """
+        <%inherit file="base"/>
+        <%def name="a()">layout_a</%def>
+        This is the layout..
+        ${next.body()}
+""")
+
+        collection.put_string("index","""
+        <%inherit file="base"/>
+        <%namespace name="sc" file="secondary"/>
+        this is index.
+        a is: ${self.a()}
+        sc.a is: ${sc.a()}
+        sc.b is: ${sc.b()}
+        sc.c is: ${sc.c()}
+        sc.body is: ${sc.body()}
+""")
+
+        collection.put_string("secondary","""
+        <%inherit file="layout"/>
+        <%def name="c()">secondary_c.  a is ${self.a()} b is ${self.b()} d is ${self.d()}</%def>
+        <%def name="d()">secondary_d.</%def>
+        this is secondary.
+        a is: ${self.a()}
+        c is: ${self.c()}
+""")
+
+        assert result_lines(collection.get_template('index').render()) ==  ['This is the base.',
+         'this is index.',
+         'a is: base_a',
+         'sc.a is: layout_a',
+         'sc.b is: base_b',
+         'sc.c is: secondary_c. a is layout_a b is base_b d is secondary_d.',
+         'sc.body is:',
+         'this is secondary.',
+         'a is: layout_a',
+         'c is: secondary_c. a is layout_a b is base_b d is secondary_d.'
+         ]
+
+    def test_pageargs(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+
+            <%
+            sorted_ = pageargs.items()
+            sorted_ = sorted(sorted_)
+            %>
+            pageargs: (type: ${type(pageargs)}) ${sorted_}
+            <%def name="foo()">
+                ${next.body(**context.kwargs)}
+            </%def>
+
+            ${foo()}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            print ${x}, ${y}, ${z}
+        """)
+
+        if compat.py3k:
+            assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [
+                "this is the base.",
+                "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]",
+                "print 5, 10, 7"
+            ]
+        else:
+            assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [
+                "this is the base.",
+                "pageargs: (type: <type 'dict'>) [('x', 5), ('y', 10)]",
+                "print 5, 10, 7"
+            ]
+
+    def test_pageargs_2(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+
+            ${next.body(**context.kwargs)}
+
+            <%def name="foo(**kwargs)">
+                ${next.body(**kwargs)}
+            </%def>
+
+            <%def name="bar(**otherargs)">
+                ${next.body(z=16, **context.kwargs)}
+            </%def>
+
+            ${foo(x=12, y=15, z=8)}
+            ${bar(x=19, y=17)}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            pageargs: ${x}, ${y}, ${z}
+        """)
+        assert result_lines(collection.get_template('index').render(x=5,y=10)) == [
+            "this is the base.",
+            "pageargs: 5, 10, 7",
+            "pageargs: 12, 15, 8",
+            "pageargs: 5, 10, 16"
+        ]
+
+    def test_pageargs_err(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            ${next.body()}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            print ${x}, ${y}, ${z}
+        """)
+        try:
+            print(collection.get_template('index').render(x=5,y=10))
+            assert False
+        except TypeError:
+            assert True
+
+    def test_toplevel(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            ${next.body()}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            this is the body
+        """)
+        assert result_lines(collection.get_template('index').render()) == [
+            "this is the base.",
+            "this is the body"
+        ]
+        assert result_lines(collection.get_template('index').get_def("body").render()) == [
+            "this is the body"
+        ]
+
+    def test_dynamic(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            ${next.body()}
+        """)
+        collection.put_string("index", """
+            <%!
+                def dyn(context):
+                    if context.get('base', None) is not None:
+                        return 'base'
+                    else:
+                        return None
+            %>
+            <%inherit file="${dyn(context)}"/>
+            this is index.
+        """)
+        assert result_lines(collection.get_template('index').render()) == [
+            'this is index.'
+        ]
+        assert result_lines(collection.get_template('index').render(base=True)) == [
+            'this is the base.',
+            'this is index.'
+        ]
+
+    def test_in_call(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("/layout.html","""
+        Super layout!
+        <%call expr="self.grid()">
+            ${next.body()}
+        </%call>
+        Oh yea!
+
+        <%def name="grid()">
+            Parent grid
+                ${caller.body()}
+            End Parent
+        </%def>
+        """)
+
+
+        collection.put_string("/subdir/layout.html", """
+        ${next.body()}
+        <%def name="grid()">
+           Subdir grid
+               ${caller.body()}
+           End subdir
+        </%def>
+        <%inherit file="/layout.html"/>
+        """)
+
+        collection.put_string("/subdir/renderedtemplate.html","""
+        Holy smokes!
+        <%inherit file="/subdir/layout.html"/>
+        """)
+
+        #print collection.get_template("/layout.html").code
+        #print collection.get_template("/subdir/renderedtemplate.html").render()
+        assert result_lines(collection.get_template("/subdir/renderedtemplate.html").render()) == [
+            "Super layout!",
+            "Subdir grid",
+            "Holy smokes!",
+            "End subdir",
+            "Oh yea!"
+        ]
+
diff --git a/test/test_lexer.py b/test/test_lexer.py
new file mode 100644 (file)
index 0000000..06ebb05
--- /dev/null
@@ -0,0 +1,897 @@
+from mako.lexer import Lexer
+from mako import exceptions, util, compat
+from test.util import flatten_result
+from mako.template import Template
+import re
+from test import TemplateTest, eq_, assert_raises_message
+
+# create fake parsetree classes which are constructed
+# exactly as the repr() of a real parsetree object.
+# this allows us to use a Python construct as the source
+# of a comparable repr(), which is also hit by the 2to3 tool.
+
+def repr_arg(x):
+    if isinstance(x, dict):
+        return util.sorted_dict_repr(x)
+    else:
+        return repr(x)
+
+def _as_unicode(arg):
+    if isinstance(arg, compat.string_types):
+        return compat.text_type(arg)
+    elif isinstance(arg, dict):
+        return dict(
+            (_as_unicode(k), _as_unicode(v))
+            for k, v in arg.items()
+        )
+    else:
+        return arg
+from mako import parsetree
+for cls in list(parsetree.__dict__.values()):
+    if isinstance(cls, type) and \
+        issubclass(cls, parsetree.Node):
+        clsname = cls.__name__
+        exec(("""
+class %s(object):
+    def __init__(self, *args):
+        self.args = [_as_unicode(arg) for arg in args]
+    def __repr__(self):
+        return "%%s(%%s)" %% (
+            self.__class__.__name__,
+            ", ".join(repr_arg(x) for x in self.args)
+            )
+""" % clsname), locals())
+
+# NOTE: most assertion expressions were generated, then formatted
+# by PyTidy, hence the dense formatting.
+
+class LexerTest(TemplateTest):
+
+    def _compare(self, node, expected):
+        eq_(repr(node), repr(expected))
+
+    def test_text_and_tag(self):
+        template = """
+<b>Hello world</b>
+        <%def name="foo()">
+                this is a def.
+        </%def>
+
+        and some more text.
+"""
+        node = Lexer(template).parse()
+        self._compare(node, TemplateNode({},
+                      [Text('''\n<b>Hello world</b>\n        ''', (1,
+                      1)), DefTag('def', {'name': 'foo()'}, (3, 9),
+                      [Text('''\n                this is a def.\n        ''',
+                      (3, 28))]),
+                      Text('''\n\n        and some more text.\n''',
+                      (5, 16))]))
+
+    def test_unclosed_tag(self):
+        template = """
+
+            <%def name="foo()">
+             other text
+        """
+        try:
+            nodes = Lexer(template).parse()
+            assert False
+        except exceptions.SyntaxException:
+            eq_(
+                str(compat.exception_as()),
+                "Unclosed tag: <%def> at line: 5 char: 9"
+            )
+
+    def test_onlyclosed_tag(self):
+        template = \
+            """
+            <%def name="foo()">
+                foo
+            </%def>
+
+            </%namespace>
+
+            hi.
+        """
+        self.assertRaises(exceptions.SyntaxException,
+                          Lexer(template).parse)
+
+    def test_noexpr_allowed(self):
+        template = \
+            """
+            <%namespace name="${foo}"/>
+        """
+        self.assertRaises(exceptions.CompileException,
+                          Lexer(template).parse)
+
+    def test_unmatched_tag(self):
+        template = \
+            """
+        <%namespace name="bar">
+        <%def name="foo()">
+            foo
+            </%namespace>
+        </%def>
+
+
+        hi.
+"""
+        self.assertRaises(exceptions.SyntaxException,
+                          Lexer(template).parse)
+
+    def test_nonexistent_tag(self):
+        template = """
+            <%lala x="5"/>
+        """
+        self.assertRaises(exceptions.CompileException,
+                          Lexer(template).parse)
+
+    def test_wrongcase_tag(self):
+        template = \
+            """
+            <%DEF name="foo()">
+            </%def>
+
+        """
+        self.assertRaises(exceptions.CompileException,
+                          Lexer(template).parse)
+
+    def test_percent_escape(self):
+        template = \
+            """
+
+%% some whatever.
+
+    %% more some whatever
+    % if foo:
+    % endif
+        """
+        node = Lexer(template).parse()
+        self._compare(node, TemplateNode({}, [Text('''\n\n''',
+                      (1, 1)), Text('''% some whatever.\n\n''', (3, 2)),
+                      Text('   %% more some whatever\n', (5, 2)),
+                      ControlLine('if', 'if foo:', False, (6, 1)),
+                      ControlLine('if', 'endif', True, (7, 1)),
+                      Text('        ', (8, 1))]))
+
+    def test_old_multiline_comment(self):
+        template = """#*"""
+        node = Lexer(template).parse()
+        self._compare(node, TemplateNode({}, [Text('''#*''', (1, 1))]))
+
+
+    def test_text_tag(self):
+        template = \
+            """
+        ## comment
+        % if foo:
+            hi
+        % endif
+        <%text>
+            # more code
+
+            % more code
+            <%illegal compionent>/></>
+            <%def name="laal()">def</%def>
+
+
+        </%text>
+
+        <%def name="foo()">this is foo</%def>
+
+        % if bar:
+            code
+        % endif
+        """
+        node = Lexer(template).parse()
+        self._compare(node,
+            TemplateNode({}, [Text('\n', (1, 1)),
+                    Comment('comment', (2, 1)),
+                    ControlLine('if', 'if foo:', False, (3, 1)),
+                    Text('            hi\n', (4, 1)),
+                    ControlLine('if', 'endif', True, (5, 1)),
+                    Text('        ', (6, 1)),
+                    TextTag('text', {}, (6, 9),
+                    [Text('\n            # more code\n\n           '
+                        ' % more code\n            <%illegal compionent>/></>\n'
+                        '            <%def name="laal()">def</%def>\n\n\n        ',
+                        (6, 16))]), Text('\n\n        ', (14, 17)),
+                    DefTag('def', {'name': 'foo()'}, (16, 9),
+                    [Text('this is foo', (16, 28))]), Text('\n\n', (16, 46)),
+                    ControlLine('if', 'if bar:', False, (18, 1)),
+                    Text('            code\n', (19, 1)),
+                    ControlLine('if', 'endif', True, (20, 1)),
+                    Text('        ', (21, 1))])
+        )
+
+    def test_def_syntax(self):
+        template = \
+            """
+        <%def lala>
+            hi
+        </%def>
+"""
+        self.assertRaises(exceptions.CompileException,
+                          Lexer(template).parse)
+
+    def test_def_syntax_2(self):
+        template = \
+            """
+        <%def name="lala">
+            hi
+        </%def>
+    """
+        self.assertRaises(exceptions.CompileException,
+                          Lexer(template).parse)
+
+    def test_whitespace_equals(self):
+        template = \
+            """
+            <%def name = "adef()" >
+              adef
+            </%def>
+        """
+        node = Lexer(template).parse()
+        self._compare(node, TemplateNode({}, [Text('\n            ',
+                      (1, 1)), DefTag('def', {'name': 'adef()'}, (2,
+                      13),
+                      [Text('''\n              adef\n            ''',
+                      (2, 36))]), Text('\n        ', (4, 20))]))
+
+    def test_ns_tag_closed(self):
+        template = \
+            """
+
+            <%self:go x="1" y="2" z="${'hi' + ' ' + 'there'}"/>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('''
+
+            ''', (1, 1)),
+                      CallNamespaceTag('self:go', {'x': '1', 'y'
+                      : '2', 'z': "${'hi' + ' ' + 'there'}"}, (3,
+                      13), []), Text('\n        ', (3, 64))]))
+
+    def test_ns_tag_empty(self):
+        template = \
+            """
+            <%form:option value=""></%form:option>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n            ',
+                      (1, 1)), CallNamespaceTag('form:option',
+                      {'value': ''}, (2, 13), []), Text('\n        '
+                      , (2, 51))]))
+
+    def test_ns_tag_open(self):
+        template = \
+            """
+
+            <%self:go x="1" y="${process()}">
+                this is the body
+            </%self:go>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('''
+
+            ''', (1, 1)),
+                      CallNamespaceTag('self:go', {'x': '1', 'y'
+                      : '${process()}'}, (3, 13),
+                      [Text('''
+                this is the body
+            ''',
+                      (3, 46))]), Text('\n        ', (5, 24))]))
+
+    def test_expr_in_attribute(self):
+        """test some slightly trickier expressions.
+
+        you can still trip up the expression parsing, though, unless we
+        integrated really deeply somehow with AST."""
+
+        template = \
+            """
+            <%call expr="foo>bar and 'lala' or 'hoho'"/>
+            <%call expr='foo<bar and hoho>lala and "x" + "y"'/>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n            ',
+                      (1, 1)), CallTag('call', {'expr'
+                      : "foo>bar and 'lala' or 'hoho'"}, (2, 13), []),
+                      Text('\n            ', (2, 57)), CallTag('call'
+                      , {'expr': 'foo<bar and hoho>lala and "x" + "y"'
+                      }, (3, 13), []), Text('\n        ', (3, 64))]))
+
+    def test_pagetag(self):
+        template = \
+            """
+            <%page cached="True", args="a, b"/>
+
+            some template
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n            ',
+                      (1, 1)), PageTag('page', {'args': 'a, b',
+                      'cached': 'True'}, (2, 13), []),
+                      Text('''
+
+            some template
+        ''',
+                      (2, 48))]))
+
+    def test_nesting(self):
+        template = \
+            """
+
+        <%namespace name="ns">
+            <%def name="lala(hi, there)">
+                <%call expr="something()"/>
+            </%def>
+        </%namespace>
+
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('''
+
+        ''', (1, 1)),
+                      NamespaceTag('namespace', {'name': 'ns'}, (3,
+                      9), [Text('\n            ', (3, 31)),
+                      DefTag('def', {'name': 'lala(hi, there)'}, (4,
+                      13), [Text('\n                ', (4, 42)),
+                      CallTag('call', {'expr': 'something()'}, (5,
+                      17), []), Text('\n            ', (5, 44))]),
+                      Text('\n        ', (6, 20))]),
+                      Text('''
+
+        ''', (7, 22))]))
+
+    if compat.py3k:
+        def test_code(self):
+            template = \
+"""text
+    <%
+        print("hi")
+        for x in range(1,5):
+            print(x)
+    %>
+more text
+    <%!
+        import foo
+    %>
+"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes,
+            TemplateNode({}, [
+                Text('text\n    ', (1, 1)),
+                Code('\nprint("hi")\nfor x in range(1,5):\n    '
+                            'print(x)\n    \n', False, (2, 5)),
+                Text('\nmore text\n    ', (6, 7)),
+                Code('\nimport foo\n    \n', True, (8, 5)),
+                Text('\n', (10, 7))])
+            )
+
+
+    else:
+
+        def test_code(self):
+            template = \
+"""text
+    <%
+        print "hi"
+        for x in range(1,5):
+            print x
+    %>
+more text
+    <%!
+        import foo
+    %>
+"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes,
+            TemplateNode({}, [
+                Text('text\n    ', (1, 1)),
+                Code('\nprint "hi"\nfor x in range(1,5):\n    '
+                            'print x\n    \n', False, (2, 5)),
+                Text('\nmore text\n    ', (6, 7)),
+                Code('\nimport foo\n    \n', True, (8, 5)),
+                Text('\n', (10, 7))])
+            )
+
+    def test_code_and_tags(self):
+        template = \
+            """
+<%namespace name="foo">
+    <%def name="x()">
+        this is x
+    </%def>
+    <%def name="y()">
+        this is y
+    </%def>
+</%namespace>
+
+<%
+    result = []
+    data = get_data()
+    for x in data:
+        result.append(x+7)
+%>
+
+    result: <%call expr="foo.x(result)"/>
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)),
+                      NamespaceTag('namespace', {'name': 'foo'}, (2,
+                      1), [Text('\n    ', (2, 24)), DefTag('def',
+                      {'name': 'x()'}, (3, 5),
+                      [Text('''\n        this is x\n    ''', (3, 22))]),
+                      Text('\n    ', (5, 12)), DefTag('def', {'name'
+                      : 'y()'}, (6, 5),
+                      [Text('''\n        this is y\n    ''', (6, 22))]),
+                      Text('\n', (8, 12))]), Text('''\n\n''', (9, 14)),
+                      Code('''\nresult = []\ndata = get_data()\n'''
+                      '''for x in data:\n    result.append(x+7)\n\n''',
+                      False, (11, 1)), Text('''\n\n    result: ''', (16,
+                      3)), CallTag('call', {'expr': 'foo.x(result)'
+                      }, (18, 13), []), Text('\n', (18, 42))]))
+
+    def test_expression(self):
+        template = \
+            """
+        this is some ${text} and this is ${textwith | escapes, moreescapes}
+        <%def name="hi()">
+            give me ${foo()} and ${bar()}
+        </%def>
+        ${hi()}
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('\n        this is some ', (1, 1)),
+                      Expression('text', [], (2, 22)),
+                      Text(' and this is ', (2, 29)),
+                      Expression('textwith ', ['escapes', 'moreescapes'
+                      ], (2, 42)), Text('\n        ', (2, 76)),
+                      DefTag('def', {'name': 'hi()'}, (3, 9),
+                      [Text('\n            give me ', (3, 27)),
+                      Expression('foo()', [], (4, 21)), Text(' and ',
+                      (4, 29)), Expression('bar()', [], (4, 34)),
+                      Text('\n        ', (4, 42))]), Text('\n        '
+                      , (5, 16)), Expression('hi()', [], (6, 9)),
+                      Text('\n', (6, 16))]))
+
+
+    def test_tricky_expression(self):
+        template = """
+
+            ${x and "|" or "hi"}
+        """
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode({}, [
+                Text('\n\n            ', (1, 1)),
+                Expression('x and "|" or "hi"', [], (3, 13)),
+                Text('\n        ', (3, 33))
+            ])
+        )
+
+        template = r"""
+
+            ${hello + '''heres '{|}' text | | }''' | escape1}
+            ${'Tricky string: ' + '\\\"\\\'|\\'}
+        """
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode({}, [
+                Text('\n\n            ', (1, 1)),
+                Expression("hello + '''heres '{|}' text | | }''' ",
+                                ['escape1'], (3, 13)),
+                Text('\n            ', (3, 62)),
+                Expression(r"""'Tricky string: ' + '\\\"\\\'|\\'""",
+                                [], (4, 13)),
+                Text('\n        ', (4, 49))
+            ])
+        )
+
+    def test_tricky_code(self):
+        if compat.py3k:
+            template = """<% print('hi %>') %>"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes, TemplateNode({},
+                          [Code("print('hi %>') \n", False, (1, 1))]))
+        else:
+            template = """<% print 'hi %>' %>"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes, TemplateNode({},
+                          [Code("print 'hi %>' \n", False, (1, 1))]))
+
+    def test_tricky_code_2(self):
+        template = \
+            """<%
+        # someone's comment
+%>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Code("""
+        # someone's comment
+
+""",
+                      False, (1, 1)), Text('\n        ', (3, 3))]))
+
+    if compat.py3k:
+        def test_tricky_code_3(self):
+            template = \
+                """<%
+            print('hi')
+            # this is a comment
+            # another comment
+            x = 7 # someone's '''comment
+            print('''
+        there
+        ''')
+            # someone else's comment
+%> '''and now some text '''"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes, TemplateNode({},
+                          [Code("""
+print('hi')
+# this is a comment
+# another comment
+x = 7 # someone's '''comment
+print('''
+        there
+        ''')
+# someone else's comment
+
+""",
+                          False, (1, 1)),
+                          Text(" '''and now some text '''", (10,
+                          3))]))
+    else:
+        def test_tricky_code_3(self):
+            template = \
+                """<%
+            print 'hi'
+            # this is a comment
+            # another comment
+            x = 7 # someone's '''comment
+            print '''
+        there
+        '''
+            # someone else's comment
+%> '''and now some text '''"""
+            nodes = Lexer(template).parse()
+            self._compare(nodes, TemplateNode({},
+                      [Code("""\nprint 'hi'\n# this is a comment\n"""
+                      """# another comment\nx = 7 """
+                      """# someone's '''comment\nprint '''\n        """
+                      """there\n        '''\n# someone else's """
+                      """comment\n\n""",
+                      False, (1, 1)),
+                      Text(" '''and now some text '''", (10, 3))]))
+
+    def test_tricky_code_4(self):
+        template = \
+            """<% foo = "\\"\\\\" %>"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Code("""foo = "\\"\\\\" \n""",
+                      False, (1, 1))]))
+
+    def test_tricky_code_5(self):
+        template = \
+            """before ${ {'key': 'value'} } after"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('before ', (1, 1)),
+                      Expression(" {'key': 'value'} ", [], (1, 8)),
+                      Text(' after', (1, 29))]))
+
+    def test_tricky_code_6(self):
+        template = \
+            """before ${ (0x5302 | 0x0400) } after"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('before ', (1, 1)),
+                      Expression(" (0x5302 | 0x0400) ", [], (1, 8)),
+                      Text(' after', (1, 30))]))
+
+    def test_control_lines(self):
+        template = \
+            """
+text text la la
+% if foo():
+ mroe text la la blah blah
+% endif
+
+        and osme more stuff
+        % for l in range(1,5):
+    tex tesl asdl l is ${l} kfmas d
+      % endfor
+    tetx text
+
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('''\ntext text la la\n''', (1, 1)),
+                      ControlLine('if', 'if foo():', False, (3, 1)),
+                      Text(' mroe text la la blah blah\n', (4, 1)),
+                      ControlLine('if', 'endif', True, (5, 1)),
+                      Text('''\n        and osme more stuff\n''', (6,
+                      1)), ControlLine('for', 'for l in range(1,5):',
+                      False, (8, 1)), Text('    tex tesl asdl l is ',
+                      (9, 1)), Expression('l', [], (9, 24)),
+                      Text(' kfmas d\n', (9, 28)), ControlLine('for',
+                      'endfor', True, (10, 1)),
+                      Text('''    tetx text\n\n''', (11, 1))]))
+
+    def test_control_lines_2(self):
+        template = \
+"""% for file in requestattr['toc'].filenames:
+    x
+% endfor
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [ControlLine('for',
+                      "for file in requestattr['toc'].filenames:",
+                      False, (1, 1)), Text('    x\n', (2, 1)),
+                      ControlLine('for', 'endfor', True, (3, 1))]))
+
+    def test_long_control_lines(self):
+        template = \
+        """
+    % for file in \\
+        requestattr['toc'].filenames:
+        x
+    % endfor
+        """
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode({}, [
+                Text('\n', (1, 1)),
+                ControlLine('for', "for file in \\\n        "
+                                "requestattr['toc'].filenames:",
+                                False, (2, 1)),
+                Text('        x\n', (4, 1)),
+                ControlLine('for', 'endfor', True, (5, 1)),
+                Text('        ', (6, 1))
+            ])
+        )
+
+    def test_unmatched_control(self):
+        template = """
+
+        % if foo:
+            % for x in range(1,5):
+        % endif
+"""
+        assert_raises_message(
+            exceptions.SyntaxException,
+            "Keyword 'endif' doesn't match keyword 'for' at line: 5 char: 1",
+            Lexer(template).parse
+        )
+
+    def test_unmatched_control_2(self):
+        template = """
+
+        % if foo:
+            % for x in range(1,5):
+            % endfor
+"""
+
+        assert_raises_message(
+            exceptions.SyntaxException,
+            "Unterminated control keyword: 'if' at line: 3 char: 1",
+            Lexer(template).parse
+        )
+
+    def test_unmatched_control_3(self):
+        template = """
+
+        % if foo:
+            % for x in range(1,5):
+            % endlala
+        % endif
+"""
+        assert_raises_message(
+            exceptions.SyntaxException,
+            "Keyword 'endlala' doesn't match keyword 'for' at line: 5 char: 1",
+            Lexer(template).parse
+        )
+
+    def test_ternary_control(self):
+        template = \
+            """
+        % if x:
+            hi
+        % elif y+7==10:
+            there
+        % elif lala:
+            lala
+        % else:
+            hi
+        % endif
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)),
+                      ControlLine('if', 'if x:', False, (2, 1)),
+                      Text('            hi\n', (3, 1)),
+                      ControlLine('elif', 'elif y+7==10:', False, (4,
+                      1)), Text('            there\n', (5, 1)),
+                      ControlLine('elif', 'elif lala:', False, (6,
+                      1)), Text('            lala\n', (7, 1)),
+                      ControlLine('else', 'else:', False, (8, 1)),
+                      Text('            hi\n', (9, 1)),
+                      ControlLine('if', 'endif', True, (10, 1))]))
+
+    def test_integration(self):
+        template = \
+            """<%namespace name="foo" file="somefile.html"/>
+ ## inherit from foobar.html
+<%inherit file="foobar.html"/>
+
+<%def name="header()">
+     <div>header</div>
+</%def>
+<%def name="footer()">
+    <div> footer</div>
+</%def>
+
+<table>
+    % for j in data():
+    <tr>
+        % for x in j:
+            <td>Hello ${x| h}</td>
+        % endfor
+    </tr>
+    % endfor
+</table>
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [NamespaceTag('namespace'
+                      , {'file': 'somefile.html', 'name': 'foo'},
+                      (1, 1), []), Text('\n', (1, 46)),
+                      Comment('inherit from foobar.html', (2, 1)),
+                      InheritTag('inherit', {'file': 'foobar.html'},
+                      (3, 1), []), Text('''\n\n''', (3, 31)),
+                      DefTag('def', {'name': 'header()'}, (5, 1),
+                      [Text('''\n     <div>header</div>\n''', (5,
+                      23))]), Text('\n', (7, 8)), DefTag('def',
+                      {'name': 'footer()'}, (8, 1),
+                      [Text('''\n    <div> footer</div>\n''', (8,
+                      23))]), Text('''\n\n<table>\n''', (10, 8)),
+                      ControlLine('for', 'for j in data():', False,
+                      (13, 1)), Text('    <tr>\n', (14, 1)),
+                      ControlLine('for', 'for x in j:', False, (15,
+                      1)), Text('            <td>Hello ', (16, 1)),
+                      Expression('x', ['h'], (16, 23)), Text('</td>\n'
+                      , (16, 30)), ControlLine('for', 'endfor', True,
+                      (17, 1)), Text('    </tr>\n', (18, 1)),
+                      ControlLine('for', 'endfor', True, (19, 1)),
+                      Text('</table>\n', (20, 1))]))
+
+    def test_comment_after_statement(self):
+        template = \
+            """
+        % if x: #comment
+            hi
+        % else: #next
+            hi
+        % endif #end
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)),
+                      ControlLine('if', 'if x: #comment', False, (2,
+                      1)), Text('            hi\n', (3, 1)),
+                      ControlLine('else', 'else: #next', False, (4,
+                      1)), Text('            hi\n', (5, 1)),
+                      ControlLine('if', 'endif #end', True, (6, 1))]))
+
+    def test_crlf(self):
+        template = util.read_file(self._file_path("crlf.html"))
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode({}, [
+                Text('<html>\r\n\r\n', (1, 1)),
+                PageTag('page', {
+                            'args': "a=['foo',\n                'bar']"
+                        }, (3, 1), []),
+                Text('\r\n\r\nlike the name says.\r\n\r\n', (4, 26)),
+                ControlLine('for', 'for x in [1,2,3]:', False, (8, 1)),
+                Text('        ', (9, 1)),
+                Expression('x', [], (9, 9)),
+                ControlLine('for', 'endfor', True, (10, 1)),
+                Text('\r\n', (11, 1)),
+                Expression("trumpeter == 'Miles' and "
+                                "trumpeter or \\\n      'Dizzy'",
+                                [], (12, 1)),
+                Text('\r\n\r\n', (13, 15)),
+                DefTag('def', {'name': 'hi()'}, (15, 1), [
+                    Text('\r\n    hi!\r\n', (15, 19))]),
+                    Text('\r\n\r\n</html>\r\n', (17, 8))
+                ])
+        )
+        assert flatten_result(Template(template).render()) \
+            == """<html> like the name says. 1 2 3 Dizzy </html>"""
+
+    def test_comments(self):
+        template = \
+            """
+<style>
+ #someselector
+ # other non comment stuff
+</style>
+## a comment
+
+# also not a comment
+
+   ## this is a comment
+
+this is ## not a comment
+
+<%doc> multiline
+comment
+</%doc>
+
+hi
+"""
+        nodes = Lexer(template).parse()
+        self._compare(nodes, TemplateNode({},
+                      [Text('''\n<style>\n #someselector\n # '''
+                        '''other non comment stuff\n</style>\n''',
+                      (1, 1)), Comment('a comment', (6, 1)),
+                      Text('''\n# also not a comment\n\n''', (7, 1)),
+                      Comment('this is a comment', (10, 1)),
+                      Text('''\nthis is ## not a comment\n\n''', (11,
+                      1)), Comment(''' multiline\ncomment\n''', (14,
+                      1)), Text('''
+
+hi
+''', (16, 8))]))
+
+    def test_docs(self):
+        template = \
+            """
+        <%doc>
+            this is a comment
+        </%doc>
+        <%def name="foo()">
+            <%doc>
+                this is the foo func
+            </%doc>
+        </%def>
+        """
+        nodes = Lexer(template).parse()
+        self._compare(nodes,
+            TemplateNode({}, [Text('\n        ', (1,
+              1)),
+              Comment('''\n            this is a comment\n        ''',
+              (2, 9)), Text('\n        ', (4, 16)),
+              DefTag('def', {'name': 'foo()'}, (5, 9),
+              [Text('\n            ', (5, 28)),
+              Comment('''\n                this is the foo func\n'''
+                '''            ''',
+              (6, 13)), Text('\n        ', (8, 20))]),
+              Text('\n        ', (9, 16))]))
+
+    def test_preprocess(self):
+
+        def preproc(text):
+            return re.sub(r'(?<=\n)\s*#[^#]', '##', text)
+
+        template = \
+            """
+    hi
+    # old style comment
+# another comment
+"""
+        nodes = Lexer(template, preprocessor=preproc).parse()
+        self._compare(nodes, TemplateNode({}, [Text('''\n    hi\n''',
+                      (1, 1)), Comment('old style comment', (3, 1)),
+                      Comment('another comment', (4, 1))]))
diff --git a/test/test_lookup.py b/test/test_lookup.py
new file mode 100644 (file)
index 0000000..43234d2
--- /dev/null
@@ -0,0 +1,108 @@
+from mako.template import Template
+from mako import lookup, exceptions, runtime
+from mako.util import FastEncodingBuffer
+from mako import compat
+from test.util import flatten_result, result_lines
+from test import eq_
+import unittest
+import os
+
+from test import TemplateTest, template_base, module_base, assert_raises_message
+
+tl = lookup.TemplateLookup(directories=[template_base])
+class LookupTest(unittest.TestCase):
+    def test_basic(self):
+        t = tl.get_template('index.html')
+        assert result_lines(t.render()) == [
+            "this is index"
+        ]
+    def test_subdir(self):
+        t = tl.get_template('/subdir/index.html')
+        assert result_lines(t.render()) == [
+            "this is sub index",
+            "this is include 2"
+
+        ]
+
+        assert tl.get_template('/subdir/index.html').module_id \
+                            == '_subdir_index_html'
+
+    def test_updir(self):
+        t = tl.get_template('/subdir/foo/../bar/../index.html')
+        assert result_lines(t.render()) == [
+            "this is sub index",
+            "this is include 2"
+
+        ]
+
+    def test_directory_lookup(self):
+        """test that hitting an existent directory still raises
+        LookupError."""
+
+        self.assertRaises(exceptions.TopLevelLookupException,
+            tl.get_template, "/subdir"
+        )
+
+    def test_no_lookup(self):
+        t = Template("hi <%include file='foo.html'/>")
+        try:
+            t.render()
+            assert False
+        except exceptions.TemplateLookupException:
+            eq_(
+                str(compat.exception_as()),
+            "Template 'memory:%s' has no TemplateLookup associated" % \
+                            hex(id(t))
+                )
+
+    def test_uri_adjust(self):
+        tl = lookup.TemplateLookup(directories=['/foo/bar'])
+        assert tl.filename_to_uri('/foo/bar/etc/lala/index.html') == \
+                        '/etc/lala/index.html'
+
+        tl = lookup.TemplateLookup(directories=['./foo/bar'])
+        assert tl.filename_to_uri('./foo/bar/etc/index.html') == \
+                        '/etc/index.html'
+
+    def test_uri_cache(self):
+        """test that the _uri_cache dictionary is available"""
+        tl._uri_cache[('foo', 'bar')] = '/some/path'
+        assert tl._uri_cache[('foo', 'bar')] == '/some/path'
+
+    def test_check_not_found(self):
+        tl = lookup.TemplateLookup()
+        tl.put_string("foo", "this is a template")
+        f = tl.get_template("foo")
+        assert f.uri in tl._collection
+        f.filename = "nonexistent"
+        self.assertRaises(exceptions.TemplateLookupException,
+            tl.get_template, "foo"
+        )
+        assert f.uri not in tl._collection
+
+    def test_dont_accept_relative_outside_of_root(self):
+        """test the mechanics of an include where
+        the include goes outside of the path"""
+        tl = lookup.TemplateLookup(directories=[os.path.join(template_base, "subdir")])
+        index = tl.get_template("index.html")
+
+        ctx = runtime.Context(FastEncodingBuffer())
+        ctx._with_template=index
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+           "Template uri \"../index.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            runtime._lookup_template, ctx, "../index.html", index.uri
+        )
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+           "Template uri \"../othersubdir/foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            runtime._lookup_template, ctx, "../othersubdir/foo.html", index.uri
+        )
+
+        # this is OK since the .. cancels out
+        t = runtime._lookup_template(ctx, "foo/../index.html", index.uri)
+
diff --git a/test/test_loop.py b/test/test_loop.py
new file mode 100644 (file)
index 0000000..bdfbaea
--- /dev/null
@@ -0,0 +1,295 @@
+import re
+import unittest
+
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako.codegen import (
+        _FOR_LOOP, mangle_mako_loop, LoopVariable
+    )
+from mako.runtime import LoopStack, LoopContext
+from mako import exceptions
+from test import assert_raises_message
+from test import TemplateTest, eq_
+from test.util import flatten_result, result_lines
+
+class TestLoop(unittest.TestCase):
+
+    def test__FOR_LOOP(self):
+        for statement, target_list, expression_list in (
+                ('for x in y:', 'x', 'y'),
+                ('for x, y in z:', 'x, y', 'z'),
+                ('for (x,y) in z:', '(x,y)', 'z'),
+                ('for ( x, y, z) in a:', '( x, y, z)', 'a'),
+                ('for x in [1, 2, 3]:', 'x', '[1, 2, 3]'),
+                ('for x in "spam":', 'x', '"spam"'),
+                ('for k,v in dict(a=1,b=2).items():', 'k,v',
+                    'dict(a=1,b=2).items()'),
+                ('for x in [y+1 for y in [1, 2, 3]]:', 'x',
+                    '[y+1 for y in [1, 2, 3]]')
+                ):
+            match = _FOR_LOOP.match(statement)
+            assert match and match.groups() == (target_list, expression_list)
+
+    def test_no_loop(self):
+        template = Template("""% for x in 'spam':
+${x}
+% endfor""")
+        code = template.code
+        assert not re.match(r"loop = __M_loop._enter\(:", code), "No need to "\
+                "generate a loop context if the loop variable wasn't accessed"
+        print(template.render())
+
+    def test_loop_demo(self):
+        template = Template("""x|index|reverse_index|first|last|cycle|even|odd
+% for x in 'ham':
+${x}|${loop.index}|${loop.reverse_index}|${loop.first}|${loop.last}|${loop.cycle('even', 'odd')}|${loop.even}|${loop.odd}
+% endfor""")
+        expected = [
+                "x|index|reverse_index|first|last|cycle|even|odd",
+                "h|0|2|True|False|even|True|False",
+                "a|1|1|False|False|odd|False|True",
+                "m|2|0|False|True|even|True|False"
+            ]
+        code = template.code
+        assert "loop = __M_loop._enter(" in code, "Generated a loop context since "\
+                "the loop variable was accessed"
+        rendered = template.render()
+        print(rendered)
+        for line in expected:
+            assert line in rendered, "Loop variables give information about "\
+                    "the progress of the loop"
+
+    def test_nested_loops(self):
+        template = Template("""% for x in 'ab':
+${x} ${loop.index} <- start in outer loop
+% for y in [0, 1]:
+${y} ${loop.index} <- go to inner loop
+% endfor
+${x} ${loop.index} <- back to outer loop
+% endfor""")
+        code = template.code
+        rendered = template.render()
+        expected = [
+                "a 0 <- start in outer loop",
+                "0 0 <- go to inner loop",
+                "1 1 <- go to inner loop",
+                "a 0 <- back to outer loop",
+                "b 1 <- start in outer loop",
+                "0 0 <- go to inner loop",
+                "1 1 <- go to inner loop",
+                "b 1 <- back to outer loop",
+            ]
+        for line in expected:
+            assert line in rendered, "The LoopStack allows you to take "\
+                    "advantage of the loop variable even in embedded loops"
+
+    def test_parent_loops(self):
+        template = Template("""% for x in 'ab':
+${x} ${loop.index} <- outer loop
+% for y in [0, 1]:
+${y} ${loop.index} <- inner loop
+${x} ${loop.parent.index} <- parent loop
+% endfor
+${x} ${loop.index} <- outer loop
+% endfor""")
+        code = template.code
+        rendered = template.render()
+        expected = [
+                "a 0 <- outer loop",
+                "a 0 <- parent loop",
+                "b 1 <- outer loop",
+                "b 1 <- parent loop"
+            ]
+        for line in expected:
+            print(code)
+            assert line in rendered, "The parent attribute of a loop gives "\
+                    "you the previous loop context in the stack"
+
+    def test_out_of_context_access(self):
+        template = Template("""${loop.index}""")
+        assert_raises_message(
+            exceptions.RuntimeException,
+            "No loop context is established",
+            template.render
+        )
+
+class TestLoopStack(unittest.TestCase):
+
+    def setUp(self):
+        self.stack = LoopStack()
+        self.bottom = 'spam'
+        self.stack.stack = [self.bottom]
+
+    def test_enter(self):
+        iterable = 'ham'
+        s = self.stack._enter(iterable)
+        assert s is self.stack.stack[-1], "Calling the stack with an iterable returns "\
+                "the stack"
+        assert iterable == self.stack.stack[-1]._iterable, "and pushes the "\
+                "iterable on the top of the stack"
+
+    def test__top(self):
+        assert self.bottom == self.stack._top, "_top returns the last item "\
+                "on the stack"
+
+    def test__pop(self):
+        assert len(self.stack.stack) == 1
+        top = self.stack._pop()
+        assert top == self.bottom
+        assert len(self.stack.stack) == 0
+
+    def test__push(self):
+        assert len(self.stack.stack) == 1
+        iterable = 'ham'
+        self.stack._push(iterable)
+        assert len(self.stack.stack) == 2
+        assert iterable is self.stack._top._iterable
+
+    def test_exit(self):
+        iterable = 'ham'
+        self.stack._enter(iterable)
+        before = len(self.stack.stack)
+        self.stack._exit()
+        after = len(self.stack.stack)
+        assert before == (after + 1), "Exiting a context pops the stack"
+
+
+class TestLoopContext(unittest.TestCase):
+
+    def setUp(self):
+        self.iterable = [1, 2, 3]
+        self.ctx = LoopContext(self.iterable)
+
+    def test___len__(self):
+        assert len(self.iterable) == len(self.ctx), "The LoopContext is the "\
+                "same length as the iterable"
+
+    def test_index(self):
+        expected = tuple(range(len(self.iterable)))
+        actual = tuple(self.ctx.index for i in self.ctx)
+        assert expected == actual, "The index is consistent with the current "\
+                "iteration count"
+
+    def test_reverse_index(self):
+        length = len(self.iterable)
+        expected = tuple([length-i-1 for i in range(length)])
+        actual = tuple(self.ctx.reverse_index for i in self.ctx)
+        print(expected, actual)
+        assert expected == actual, "The reverse_index is the number of "\
+                "iterations until the end"
+
+    def test_first(self):
+        expected = (True, False, False)
+        actual = tuple(self.ctx.first for i in self.ctx)
+        assert expected == actual, "first is only true on the first iteration"
+
+    def test_last(self):
+        expected = (False, False, True)
+        actual = tuple(self.ctx.last for i in self.ctx)
+        assert expected == actual, "last is only true on the last iteration"
+
+    def test_even(self):
+        expected = (True, False, True)
+        actual = tuple(self.ctx.even for i in self.ctx)
+        assert expected == actual, "even is true on even iterations"
+
+    def test_odd(self):
+        expected = (False, True, False)
+        actual = tuple(self.ctx.odd for i in self.ctx)
+        assert expected == actual, "odd is true on odd iterations"
+
+    def test_cycle(self):
+        expected = ('a', 'b', 'a')
+        actual = tuple(self.ctx.cycle('a', 'b') for i in self.ctx)
+        assert expected == actual, "cycle endlessly cycles through the values"
+
+class TestLoopFlags(TemplateTest):
+    def test_loop_disabled_template(self):
+        self._do_memory_test(
+        """
+            the loop: ${loop}
+        """,
+        "the loop: hi",
+        template_args=dict(loop='hi'),
+        filters=flatten_result,
+        enable_loop=False
+        )
+
+    def test_loop_disabled_lookup(self):
+        l = TemplateLookup(enable_loop=False)
+        l.put_string("x",
+        """
+            the loop: ${loop}
+        """
+        )
+
+        self._do_test(
+            l.get_template("x"),
+            "the loop: hi",
+            template_args=dict(loop='hi'),
+            filters=flatten_result,
+        )
+
+    def test_loop_disabled_override_template(self):
+        self._do_memory_test(
+        """
+            <%page enable_loop="True" />
+            % for i in (1, 2, 3):
+                ${i} ${loop.index}
+            % endfor
+        """,
+        "1 0 2 1 3 2",
+        template_args=dict(loop='hi'),
+        filters=flatten_result,
+        enable_loop=False
+        )
+
+    def test_loop_disabled_override_lookup(self):
+        l = TemplateLookup(enable_loop=False)
+        l.put_string("x",
+        """
+            <%page enable_loop="True" />
+            % for i in (1, 2, 3):
+                ${i} ${loop.index}
+            % endfor
+        """
+        )
+
+        self._do_test(
+            l.get_template("x"),
+            "1 0 2 1 3 2",
+            template_args=dict(loop='hi'),
+            filters=flatten_result,
+        )
+
+    def test_loop_enabled_override_template(self):
+        self._do_memory_test(
+        """
+            <%page enable_loop="True" />
+            % for i in (1, 2, 3):
+                ${i} ${loop.index}
+            % endfor
+        """,
+        "1 0 2 1 3 2",
+        template_args=dict(),
+        filters=flatten_result,
+        )
+
+    def test_loop_enabled_override_lookup(self):
+        l = TemplateLookup()
+        l.put_string("x",
+        """
+            <%page enable_loop="True" />
+            % for i in (1, 2, 3):
+                ${i} ${loop.index}
+            % endfor
+        """
+        )
+
+        self._do_test(
+            l.get_template("x"),
+            "1 0 2 1 3 2",
+            template_args=dict(),
+            filters=flatten_result,
+        )
+
diff --git a/test/test_lru.py b/test/test_lru.py
new file mode 100644 (file)
index 0000000..6152799
--- /dev/null
@@ -0,0 +1,114 @@
+from mako.util import LRUCache
+import string
+import unittest
+import time
+import random
+
+from mako.compat import thread
+
+class item:
+    def __init__(self, id):
+        self.id = id
+
+    def __str__(self):
+        return "item id %d" % self.id
+
+class LRUTest(unittest.TestCase):
+
+
+    def testlru(self):
+        l = LRUCache(10, threshold=.2)
+
+        for id in range(1,20):
+            l[id] = item(id)
+
+        # first couple of items should be gone
+        assert 1 not in l
+        assert 2 not in l
+
+        # next batch over the threshold of 10 should be present
+        for id in range(11,20):
+            assert id in l
+
+        l[12]
+        l[15]
+        l[23] = item(23)
+        l[24] = item(24)
+        l[25] = item(25)
+        l[26] = item(26)
+        l[27] = item(27)
+
+        assert 11 not in l
+        assert 13 not in l
+
+        for id in (25, 24, 23, 14, 12, 19, 18, 17, 16, 15):
+            assert id in l
+
+    def _disabled_test_threaded(self):
+        size = 100
+        threshold = .5
+        all_elems = 2000
+        hot_zone = list(range(30,40))
+        cache = LRUCache(size, threshold)
+
+        # element to store
+        class Element(object):
+            def __init__(self, id):
+                self.id = id
+                self.regets = 0
+
+        # return an element.  we will favor ids in the relatively small
+        # "hot zone" 25% of  the time.
+        def get_elem():
+            if random.randint(1,4) == 1:
+                return hot_zone[random.randint(0, len(hot_zone) - 1)]
+            else:
+                return random.randint(1, all_elems)
+
+        total = [0]
+        # request thread.
+        def request_elem():
+            while True:
+                total[0] += 1
+                id = get_elem()
+                try:
+                    elem = cache[id]
+                    elem.regets += 1
+                except KeyError:
+                    e = Element(id)
+                    cache[id] = e
+
+                time.sleep(random.random() / 1000)
+
+        for x in range(0,20):
+            _thread.start_new_thread(request_elem, ())
+
+        # assert size doesn't grow unbounded, doesnt shrink well below size
+        for x in range(0,5):
+            time.sleep(1)
+            print("size:", len(cache))
+            assert len(cache) < size + size * threshold * 2
+            assert len(cache) > size - (size * .1)
+
+        # computs the average number of times a range of elements were "reused",
+        # i.e. without being removed from the cache.
+        def average_regets_in_range(start, end):
+            elem = [e for e in list(cache.values()) if e.id >= start and e.id <= end]
+            if len(elem) == 0:
+                return 0
+            avg = sum([e.regets for e in elem]) / len(elem)
+            return avg
+
+        hotzone_avg = average_regets_in_range(30, 40)
+        control_avg = average_regets_in_range(450,760)
+        total_avg = average_regets_in_range(0, 2000)
+
+        # hotzone should be way above the others
+        print("total fetches", total[0], "hotzone", \
+                                hotzone_avg, "control", \
+                                control_avg, "total", total_avg)
+
+        assert hotzone_avg > total_avg * 5 > control_avg * 5
+
+
+
diff --git a/test/test_namespace.py b/test/test_namespace.py
new file mode 100644 (file)
index 0000000..90964b5
--- /dev/null
@@ -0,0 +1,792 @@
+from mako.template import Template
+from mako import lookup
+from test.util import flatten_result, result_lines
+from test import TemplateTest, eq_
+
+class NamespaceTest(TemplateTest):
+    def test_inline_crossreference(self):
+        self._do_memory_test(
+            """
+            <%namespace name="x">
+                <%def name="a()">
+                    this is x a
+                </%def>
+                <%def name="b()">
+                    this is x b, and heres ${a()}
+                </%def>
+            </%namespace>
+
+            ${x.a()}
+
+            ${x.b()}
+    """,
+            "this is x a this is x b, and heres this is x a",
+            filters=flatten_result
+        )
+
+    def test_inline_assignment(self):
+        self._do_memory_test(
+            """
+            <%namespace name="x">
+                <%def name="a()">
+                    <%
+                        x = 5
+                    %>
+                    this is x: ${x}
+                </%def>
+            </%namespace>
+
+            ${x.a()}
+
+    """,
+            "this is x: 5",
+            filters=flatten_result
+        )
+
+    def test_inline_arguments(self):
+        self._do_memory_test(
+            """
+            <%namespace name="x">
+                <%def name="a(x, y)">
+                    <%
+                        result = x * y
+                    %>
+                    result: ${result}
+                </%def>
+            </%namespace>
+
+            ${x.a(5, 10)}
+
+    """,
+            "result: 50",
+            filters=flatten_result
+        )
+
+    def test_inline_not_duped(self):
+        self._do_memory_test(
+            """
+            <%namespace name="x">
+                <%def name="a()">
+                    foo
+                </%def>
+            </%namespace>
+
+            <%
+                assert x.a is not UNDEFINED, "namespace x.a wasn't defined"
+                assert a is UNDEFINED, "name 'a' is in the body locals"
+            %>
+
+    """,
+            "",
+            filters=flatten_result
+        )
+
+    def test_dynamic(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('a', """
+        <%namespace name="b" file="${context['b_def']}"/>
+
+        a.  b: ${b.body()}
+""")
+
+        collection.put_string('b', """
+        b.
+""")
+
+        eq_(
+            flatten_result(collection.get_template('a').render(b_def='b')),
+            "a. b: b."
+        )
+
+    def test_template(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace name="comp" file="defs.html"/>
+
+        this is main.  ${comp.def1("hi")}
+        ${comp.def2("there")}
+""")
+
+        collection.put_string('defs.html', """
+        <%def name="def1(s)">
+            def1: ${s}
+        </%def>
+
+        <%def name="def2(x)">
+            def2: ${x}
+        </%def>
+""")
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. def1: hi def2: there"
+
+    def test_module(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace name="comp" module="test.sample_module_namespace"/>
+
+        this is main.  ${comp.foo1()}
+        ${comp.foo2("hi")}
+""")
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+    def test_module_2(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace name="comp" module="test.foo.test_ns"/>
+
+        this is main.  ${comp.foo1()}
+        ${comp.foo2("hi")}
+""")
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+    def test_module_imports(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace import="*" module="test.foo.test_ns"/>
+
+        this is main.  ${foo1()}
+        ${foo2("hi")}
+""")
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+    def test_module_imports_2(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace import="foo1, foo2" module="test.foo.test_ns"/>
+
+        this is main.  ${foo1()}
+        ${foo2("hi")}
+""")
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+    def test_context(self):
+        """test that namespace callables get access to the current context"""
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace name="comp" file="defs.html"/>
+
+        this is main.  ${comp.def1()}
+        ${comp.def2("there")}
+""")
+
+        collection.put_string('defs.html', """
+        <%def name="def1()">
+            def1: x is ${x}
+        </%def>
+
+        <%def name="def2(x)">
+            def2: x is ${x}
+        </%def>
+""")
+
+        assert flatten_result(collection.get_template('main.html').render(x="context x")) == "this is main. def1: x is context x def2: x is there"
+
+    def test_overload(self):
+        collection = lookup.TemplateLookup()
+
+        collection.put_string('main.html', """
+        <%namespace name="comp" file="defs.html">
+            <%def name="def1(x, y)">
+                overridden def1 ${x}, ${y}
+            </%def>
+        </%namespace>
+
+        this is main.  ${comp.def1("hi", "there")}
+        ${comp.def2("there")}
+    """)
+
+        collection.put_string('defs.html', """
+        <%def name="def1(s)">
+            def1: ${s}
+        </%def>
+
+        <%def name="def2(x)">
+            def2: ${x}
+        </%def>
+    """)
+
+        assert flatten_result(collection.get_template('main.html').render()) == "this is main. overridden def1 hi, there def2: there"
+
+    def test_getattr(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("main.html", """
+            <%namespace name="foo" file="ns.html"/>
+            <%
+                 if hasattr(foo, 'lala'):
+                     foo.lala()
+                 if not hasattr(foo, 'hoho'):
+                     context.write('foo has no hoho.')
+            %>
+         """)
+        collection.put_string("ns.html", """
+          <%def name="lala()">this is lala.</%def>
+        """)
+        assert flatten_result(collection.get_template("main.html").render()) == "this is lala.foo has no hoho."
+
+    def test_in_def(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("main.html", """
+            <%namespace name="foo" file="ns.html"/>
+
+            this is main.  ${bar()}
+            <%def name="bar()">
+                this is bar, foo is ${foo.bar()}
+            </%def>
+        """)
+
+        collection.put_string("ns.html", """
+            <%def name="bar()">
+                this is ns.html->bar
+            </%def>
+        """)
+
+        assert result_lines(collection.get_template("main.html").render()) == [
+            "this is main.",
+            "this is bar, foo is" ,
+            "this is ns.html->bar"
+        ]
+
+
+    def test_in_remote_def(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("main.html", """
+            <%namespace name="foo" file="ns.html"/>
+
+            this is main.  ${bar()}
+            <%def name="bar()">
+                this is bar, foo is ${foo.bar()}
+            </%def>
+        """)
+
+        collection.put_string("ns.html", """
+            <%def name="bar()">
+                this is ns.html->bar
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%namespace name="main" file="main.html"/>
+
+            this is index
+            ${main.bar()}
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is index",
+            "this is bar, foo is" ,
+            "this is ns.html->bar"
+        ]
+
+    def test_dont_pollute_self(self):
+        # test that get_namespace() doesn't modify the original context
+        # incompatibly
+
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+
+        <%def name="foo()">
+        <%
+            foo = local.get_namespace("foo.html")
+        %>
+        </%def>
+
+        name: ${self.name}
+        name via bar: ${bar()}
+
+        ${next.body()}
+
+        name: ${self.name}
+        name via bar: ${bar()}
+        <%def name="bar()">
+            ${self.name}
+        </%def>
+
+
+        """)
+
+        collection.put_string("page.html", """
+        <%inherit file="base.html"/>
+
+        ${self.foo()}
+
+        hello world
+
+        """)
+
+        collection.put_string("foo.html", """<%inherit file="base.html"/>""")
+        assert result_lines(collection.get_template("page.html").render()) == [
+            "name: self:page.html",
+            "name via bar:",
+            "self:page.html",
+            "hello world",
+            "name: self:page.html",
+            "name via bar:",
+            "self:page.html"
+        ]
+
+    def test_inheritance(self):
+        """test namespace initialization in a base inherited template that doesnt otherwise access the namespace"""
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%namespace name="foo" file="ns.html" inheritable="True"/>
+
+            ${next.body()}
+""")
+        collection.put_string("ns.html", """
+            <%def name="bar()">
+                this is ns.html->bar
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%inherit file="base.html"/>
+
+            this is index
+            ${self.foo.bar()}
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is index",
+            "this is ns.html->bar"
+        ]
+
+    def test_inheritance_two(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%def name="foo()">
+                base.foo
+            </%def>
+
+            <%def name="bat()">
+                base.bat
+            </%def>
+""")
+        collection.put_string("lib.html", """
+            <%inherit file="base.html"/>
+            <%def name="bar()">
+                lib.bar
+                ${parent.foo()}
+                ${self.foo()}
+                ${parent.bat()}
+                ${self.bat()}
+            </%def>
+
+            <%def name="foo()">
+                lib.foo
+            </%def>
+
+        """)
+
+        collection.put_string("front.html", """
+            <%namespace name="lib" file="lib.html"/>
+            ${lib.bar()}
+        """)
+
+        assert result_lines(collection.get_template("front.html").render()) == ['lib.bar', 'base.foo', 'lib.foo', 'base.bat', 'base.bat']
+
+    def test_attr(self):
+        l = lookup.TemplateLookup()
+
+        l.put_string("foo.html", """
+        <%!
+            foofoo = "foo foo"
+            onlyfoo = "only foo"
+        %>
+        <%inherit file="base.html"/>
+        <%def name="setup()">
+            <%
+            self.attr.foolala = "foo lala"
+            %>
+        </%def>
+        ${self.attr.basefoo}
+        ${self.attr.foofoo}
+        ${self.attr.onlyfoo}
+        ${self.attr.lala}
+        ${self.attr.foolala}
+        """)
+
+        l.put_string("base.html", """
+        <%!
+            basefoo = "base foo 1"
+            foofoo = "base foo 2"
+        %>
+        <%
+            self.attr.lala = "base lala"
+        %>
+
+        ${self.attr.basefoo}
+        ${self.attr.foofoo}
+        ${self.attr.onlyfoo}
+        ${self.attr.lala}
+        ${self.setup()}
+        ${self.attr.foolala}
+        body
+        ${self.body()}
+        """)
+
+        assert result_lines(l.get_template("foo.html").render()) == [
+            "base foo 1",
+            "foo foo",
+            "only foo",
+            "base lala",
+            "foo lala",
+            "body",
+            "base foo 1",
+            "foo foo",
+            "only foo",
+            "base lala",
+            "foo lala",
+        ]
+
+    def test_attr_raise(self):
+        l = lookup.TemplateLookup()
+
+        l.put_string("foo.html", """
+            <%def name="foo()">
+            </%def>
+        """)
+
+        l.put_string("bar.html", """
+        <%namespace name="foo" file="foo.html"/>
+
+        ${foo.notfoo()}
+        """)
+
+        self.assertRaises(AttributeError, l.get_template("bar.html").render)
+
+    def test_custom_tag_1(self):
+        template = Template("""
+
+            <%def name="foo(x, y)">
+                foo: ${x} ${y}
+            </%def>
+
+            <%self:foo x="5" y="${7+8}"/>
+        """)
+        assert result_lines(template.render()) == ['foo: 5 15']
+
+    def test_custom_tag_2(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%def name="foo(x, y)">
+                foo: ${x} ${y}
+            </%def>
+
+            <%def name="bat(g)"><%
+                return "the bat! %s" % g
+            %></%def>
+
+            <%def name="bar(x)">
+                ${caller.body(z=x)}
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%namespace name="myns" file="base.html"/>
+
+            <%myns:foo x="${'some x'}" y="some y"/>
+
+            <%myns:bar x="${myns.bat(10)}" args="z">
+                record: ${z}
+            </%myns:bar>
+
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            'foo: some x some y',
+            'record: the bat! 10'
+        ]
+
+    def test_custom_tag_3(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%namespace name="foo" file="ns.html" inheritable="True"/>
+
+            ${next.body()}
+    """)
+        collection.put_string("ns.html", """
+            <%def name="bar()">
+                this is ns.html->bar
+                caller body: ${caller.body()}
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%inherit file="base.html"/>
+
+            this is index
+            <%self.foo:bar>
+                call body
+            </%self.foo:bar>
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is index",
+            "this is ns.html->bar",
+            "caller body:",
+            "call body"
+        ]
+
+    def test_custom_tag_case_sensitive(self):
+        t = Template("""
+        <%def name="renderPanel()">
+            panel ${caller.body()}
+        </%def>
+
+        <%def name="renderTablePanel()">
+            <%self:renderPanel>
+                hi
+            </%self:renderPanel>
+        </%def>
+
+        <%self:renderTablePanel/>
+        """)
+        assert result_lines(t.render()) == ['panel', 'hi']
+
+
+    def test_expr_grouping(self):
+        """test that parenthesis are placed around string-embedded expressions."""
+
+        template = Template("""
+            <%def name="bar(x, y)">
+                ${x}
+                ${y}
+            </%def>
+
+            <%self:bar x=" ${foo} " y="x${g and '1' or '2'}y"/>
+        """, input_encoding='utf-8')
+
+        # the concat has to come out as "x + (g and '1' or '2') + y"
+        assert result_lines(template.render(foo='this is foo', g=False)) == [
+            "this is foo",
+            "x2y"
+        ]
+
+
+    def test_ccall(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%namespace name="foo" file="ns.html" inheritable="True"/>
+
+            ${next.body()}
+    """)
+        collection.put_string("ns.html", """
+            <%def name="bar()">
+                this is ns.html->bar
+                caller body: ${caller.body()}
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%inherit file="base.html"/>
+
+            this is index
+            <%call expr="self.foo.bar()">
+                call body
+            </%call>
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is index",
+            "this is ns.html->bar",
+            "caller body:",
+            "call body"
+        ]
+
+    def test_ccall_2(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base.html", """
+            <%namespace name="foo" file="ns1.html" inheritable="True"/>
+
+            ${next.body()}
+    """)
+        collection.put_string("ns1.html", """
+            <%namespace name="foo2" file="ns2.html"/>
+            <%def name="bar()">
+                <%call expr="foo2.ns2_bar()">
+                this is ns1.html->bar
+                caller body: ${caller.body()}
+                </%call>
+            </%def>
+        """)
+
+        collection.put_string("ns2.html", """
+            <%def name="ns2_bar()">
+                this is ns2.html->bar
+                caller body: ${caller.body()}
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%inherit file="base.html"/>
+
+            this is index
+            <%call expr="self.foo.bar()">
+                call body
+            </%call>
+        """)
+
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is index",
+            "this is ns2.html->bar",
+            "caller body:",
+            "this is ns1.html->bar",
+            "caller body:",
+            "call body"
+        ]
+
+    def test_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo()">
+                this is foo
+            </%def>
+
+            <%def name="bar()">
+                this is bar
+            </%def>
+
+            <%def name="lala()">
+                this is lala
+            </%def>
+        """)
+
+        collection.put_string("func2.html", """
+            <%def name="a()">
+                this is a
+            </%def>
+            <%def name="b()">
+                this is b
+            </%def>
+        """)
+        collection.put_string("index.html", """
+            <%namespace file="functions.html" import="*"/>
+            <%namespace file="func2.html" import="a, b"/>
+            ${foo()}
+            ${bar()}
+            ${lala()}
+            ${a()}
+            ${b()}
+            ${x}
+        """)
+
+        assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+            "this is foo",
+            "this is bar",
+            "this is lala",
+            "this is a",
+            "this is b",
+            "this is x"
+        ]
+
+    def test_import_calledfromdef(self):
+        l = lookup.TemplateLookup()
+        l.put_string("a", """
+        <%def name="table()">
+            im table
+        </%def>
+        """)
+
+        l.put_string("b","""
+        <%namespace file="a" import="table"/>
+
+        <%
+            def table2():
+                table()
+                return ""
+        %>
+
+        ${table2()}
+        """)
+
+        t = l.get_template("b")
+        assert flatten_result(t.render()) == "im table"
+
+    def test_closure_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo()">
+                this is foo
+            </%def>
+
+            <%def name="bar()">
+                this is bar
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%namespace file="functions.html" import="*"/>
+            <%def name="cl1()">
+                ${foo()}
+            </%def>
+
+            <%def name="cl2()">
+                ${bar()}
+            </%def>
+
+            ${cl1()}
+            ${cl2()}
+        """)
+        assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+            "this is foo",
+            "this is bar",
+        ]
+
+    def test_import_local(self):
+        t = Template("""
+            <%namespace import="*">
+                <%def name="foo()">
+                    this is foo
+                </%def>
+            </%namespace>
+
+            ${foo()}
+
+        """)
+        assert flatten_result(t.render()) == "this is foo"
+
+    def test_ccall_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo()">
+                this is foo
+            </%def>
+
+            <%def name="bar()">
+                this is bar.
+                ${caller.body()}
+                ${caller.lala()}
+            </%def>
+        """)
+
+        collection.put_string("index.html", """
+            <%namespace name="func" file="functions.html" import="*"/>
+            <%call expr="bar()">
+                this is index embedded
+                foo is ${foo()}
+                <%def name="lala()">
+                     this is lala ${foo()}
+                </%def>
+            </%call>
+        """)
+        #print collection.get_template("index.html").code
+        #print collection.get_template("functions.html").code
+        assert result_lines(collection.get_template("index.html").render()) == [
+            "this is bar.",
+            "this is index embedded",
+            "foo is",
+            "this is foo",
+            "this is lala",
+            "this is foo"
+        ]
diff --git a/test/test_pygen.py b/test/test_pygen.py
new file mode 100644 (file)
index 0000000..7671bd9
--- /dev/null
@@ -0,0 +1,254 @@
+import unittest
+
+from mako.pygen import PythonPrinter, adjust_whitespace
+from mako.compat import StringIO
+from test import eq_
+
+
+class GeneratePythonTest(unittest.TestCase):
+    def test_generate_normal(self):
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        printer.writeline("import lala")
+        printer.writeline("for x in foo:")
+        printer.writeline("print x")
+        printer.writeline(None)
+        printer.writeline("print y")
+        assert stream.getvalue() == \
+"""import lala
+for x in foo:
+    print x
+print y
+"""
+    def test_generate_adjusted(self):
+        block = """
+        x = 5 +6
+        if x > 7:
+            for y in range(1,5):
+                print "<td>%s</td>" % y
+"""
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        printer.write_indented_block(block)
+        printer.close()
+        #print stream.getvalue()
+        assert stream.getvalue() == \
+"""
+x = 5 +6
+if x > 7:
+    for y in range(1,5):
+        print "<td>%s</td>" % y
+
+"""
+    def test_generate_combo(self):
+        block = \
+"""
+                x = 5 +6
+                if x > 7:
+                    for y in range(1,5):
+                        print "<td>%s</td>" % y
+                    print "hi"
+                print "there"
+                foo(lala)
+"""
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        printer.writeline("import lala")
+        printer.writeline("for x in foo:")
+        printer.writeline("print x")
+        printer.write_indented_block(block)
+        printer.writeline(None)
+        printer.writeline("print y")
+        printer.close()
+        #print "->" + stream.getvalue().replace(' ', '#') + "<-"
+        eq_(stream.getvalue(),
+"""import lala
+for x in foo:
+    print x
+
+    x = 5 +6
+    if x > 7:
+        for y in range(1,5):
+            print "<td>%s</td>" % y
+        print "hi"
+    print "there"
+    foo(lala)
+
+print y
+""")
+    def test_multi_line(self):
+        block = \
+"""
+    if test:
+        print ''' this is a block of stuff.
+this is more stuff in the block.
+and more block.
+'''
+        do_more_stuff(g)
+"""
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        printer.write_indented_block(block)
+        printer.close()
+        #print stream.getvalue()
+        assert stream.getvalue() == \
+"""
+if test:
+    print ''' this is a block of stuff.
+this is more stuff in the block.
+and more block.
+'''
+    do_more_stuff(g)
+
+"""
+
+    def test_false_unindentor(self):
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        for line in [
+            "try:",
+            "elsemyvar = 12",
+            "if True:",
+            "print 'hi'",
+            None,
+            "finally:",
+            "dosomething",
+            None
+        ]:
+            printer.writeline(line)
+
+        assert stream.getvalue() == \
+"""try:
+    elsemyvar = 12
+    if True:
+        print 'hi'
+finally:
+    dosomething
+"""    , stream.getvalue()
+
+
+    def test_backslash_line(self):
+        block = \
+"""
+            # comment
+    if test:
+        if (lala + hoho) + \\
+(foobar + blat) == 5:
+            print "hi"
+    print "more indent"
+"""
+        stream = StringIO()
+        printer = PythonPrinter(stream)
+        printer.write_indented_block(block)
+        printer.close()
+        assert stream.getvalue() == \
+"""
+            # comment
+if test:
+    if (lala + hoho) + \\
+(foobar + blat) == 5:
+        print "hi"
+print "more indent"
+
+"""
+
+class WhitespaceTest(unittest.TestCase):
+    def test_basic(self):
+        text = """
+        for x in range(0,15):
+            print x
+        print "hi"
+        """
+        assert adjust_whitespace(text) == \
+"""
+for x in range(0,15):
+    print x
+print "hi"
+"""
+
+    def test_blank_lines(self):
+        text = """
+    print "hi"  # a comment
+
+    # more comments
+
+    print g
+"""
+        assert adjust_whitespace(text) == \
+"""
+print "hi"  # a comment
+
+# more comments
+
+print g
+"""
+
+    def test_open_quotes_with_pound(self):
+        text = '''
+        print """  this is text
+          # and this is text
+        # and this is too """
+'''
+        assert adjust_whitespace(text) == \
+'''
+print """  this is text
+          # and this is text
+        # and this is too """
+'''
+
+    def test_quote_with_comments(self):
+        text= """
+            print 'hi'
+            # this is a comment
+            # another comment
+            x = 7 # someone's '''comment
+            print '''
+        there
+        '''
+            # someone else's comment
+"""
+
+        assert adjust_whitespace(text) == \
+"""
+print 'hi'
+# this is a comment
+# another comment
+x = 7 # someone's '''comment
+print '''
+        there
+        '''
+# someone else's comment
+"""
+
+
+    def test_quotes_with_pound(self):
+        text = '''
+        if True:
+            """#"""
+        elif False:
+            "bar"
+'''
+        assert adjust_whitespace(text) == \
+'''
+if True:
+    """#"""
+elif False:
+    "bar"
+'''
+
+    def test_quotes(self):
+        text = """
+        print ''' aslkjfnas kjdfn
+askdjfnaskfd fkasnf dknf sadkfjn asdkfjna sdakjn
+asdkfjnads kfajns '''
+        if x:
+            print y
+"""
+        assert adjust_whitespace(text) == \
+"""
+print ''' aslkjfnas kjdfn
+askdjfnaskfd fkasnf dknf sadkfjn asdkfjna sdakjn
+asdkfjnads kfajns '''
+if x:
+    print y
+"""
diff --git a/test/test_runtime.py b/test/test_runtime.py
new file mode 100644 (file)
index 0000000..80b97ce
--- /dev/null
@@ -0,0 +1,21 @@
+"""Assorted runtime unit tests
+"""
+from mako import runtime
+import unittest
+from test import eq_
+
+class ContextTest(unittest.TestCase):
+    def test_locals_kwargs(self):
+        c = runtime.Context(None, foo='bar')
+        eq_(c.kwargs, {'foo': 'bar'})
+
+        d = c._locals({'zig': 'zag'})
+
+        # kwargs is the original args sent to the Context,
+        # it's intentionally kept separate from _data
+        eq_(c.kwargs, {'foo': 'bar'})
+        eq_(d.kwargs, {'foo': 'bar'})
+
+        eq_(d._data['zig'], 'zag')
+
+
diff --git a/test/test_template.py b/test/test_template.py
new file mode 100644 (file)
index 0000000..7f21978
--- /dev/null
@@ -0,0 +1,1375 @@
+# -*- coding: utf-8 -*-
+
+from mako.template import Template, ModuleTemplate, ModuleInfo
+from mako.lookup import TemplateLookup
+from mako.ext.preprocessors import convert_comments
+from mako import exceptions, runtime
+from mako import compat
+from mako import util
+import os
+from test.util import flatten_result, result_lines
+from mako.compat import u
+from test import TemplateTest, eq_, template_base, module_base, \
+    requires_python_26_or_greater, assert_raises, assert_raises_message, \
+    requires_python_2
+import unittest
+
+class ctx(object):
+    def __init__(self, a, b):
+        pass
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, *arg):
+        pass
+
+class EncodingTest(TemplateTest):
+    def test_escapes_html_tags(self):
+        from mako.exceptions import html_error_template
+
+        x = Template("""
+        X:
+        <% raise Exception('<span style="color:red">Foobar</span>') %>
+        """)
+
+        try:
+            x.render()
+        except:
+            # <h3>Exception: <span style="color:red">Foobar</span></h3>
+            markup = html_error_template().render(full=False, css=False)
+            if compat.py3k:
+                assert '<span style="color:red">Foobar</span></h3>'\
+                            .encode('ascii') not in markup
+                assert '&lt;span style=&#34;color:red&#34;'\
+                            '&gt;Foobar&lt;/span&gt;'\
+                            .encode('ascii') in markup
+            else:
+                assert '<span style="color:red">Foobar</span></h3>' \
+                            not in markup
+                assert '&lt;span style=&#34;color:red&#34;'\
+                            '&gt;Foobar&lt;/span&gt;' in markup
+
+    def test_unicode(self):
+        self._do_memory_test(
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+    def test_encoding_doesnt_conflict(self):
+        self._do_memory_test(
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            output_encoding='utf-8'
+        )
+
+    def test_unicode_arg(self):
+        val = u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        self._do_memory_test(
+            "${val}",
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            template_args={'val':val}
+        )
+
+    def test_unicode_file(self):
+        self._do_file_test(
+            "unicode.html",
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+    def test_unicode_file_code(self):
+        self._do_file_test(
+            'unicode_code.html',
+            u("""hi, drôle de petite voix m’a réveillé."""),
+            filters=flatten_result
+        )
+
+    def test_unicode_file_lookup(self):
+        lookup = TemplateLookup(
+                    directories=[template_base],
+                    output_encoding='utf-8',
+                    default_filters=['decode.utf8'])
+        if compat.py3k:
+            template = lookup.get_template('/chs_unicode_py3k.html')
+        else:
+            template = lookup.get_template('/chs_unicode.html')
+        eq_(
+            flatten_result(template.render_unicode(name='毛泽东')),
+            u('毛泽东 是 新中国的主席<br/> Welcome 你 to 北京.')
+        )
+
+    def test_unicode_bom(self):
+        self._do_file_test(
+            'bom.html',
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+        self._do_file_test(
+            'bommagic.html',
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+        self.assertRaises(
+            exceptions.CompileException,
+            Template, filename=self._file_path('badbom.html'),
+            module_directory=module_base
+        )
+
+    def test_unicode_memory(self):
+        val = u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        self._do_memory_test(
+            ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+    def test_unicode_text(self):
+        val = u("""<%text>Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »</%text>""")
+        self._do_memory_test(
+            ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""")
+        )
+
+    def test_unicode_text_ccall(self):
+        val = u("""
+        <%def name="foo()">
+            ${capture(caller.body)}
+        </%def>
+        <%call expr="foo()">
+        <%text>Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »</%text>
+        </%call>""")
+        self._do_memory_test(
+            ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            filters=flatten_result
+        )
+
+    def test_unicode_literal_in_expr(self):
+        if compat.py3k:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                ${"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"}
+                """).encode('utf-8'),
+                u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+                filters = lambda s:s.strip()
+            )
+        else:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                ${u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"}
+                """).encode('utf-8'),
+                u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+                filters = lambda s:s.strip()
+            )
+
+    def test_unicode_literal_in_expr_file(self):
+        self._do_file_test(
+            'unicode_expr.html',
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            lambda t:t.strip()
+        )
+
+    def test_unicode_literal_in_code(self):
+        if compat.py3k:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%
+                    context.write("Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »")
+                %>
+                """).encode('utf-8'),
+                u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+                filters=lambda s:s.strip()
+            )
+        else:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%
+                    context.write(u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »")
+                %>
+                """).encode('utf-8'),
+                u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+                filters=lambda s:s.strip()
+            )
+
+    def test_unicode_literal_in_controlline(self):
+        if compat.py3k:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%
+                    x = "drôle de petite voix m’a réveillé."
+                %>
+                % if x=="drôle de petite voix m’a réveillé.":
+                    hi, ${x}
+                % endif
+                """).encode('utf-8'),
+                u("""hi, drôle de petite voix m’a réveillé."""),
+                filters=lambda s:s.strip(),
+            )
+        else:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%
+                    x = u"drôle de petite voix m’a réveillé."
+                %>
+                % if x==u"drôle de petite voix m’a réveillé.":
+                    hi, ${x}
+                % endif
+                """).encode('utf-8'),
+                u("""hi, drôle de petite voix m’a réveillé."""),
+                filters=lambda s:s.strip(),
+            )
+
+    def test_unicode_literal_in_tag(self):
+        self._do_file_test(
+            "unicode_arguments.html",
+            [
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+            ],
+            filters=result_lines
+        )
+
+        self._do_memory_test(
+            util.read_file(self._file_path("unicode_arguments.html")),
+            [
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+                u('x is: drôle de petite voix m’a réveillé'),
+            ],
+            filters=result_lines
+        )
+
+    def test_unicode_literal_in_def(self):
+        if compat.py3k:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%def name="bello(foo, bar)">
+                Foo: ${ foo }
+                Bar: ${ bar }
+                </%def>
+                <%call expr="bello(foo='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+                </%call>""").encode('utf-8'),
+                u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""),
+                filters=flatten_result
+            )
+
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%def name="hello(foo='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+                Foo: ${ foo }
+                Bar: ${ bar }
+                </%def>
+                ${ hello() }""").encode('utf-8'),
+                u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""),
+                filters=flatten_result
+            )
+        else:
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%def name="bello(foo, bar)">
+                Foo: ${ foo }
+                Bar: ${ bar }
+                </%def>
+                <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+                </%call>""").encode('utf-8'),
+                u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""),
+                filters=flatten_result
+            )
+
+            self._do_memory_test(
+                u("""## -*- coding: utf-8 -*-
+                <%def name="hello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+                Foo: ${ foo }
+                Bar: ${ bar }
+                </%def>
+                ${ hello() }""").encode('utf-8'),
+                u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""),
+                filters=flatten_result
+            )
+
+    def test_input_encoding(self):
+        """test the 'input_encoding' flag on Template, and that unicode
+            objects arent double-decoded"""
+
+        if compat.py3k:
+            self._do_memory_test(
+                u("hello ${f('śląsk')}"),
+                u("hello śląsk"),
+                input_encoding='utf-8',
+                template_args={'f': lambda x:x}
+            )
+
+            self._do_memory_test(
+                u("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"),
+                u("hello śląsk"),
+                template_args={'f': lambda x:x}
+            )
+        else:
+            self._do_memory_test(
+                u("hello ${f(u'śląsk')}"),
+                u("hello śląsk"),
+                input_encoding='utf-8',
+                template_args={'f': lambda x:x}
+            )
+
+            self._do_memory_test(
+                u("## -*- coding: utf-8 -*-\nhello ${f(u'śląsk')}"),
+                u("hello śląsk"),
+                template_args={'f': lambda x:x}
+            )
+
+    def test_raw_strings(self):
+        """test that raw strings go straight thru with default_filters turned off,
+        bytestring_passthrough enabled.
+
+        """
+
+        self._do_memory_test(
+            u("## -*- coding: utf-8 -*-\nhello ${x}"),
+            "hello śląsk",
+            default_filters=[],
+            template_args={'x':'śląsk'},
+            unicode_=False,
+            bytestring_passthrough=True,
+            output_encoding=None #'ascii'
+        )
+
+        # now, the way you *should* be doing it....
+        self._do_memory_test(
+            u("## -*- coding: utf-8 -*-\nhello ${x}"),
+            u("hello śląsk"),
+            template_args={'x':u('śląsk')}
+        )
+
+    def test_encoding(self):
+        self._do_memory_test(
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""),
+            u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""").encode('utf-8'),
+            output_encoding='utf-8',
+            unicode_=False
+        )
+
+    def test_encoding_errors(self):
+        self._do_memory_test(
+            u("""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)"""),
+            u("""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)""").encode('iso-8859-1', 'replace'),
+            output_encoding='iso-8859-1', encoding_errors='replace',
+            unicode_=False
+        )
+
+    def test_read_unicode(self):
+        lookup = TemplateLookup(directories=[template_base],
+                                filesystem_checks=True, output_encoding='utf-8')
+        if compat.py3k:
+            template = lookup.get_template('/read_unicode_py3k.html')
+        else:
+            template = lookup.get_template('/read_unicode.html')
+        # TODO: I've no idea what encoding this file is, Python 3.1.2
+        # won't read the file even with open(...encoding='utf-8') unless
+        # errors is specified.   or if there's some quirk in 3.1.2
+        # since I'm pretty sure this test worked with py3k when I wrote it.
+        data = template.render(path=self._file_path('internationalization.html'))
+
+    @requires_python_2
+    def test_bytestring_passthru(self):
+        self._do_file_test(
+            'chs_utf8.html',
+            '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.',
+            default_filters=[],
+            disable_unicode=True,
+            output_encoding=None,
+            template_args={'name':'毛泽东'},
+            filters=flatten_result,
+            unicode_=False
+        )
+
+        self._do_file_test(
+            'chs_utf8.html',
+            '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.',
+            disable_unicode=True,
+            output_encoding=None,
+            template_args={'name':'毛泽东'},
+            filters=flatten_result,
+            unicode_=False
+        )
+
+        template = self._file_template('chs_utf8.html',
+                    output_encoding=None,
+                    disable_unicode=True)
+        self.assertRaises(UnicodeDecodeError, template.render_unicode, name='毛泽东')
+
+        template = Template(
+            "${'Alors vous imaginez ma surprise, au lever"
+            " du jour, quand une drôle de petite voix m’a "
+            "réveillé. Elle disait: « S’il vous plaît… "
+            "dessine-moi un mouton! »'}",
+            output_encoding=None,
+            disable_unicode=True, input_encoding='utf-8')
+        assert template.render() == "Alors vous imaginez ma surprise, "\
+                "au lever du jour, quand une drôle de petite "\
+                "voix m’a réveillé. Elle disait: « S’il vous "\
+                "plaît… dessine-moi un mouton! »"
+        template = Template(
+                "${'Alors vous imaginez ma surprise, au "
+                "lever du jour, quand une drôle de petite "
+                "voix m’a réveillé. Elle disait: « S’il "
+                "vous plaît… dessine-moi un mouton! »'}",
+                input_encoding='utf8', output_encoding='utf8',
+                disable_unicode=False, default_filters=[])
+        # raises because expression contains an encoded bytestring which cannot be decoded
+        self.assertRaises(UnicodeDecodeError, template.render)
+
+
+class PageArgsTest(TemplateTest):
+    def test_basic(self):
+        template = Template("""
+            <%page args="x, y, z=7"/>
+
+            this is page, ${x}, ${y}, ${z}
+""")
+
+        assert flatten_result(template.render(x=5, y=10)) == "this is page, 5, 10, 7"
+        assert flatten_result(template.render(x=5, y=10, z=32)) == "this is page, 5, 10, 32"
+        assert_raises(TypeError, template.render, y=10)
+
+    def test_inherits(self):
+        lookup = TemplateLookup()
+        lookup.put_string("base.tmpl",
+        """
+        <%page args="bar" />
+        ${bar}
+        ${pageargs['foo']}
+        ${self.body(**pageargs)}
+        """
+        )
+        lookup.put_string("index.tmpl", """
+        <%inherit file="base.tmpl" />
+        <%page args="variable" />
+        ${variable}
+        """)
+
+        self._do_test(
+            lookup.get_template("index.tmpl"),
+            "bar foo var",
+            filters=flatten_result,
+            template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
+
+        )
+
+    def test_includes(self):
+        lookup = TemplateLookup()
+        lookup.put_string("incl1.tmpl",
+        """
+        <%page args="bar" />
+        ${bar}
+        ${pageargs['foo']}
+        """
+        )
+        lookup.put_string("incl2.tmpl",
+        """
+        ${pageargs}
+        """
+        )
+        lookup.put_string("index.tmpl", """
+        <%include file="incl1.tmpl" args="**pageargs"/>
+        <%page args="variable" />
+        ${variable}
+        <%include file="incl2.tmpl" />
+        """)
+
+        self._do_test(
+            lookup.get_template("index.tmpl"),
+            "bar foo var {}",
+            filters=flatten_result,
+            template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
+
+        )
+
+    def test_context_small(self):
+        ctx = runtime.Context([].append, x=5, y=4)
+        eq_(sorted(ctx.keys()), ['caller', 'capture', 'x', 'y'])
+
+    def test_with_context(self):
+        template = Template("""
+            <%page args="x, y, z=7"/>
+
+            this is page, ${x}, ${y}, ${z}, ${w}
+""")
+        #print template.code
+        assert flatten_result(template.render(x=5, y=10, w=17)) == "this is page, 5, 10, 7, 17"
+
+    def test_overrides_builtins(self):
+        template = Template("""
+            <%page args="id"/>
+
+            this is page, id is ${id}
+        """)
+
+        assert flatten_result(template.render(id="im the id")) == "this is page, id is im the id"
+
+    def test_canuse_builtin_names(self):
+        template = Template("""
+            exception: ${Exception}
+            id: ${id}
+        """)
+        assert flatten_result(template.render(id='some id', Exception='some exception')) == "exception: some exception id: some id"
+
+    def test_builtin_names_dont_clobber_defaults_in_includes(self):
+        lookup = TemplateLookup()
+        lookup.put_string("test.mako",
+        """
+        <%include file="test1.mako"/>
+
+        """)
+
+        lookup.put_string("test1.mako", """
+        <%page args="id='foo'"/>
+
+        ${id}
+        """)
+
+        for template in ("test.mako", "test1.mako"):
+            assert flatten_result(lookup.get_template(template).render()) == "foo"
+            assert flatten_result(lookup.get_template(template).render(id=5)) == "5"
+            assert flatten_result(lookup.get_template(template).render(id=id)) == "<built-in function id>"
+
+    def test_dict_locals(self):
+        template = Template("""
+            <%
+                dict = "this is dict"
+                locals = "this is locals"
+            %>
+            dict: ${dict}
+            locals: ${locals}
+        """)
+        assert flatten_result(template.render()) == "dict: this is dict locals: this is locals"
+
+class IncludeTest(TemplateTest):
+    def test_basic(self):
+        lookup = TemplateLookup()
+        lookup.put_string("a", """
+            this is a
+            <%include file="b" args="a=3,b=4,c=5"/>
+        """)
+        lookup.put_string("b", """
+            <%page args="a,b,c"/>
+            this is b.  ${a}, ${b}, ${c}
+        """)
+        assert flatten_result(lookup.get_template("a").render()) == "this is a this is b. 3, 4, 5"
+
+    def test_localargs(self):
+        lookup = TemplateLookup()
+        lookup.put_string("a", """
+            this is a
+            <%include file="b" args="a=a,b=b,c=5"/>
+        """)
+        lookup.put_string("b", """
+            <%page args="a,b,c"/>
+            this is b.  ${a}, ${b}, ${c}
+        """)
+        assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5"
+
+    def test_viakwargs(self):
+        lookup = TemplateLookup()
+        lookup.put_string("a", """
+            this is a
+            <%include file="b" args="c=5, **context.kwargs"/>
+        """)
+        lookup.put_string("b", """
+            <%page args="a,b,c"/>
+            this is b.  ${a}, ${b}, ${c}
+        """)
+        #print lookup.get_template("a").code
+        assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5"
+
+    def test_include_withargs(self):
+        lookup = TemplateLookup()
+        lookup.put_string("a", """
+            this is a
+            <%include file="${i}" args="c=5, **context.kwargs"/>
+        """)
+        lookup.put_string("b", """
+            <%page args="a,b,c"/>
+            this is b.  ${a}, ${b}, ${c}
+        """)
+        assert flatten_result(lookup.get_template("a").render(a=7,b=8,i='b')) == "this is a this is b. 7, 8, 5"
+
+    def test_within_ccall(self):
+        lookup = TemplateLookup()
+        lookup.put_string("a", """this is a""")
+        lookup.put_string("b", """
+        <%def name="bar()">
+            bar: ${caller.body()}
+            <%include file="a"/>
+        </%def>
+        """)
+        lookup.put_string("c", """
+        <%namespace name="b" file="b"/>
+        <%b:bar>
+            calling bar
+        </%b:bar>
+        """)
+        assert flatten_result(lookup.get_template("c").render()) == "bar: calling bar this is a"
+
+    def test_include_error_handler(self):
+        def handle(context, error):
+            context.write('include error')
+            return True
+
+        lookup = TemplateLookup(include_error_handler=handle)
+        lookup.put_string("a", """
+            this is a.
+            <%include file="b"/>
+        """)
+        lookup.put_string("b", """
+            this is b ${1/0} end.
+        """)
+        assert flatten_result(lookup.get_template("a").render()) == "this is a. this is b include error"
+
+class UndefinedVarsTest(TemplateTest):
+    def test_undefined(self):
+        t = Template("""
+            % if x is UNDEFINED:
+                undefined
+            % else:
+                x: ${x}
+            % endif
+        """)
+
+        assert result_lines(t.render(x=12)) == ["x: 12"]
+        assert result_lines(t.render(y=12)) == ["undefined"]
+
+    def test_strict(self):
+        t = Template("""
+            % if x is UNDEFINED:
+                undefined
+            % else:
+                x: ${x}
+            % endif
+        """, strict_undefined=True)
+
+        assert result_lines(t.render(x=12)) == ['x: 12']
+
+        assert_raises(
+            NameError,
+            t.render, y=12
+        )
+
+        l = TemplateLookup(strict_undefined=True)
+        l.put_string("a", "some template")
+        l.put_string("b", """
+            <%namespace name='a' file='a' import='*'/>
+            % if x is UNDEFINED:
+                undefined
+            % else:
+                x: ${x}
+            % endif
+        """)
+
+        assert result_lines(t.render(x=12)) == ['x: 12']
+
+        assert_raises(
+            NameError,
+            t.render, y=12
+        )
+
+    def test_expression_declared(self):
+        t = Template("""
+            ${",".join([t for t in ("a", "b", "c")])}
+        """, strict_undefined=True)
+
+        eq_(result_lines(t.render()), ['a,b,c'])
+
+        t = Template("""
+            <%self:foo value="${[(val, n) for val, n in [(1, 2)]]}"/>
+
+            <%def name="foo(value)">
+                ${value}
+            </%def>
+
+        """, strict_undefined=True)
+
+        eq_(result_lines(t.render()), ['[(1, 2)]'])
+
+        t = Template("""
+            <%call expr="foo(value=[(val, n) for val, n in [(1, 2)]])" />
+
+            <%def name="foo(value)">
+                ${value}
+            </%def>
+
+        """, strict_undefined=True)
+
+        eq_(result_lines(t.render()), ['[(1, 2)]'])
+
+        l = TemplateLookup(strict_undefined=True)
+        l.put_string("i", "hi, ${pageargs['y']}")
+        l.put_string("t", """
+            <%include file="i" args="y=[x for x in range(3)]" />
+        """)
+        eq_(
+            result_lines(l.get_template("t").render()), ['hi, [0, 1, 2]']
+        )
+
+        l.put_string('q', """
+            <%namespace name="i" file="${(str([x for x in range(3)][2]) + 'i')[-1]}" />
+            ${i.body(y='x')}
+        """)
+        eq_(
+            result_lines(l.get_template("q").render()), ['hi, x']
+        )
+
+        t = Template("""
+            <%
+                y = lambda q: str(q)
+            %>
+            ${y('hi')}
+        """, strict_undefined=True)
+        eq_(
+            result_lines(t.render()), ["hi"]
+        )
+
+    def test_list_comprehensions_plus_undeclared_nonstrict(self):
+        # traditional behavior.  variable inside a list comprehension
+        # is treated as an "undefined", so is pulled from the context.
+        t = Template("""
+            t is: ${t}
+
+            ${",".join([t for t in ("a", "b", "c")])}
+        """)
+
+        eq_(
+            result_lines(t.render(t="T")),
+            ['t is: T', 'a,b,c']
+        )
+
+    def test_traditional_assignment_plus_undeclared(self):
+        t = Template("""
+            t is: ${t}
+
+            <%
+                t = 12
+            %>
+        """)
+        assert_raises(
+            UnboundLocalError,
+            t.render, t="T"
+        )
+
+    def test_list_comprehensions_plus_undeclared_strict(self):
+        # with strict, a list comprehension now behaves
+        # like the undeclared case above.
+        t = Template("""
+            t is: ${t}
+
+            ${",".join([t for t in ("a", "b", "c")])}
+        """, strict_undefined=True)
+
+        eq_(
+            result_lines(t.render(t="T")),
+            ['t is: T', 'a,b,c']
+        )
+
+class StopRenderingTest(TemplateTest):
+    def test_return_in_template(self):
+        t = Template("""
+           Line one
+           <% return STOP_RENDERING %>
+           Line Three
+        """, strict_undefined=True)
+
+        eq_(
+            result_lines(t.render()),
+            ['Line one']
+        )
+
+class ReservedNameTest(TemplateTest):
+    def test_names_on_context(self):
+        for name in ('context', 'loop', 'UNDEFINED', 'STOP_RENDERING'):
+            assert_raises_message(
+                exceptions.NameConflictError,
+                r"Reserved words passed to render\(\): %s" % name,
+                Template("x").render, **{name:'foo'}
+            )
+
+    def test_names_in_template(self):
+        for name in ('context', 'loop', 'UNDEFINED', 'STOP_RENDERING'):
+            assert_raises_message(
+                exceptions.NameConflictError,
+                r"Reserved words declared in template: %s" % name,
+                Template, "<%% %s = 5 %%>" % name
+            )
+
+    def test_exclude_loop_context(self):
+        self._do_memory_test(
+            "loop is ${loop}",
+            "loop is 5",
+            template_args=dict(loop=5),
+            enable_loop=False
+        )
+
+    def test_exclude_loop_template(self):
+        self._do_memory_test(
+            "<% loop = 12 %>loop is ${loop}",
+            "loop is 12",
+            enable_loop=False
+        )
+
+class ControlTest(TemplateTest):
+    def test_control(self):
+        t = Template("""
+    ## this is a template.
+    % for x in y:
+    %   if 'test' in x:
+        yes x has test
+    %   else:
+        no x does not have test
+    %endif
+    %endfor
+""")
+        assert result_lines(t.render(y=[{'test':'one'}, {'foo':'bar'}, {'foo':'bar', 'test':'two'}])) == [
+            "yes x has test",
+            "no x does not have test",
+            "yes x has test"
+        ]
+
+    def test_blank_control_1(self):
+        self._do_memory_test(
+            """
+            % if True:
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_2(self):
+        self._do_memory_test(
+            """
+            % if True:
+            % elif True:
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_3(self):
+        self._do_memory_test(
+            """
+            % if True:
+            % else:
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_4(self):
+        self._do_memory_test(
+            """
+            % if True:
+            % elif True:
+            % else:
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_5(self):
+        self._do_memory_test(
+            """
+            % for x in range(10):
+            % endfor
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_6(self):
+        self._do_memory_test(
+            """
+            % while False:
+            % endwhile
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_blank_control_7(self):
+        self._do_memory_test(
+            """
+            % try:
+            % except:
+            % endtry
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    @requires_python_26_or_greater
+    def test_blank_control_8(self):
+        self._do_memory_test(
+            """
+            % with ctx('x', 'w') as fp:
+            % endwith
+            """,
+            "",
+            filters=lambda s: s.strip(),
+            template_args={"ctx": ctx}
+        )
+
+    def test_commented_blank_control_1(self):
+        self._do_memory_test(
+            """
+            % if True:
+            ## comment
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_2(self):
+        self._do_memory_test(
+            """
+            % if True:
+            ## comment
+            % elif True:
+            ## comment
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_3(self):
+        self._do_memory_test(
+            """
+            % if True:
+            ## comment
+            % else:
+            ## comment
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_4(self):
+        self._do_memory_test(
+            """
+            % if True:
+            ## comment
+            % elif True:
+            ## comment
+            % else:
+            ## comment
+            % endif
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_5(self):
+        self._do_memory_test(
+            """
+            % for x in range(10):
+            ## comment
+            % endfor
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_6(self):
+        self._do_memory_test(
+            """
+            % while False:
+            ## comment
+            % endwhile
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    def test_commented_blank_control_7(self):
+        self._do_memory_test(
+            """
+            % try:
+            ## comment
+            % except:
+            ## comment
+            % endtry
+            """,
+            "",
+            filters=lambda s:s.strip()
+        )
+
+    @requires_python_26_or_greater
+    def test_commented_blank_control_8(self):
+        self._do_memory_test(
+            """
+            % with ctx('x', 'w') as fp:
+            ## comment
+            % endwith
+            """,
+            "",
+            filters=lambda s: s.strip(),
+            template_args={"ctx": ctx}
+        )
+
+    def test_multiline_control(self):
+        t = Template("""
+    % for x in \\
+        [y for y in [1,2,3]]:
+        ${x}
+    % endfor
+""")
+        #print t.code
+        assert flatten_result(t.render()) == "1 2 3"
+
+class GlobalsTest(TemplateTest):
+    def test_globals(self):
+        self._do_memory_test(
+            """
+                <%!
+                    y = "hi"
+                %>
+            y is ${y}
+            """,
+            "y is hi",
+            filters=lambda t:t.strip()
+        )
+
+class RichTracebackTest(TemplateTest):
+
+    def _do_test_traceback(self, utf8, memory, syntax):
+        if memory:
+            if syntax:
+                source = u('## coding: utf-8\n<% print "m’a réveillé. '\
+                        'Elle disait: « S’il vous plaît… dessine-moi un mouton! » %>')
+            else:
+                source = u('## coding: utf-8\n<% print u"m’a réveillé. '\
+                        'Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + str(5/0) %>')
+            if utf8:
+                source = source.encode('utf-8')
+            else:
+                source = source
+            templateargs = {'text': source}
+        else:
+            if syntax:
+                filename = 'unicode_syntax_error.html'
+            else:
+                filename = 'unicode_runtime_error.html'
+            source = util.read_file(self._file_path(filename), 'rb')
+            if not utf8:
+                source = source.decode('utf-8')
+            templateargs = {'filename': self._file_path(filename)}
+        try:
+            template = Template(**templateargs)
+            if not syntax:
+                template.render_unicode()
+            assert False
+        except Exception:
+            tback = exceptions.RichTraceback()
+            if utf8:
+                assert tback.source == source.decode('utf-8')
+            else:
+                assert tback.source == source
+
+for utf8 in (True, False):
+    for memory in (True, False):
+        for syntax in (True, False):
+            def _do_test(self):
+                self._do_test_traceback(utf8, memory, syntax)
+            name = 'test_%s_%s_%s' % (utf8 and 'utf8' or 'unicode',
+                                        memory and 'memory' or 'file',
+                                        syntax and 'syntax' or 'runtime')
+            _do_test.__name__ = name
+            setattr(RichTracebackTest, name, _do_test)
+            del _do_test
+
+class ModuleDirTest(TemplateTest):
+    def tearDown(self):
+        import shutil
+        shutil.rmtree(module_base, True)
+
+    def test_basic(self):
+        t = self._file_template("modtest.html")
+        t2 = self._file_template('subdir/modtest.html')
+
+        eq_(
+            t.module.__file__,
+            os.path.join(module_base, 'modtest.html.py')
+        )
+        eq_(
+            t2.module.__file__,
+            os.path.join(module_base, 'subdir', 'modtest.html.py')
+        )
+
+    def test_callable(self):
+        def get_modname(filename, uri):
+            return os.path.join(
+                        module_base,
+                        os.path.dirname(uri)[1:],
+                        'foo',
+                        os.path.basename(filename) + ".py")
+
+        lookup = TemplateLookup(template_base, modulename_callable=get_modname)
+        t = lookup.get_template('/modtest.html')
+        t2 = lookup.get_template('/subdir/modtest.html')
+        eq_(
+            t.module.__file__,
+            os.path.join(module_base, 'foo', 'modtest.html.py')
+        )
+        eq_(
+            t2.module.__file__,
+            os.path.join(module_base, 'subdir', 'foo', 'modtest.html.py')
+        )
+
+    def test_custom_writer(self):
+        canary = []
+        def write_module(source, outputpath):
+            f = open(outputpath, 'wb')
+            canary.append(outputpath)
+            f.write(source)
+            f.close()
+        lookup = TemplateLookup(template_base, module_writer=write_module,
+                                            module_directory=module_base)
+        t = lookup.get_template('/modtest.html')
+        t2 = lookup.get_template('/subdir/modtest.html')
+        eq_(
+            canary,
+            [os.path.join(module_base, "modtest.html.py"),
+            os.path.join(module_base, "subdir", "modtest.html.py")]
+        )
+
+class FilenameToURITest(TemplateTest):
+    def test_windows_paths(self):
+        """test that windows filenames are handled appropriately by Template."""
+
+        current_path = os.path
+        import ntpath
+        os.path = ntpath
+        try:
+            class NoCompileTemplate(Template):
+                def _compile_from_file(self, path, filename):
+                    self.path = path
+                    return Template("foo bar").module
+
+            t1 = NoCompileTemplate(
+                                    filename="c:\\foo\\template.html",
+                                    module_directory="c:\\modules\\")
+
+            eq_(t1.uri, "/foo/template.html")
+            eq_(t1.path, "c:\\modules\\foo\\template.html.py")
+
+            t1 = NoCompileTemplate(
+                                    filename="c:\\path\\to\\templates\\template.html",
+                                    uri = "/bar/template.html",
+                                    module_directory="c:\\modules\\")
+
+            eq_(t1.uri, "/bar/template.html")
+            eq_(t1.path, "c:\\modules\\bar\\template.html.py")
+
+        finally:
+            os.path = current_path
+
+    def test_posix_paths(self):
+        """test that posixs filenames are handled appropriately by Template."""
+
+        current_path = os.path
+        import posixpath
+        os.path = posixpath
+        try:
+            class NoCompileTemplate(Template):
+                def _compile_from_file(self, path, filename):
+                    self.path = path
+                    return Template("foo bar").module
+
+            t1 = NoCompileTemplate(
+                                    filename="/var/www/htdocs/includes/template.html",
+                                    module_directory="/var/lib/modules")
+
+            eq_(t1.uri, "/var/www/htdocs/includes/template.html")
+            eq_(t1.path, "/var/lib/modules/var/www/htdocs/includes/template.html.py")
+
+            t1 = NoCompileTemplate(
+                                    filename="/var/www/htdocs/includes/template.html",
+                                    uri = "/bar/template.html",
+                                    module_directory="/var/lib/modules")
+
+            eq_(t1.uri, "/bar/template.html")
+            eq_(t1.path, "/var/lib/modules/bar/template.html.py")
+
+        finally:
+            os.path = current_path
+
+    def test_dont_accept_relative_outside_of_root(self):
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+            "Template uri \"../../foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            Template, "test", uri="../../foo.html",
+        )
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+            "Template uri \"/../../foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            Template, "test", uri="/../../foo.html",
+        )
+
+        # normalizes in the root is OK
+        t = Template("test", uri="foo/bar/../../foo.html")
+        eq_(t.uri, "foo/bar/../../foo.html")
+
+
+class ModuleTemplateTest(TemplateTest):
+    def test_module_roundtrip(self):
+        lookup = TemplateLookup()
+
+        template = Template("""
+        <%inherit file="base.html"/>
+
+        % for x in range(5):
+            ${x}
+        % endfor
+""", lookup=lookup)
+
+        base = Template("""
+        This is base.
+        ${self.body()}
+""", lookup=lookup)
+
+        lookup.put_template("base.html", base)
+        lookup.put_template("template.html", template)
+
+        assert result_lines(template.render()) == [
+            "This is base.", "0", "1", "2", "3", "4"
+        ]
+
+        lookup = TemplateLookup()
+        template = ModuleTemplate(template.module, lookup=lookup)
+        base = ModuleTemplate(base.module, lookup=lookup)
+
+        lookup.put_template("base.html", base)
+        lookup.put_template("template.html", template)
+
+        assert result_lines(template.render()) == [
+            "This is base.", "0", "1", "2", "3", "4"
+        ]
+
+class TestTemplateAPI(unittest.TestCase):
+    def test_metadata(self):
+        t = Template("""
+Text
+Text
+% if bar:
+    ${expression}
+% endif
+
+<%include file='bar'/>
+
+""", uri="/some/template")
+        eq_(
+            ModuleInfo.get_module_source_metadata(t.code, full_line_map=True),
+            {
+                'full_line_map': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 5, 5, 7,
+                    8, 8, 8, 8, 8, 8, 8],
+                'source_encoding': 'ascii',
+                'filename': None,
+                'line_map': {35: 29, 15: 0, 22: 1, 23: 4, 24: 5, 25: 5,
+                             26: 5, 27: 7, 28: 8, 29: 8},
+                'uri': '/some/template'
+            }
+
+        )
+
+    def test_metadata_two(self):
+        t = Template("""
+Text
+Text
+% if bar:
+    ${expression}
+% endif
+
+    <%block name="foo">
+        hi block
+    </%block>
+
+
+""", uri="/some/template")
+        eq_(
+            ModuleInfo.get_module_source_metadata(t.code, full_line_map=True),
+            {
+                'full_line_map': [
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 5, 5, 7, 7,
+                    7, 7, 7, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8,
+                    8, 8, 8, 8, 8, 8, 8, 8],
+                'source_encoding': 'ascii',
+                'filename': None,
+                'line_map': {34: 10, 40: 8, 46: 8, 15: 0, 52: 46,
+                             24: 1, 25: 4, 26: 5, 27: 5, 28: 5, 29: 7},
+                'uri': '/some/template'}
+        )
+
+
+class PreprocessTest(TemplateTest):
+    def test_old_comments(self):
+        t = Template("""
+        im a template
+# old style comment
+    # more old style comment
+
+    ## new style comment
+    - # not a comment
+    - ## not a comment
+""", preprocessor=convert_comments)
+
+        assert flatten_result(t.render()) == "im a template - # not a comment - ## not a comment"
+
+class LexerTest(TemplateTest):
+    def _fixture(self):
+        from mako.parsetree import TemplateNode, Text
+        class MyLexer(object):
+            encoding = 'ascii'
+            def __init__(self, *arg, **kw):
+                pass
+
+            def parse(self):
+                t = TemplateNode("foo")
+                t.nodes.append(
+                    Text("hello world", source="foo", lineno=0,
+                            pos=0, filename=None)
+                )
+                return t
+        return MyLexer
+
+    def _test_custom_lexer(self, template):
+        eq_(
+            result_lines(template.render()),
+            ["hello world"]
+        )
+
+    def test_via_template(self):
+        t = Template("foo", lexer_cls=self._fixture())
+        self._test_custom_lexer(t)
+
+    def test_via_lookup(self):
+        tl = TemplateLookup(lexer_cls=self._fixture())
+        tl.put_string("foo", "foo")
+        t = tl.get_template("foo")
+        self._test_custom_lexer(t)
+
+class FuturesTest(TemplateTest):
+
+    def test_future_import(self):
+        t = Template("${ x / y }", future_imports=["division"])
+        assert result_lines(t.render(x=12, y=5)) == ["2.4"]
diff --git a/test/test_tgplugin.py b/test/test_tgplugin.py
new file mode 100644 (file)
index 0000000..3f548c4
--- /dev/null
@@ -0,0 +1,49 @@
+from mako.ext.turbogears import TGPlugin
+from test.util import result_lines
+from test import TemplateTest, template_base
+from mako import compat
+
+tl = TGPlugin(options=dict(directories=[template_base]), extension='html')
+
+class TestTGPlugin(TemplateTest):
+    def test_basic(self):
+        t = tl.load_template('/index.html')
+        assert result_lines(t.render()) == [
+            "this is index"
+        ]
+    def test_subdir(self):
+        t = tl.load_template('/subdir/index.html')
+        assert result_lines(t.render()) == [
+            "this is sub index",
+            "this is include 2"
+
+        ]
+
+        assert tl.load_template('/subdir/index.html').module_id == '_subdir_index_html'
+
+    def test_basic_dot(self):
+        t = tl.load_template('index')
+        assert result_lines(t.render()) == [
+            "this is index"
+        ]
+    def test_subdir_dot(self):
+        t = tl.load_template('subdir.index')
+        assert result_lines(t.render()) == [
+            "this is sub index",
+            "this is include 2"
+
+        ]
+
+        assert tl.load_template('subdir.index').module_id == '_subdir_index_html'
+
+    def test_string(self):
+        t = tl.load_template('foo', "hello world")
+        assert t.render() == "hello world"
+
+    def test_render(self):
+        assert result_lines(tl.render({}, template='/index.html')) == [
+            "this is index"
+        ]
+        assert result_lines(tl.render({}, template=compat.u('/index.html'))) == [
+            "this is index"
+        ]
diff --git a/test/test_util.py b/test/test_util.py
new file mode 100644 (file)
index 0000000..c8034a1
--- /dev/null
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+
+import os
+import unittest
+from mako import util, exceptions, compat
+from test import eq_, skip_if, assert_raises_message
+from mako.compat import u
+
+class UtilTest(unittest.TestCase):
+    def test_fast_buffer_write(self):
+        buf = util.FastEncodingBuffer()
+        buf.write("string a ")
+        buf.write("string b")
+        eq_(buf.getvalue(), "string a string b")
+
+    def test_fast_buffer_truncate(self):
+        buf = util.FastEncodingBuffer()
+        buf.write("string a ")
+        buf.write("string b")
+        buf.truncate()
+        buf.write("string c ")
+        buf.write("string d")
+        eq_(buf.getvalue(), "string c string d")
+
+    def test_fast_buffer_encoded(self):
+        s = u("drôl m’a rée « S’il")
+        buf = util.FastEncodingBuffer(encoding='utf-8')
+        buf.write(s[0:10])
+        buf.write(s[10:])
+        q = buf.getvalue()
+        eq_(buf.getvalue(), s.encode('utf-8'))
+
+    def test_read_file(self):
+        fn = os.path.join(os.path.dirname(__file__), 'test_util.py')
+        data = util.read_file(fn, 'rb')
+        assert 'test_util' in str(data)  # str() for py3k
+
+    @skip_if(lambda: compat.pypy, "Pypy does this differently")
+    def test_load_module(self):
+        fn = os.path.join(os.path.dirname(__file__), 'test_util.py')
+        module = compat.load_module('mako.template', fn)
+        import mako.template
+        self.assertEqual(module, mako.template)
+
+    def test_load_plugin_failure(self):
+        loader = util.PluginLoader("fakegroup")
+        assert_raises_message(
+            exceptions.RuntimeException,
+            "Can't load plugin fakegroup fake",
+            loader.load, "fake"
+        )
diff --git a/test/util.py b/test/util.py
new file mode 100644 (file)
index 0000000..605269f
--- /dev/null
@@ -0,0 +1,7 @@
+import re
+
+def flatten_result(result):
+    return re.sub(r'[\s\r\n]+', ' ', result).strip()
+
+def result_lines(result):
+    return [x.strip() for x in re.split(r'\r?\n', re.sub(r' +', ' ', result)) if x.strip() != '']
\ No newline at end of file