[Python-checkins] benchmarks: Add the chameleon benchmark from PyPy.

brett.cannon python-checkins at python.org
Tue Sep 25 17:00:25 CEST 2012


http://hg.python.org/benchmarks/rev/e2dd5d15cd78
changeset:   182:e2dd5d15cd78
user:        Brett Cannon <brett at python.org>
date:        Tue Sep 25 11:00:17 2012 -0400
summary:
  Add the chameleon benchmark from PyPy.

files:
  lib/Chameleon-2.9.2/.gitignore                                                             |    12 +
  lib/Chameleon-2.9.2/CHANGES.rst                                                            |  1075 ++++++
  lib/Chameleon-2.9.2/COPYRIGHT.txt                                                          |     7 +
  lib/Chameleon-2.9.2/LICENSE.txt                                                            |   185 +
  lib/Chameleon-2.9.2/Makefile                                                               |    89 +
  lib/Chameleon-2.9.2/PKG-INFO                                                               |  1122 ++++++
  lib/Chameleon-2.9.2/README.rst                                                             |    25 +
  lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py                                             |   128 +
  lib/Chameleon-2.9.2/benchmarks/bm_mako.py                                                  |   153 +
  lib/Chameleon-2.9.2/benchmarks/util.py                                                     |    51 +
  lib/Chameleon-2.9.2/distribute_setup.py                                                    |   485 ++
  lib/Chameleon-2.9.2/docs/conf.py                                                           |   194 +
  lib/Chameleon-2.9.2/docs/configuration.rst                                                 |    43 +
  lib/Chameleon-2.9.2/docs/index.rst                                                         |   217 +
  lib/Chameleon-2.9.2/docs/integration.rst                                                   |    41 +
  lib/Chameleon-2.9.2/docs/library.rst                                                       |   238 +
  lib/Chameleon-2.9.2/docs/reference.rst                                                     |  1695 ++++++++++
  lib/Chameleon-2.9.2/setup.cfg                                                              |    14 +
  lib/Chameleon-2.9.2/setup.py                                                               |    90 +
  lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO                                        |  1122 ++++++
  lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt                                     |   380 ++
  lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt                            |     1 +
  lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe                                    |     1 +
  lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt                                   |     1 +
  lib/Chameleon-2.9.2/src/chameleon/__init__.py                                              |     5 +
  lib/Chameleon-2.9.2/src/chameleon/ast24.py                                                 |   135 +
  lib/Chameleon-2.9.2/src/chameleon/astutil.py                                               |   926 +++++
  lib/Chameleon-2.9.2/src/chameleon/benchmark.py                                             |   478 ++
  lib/Chameleon-2.9.2/src/chameleon/codegen.py                                               |   221 +
  lib/Chameleon-2.9.2/src/chameleon/compiler.py                                              |  1553 +++++++++
  lib/Chameleon-2.9.2/src/chameleon/config.py                                                |    47 +
  lib/Chameleon-2.9.2/src/chameleon/exc.py                                                   |   289 +
  lib/Chameleon-2.9.2/src/chameleon/i18n.py                                                  |   120 +
  lib/Chameleon-2.9.2/src/chameleon/interfaces.py                                            |   102 +
  lib/Chameleon-2.9.2/src/chameleon/loader.py                                                |   174 +
  lib/Chameleon-2.9.2/src/chameleon/metal.py                                                 |    23 +
  lib/Chameleon-2.9.2/src/chameleon/namespaces.py                                            |     9 +
  lib/Chameleon-2.9.2/src/chameleon/nodes.py                                                 |   210 +
  lib/Chameleon-2.9.2/src/chameleon/parser.py                                                |   238 +
  lib/Chameleon-2.9.2/src/chameleon/program.py                                               |    38 +
  lib/Chameleon-2.9.2/src/chameleon/py25.py                                                  |    36 +
  lib/Chameleon-2.9.2/src/chameleon/py26.py                                                  |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tal.py                                                   |   479 ++
  lib/Chameleon-2.9.2/src/chameleon/tales.py                                                 |   541 +++
  lib/Chameleon-2.9.2/src/chameleon/template.py                                              |   332 +
  lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py                                        |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt                       |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt                       |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt                         |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt                              |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt                           |    18 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt                              |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt              |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt                |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt                             |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt                             |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt                            |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt                             |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt                          |    21 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt                        |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt                |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt                   |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt                 |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt                             |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt           |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt                              |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt                             |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt                   |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt                               |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt                            |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt                   |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt                    |    14 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt                      |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt                |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt                   |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt                        |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt                   |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt                      |    20 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt                    |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt                |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt             |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt     |     2 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt       |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt                    |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt                              |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt          |    20 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt               |    22 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt                |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt            |    19 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt                         |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml                                     |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt                           |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt                         |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt                   |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt               |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml                                     |   Bin 
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt      |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml                                     |   Bin 
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt               |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml                                     |   Bin 
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt       |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt                    |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml                                     |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt    |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt                    |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt                                |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt                               |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt                  |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml                                     |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt       |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt        |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt             |    27 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt                         |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt          |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt                    |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt                      |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt         |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt              |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt                 |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt                         |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt                        |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt                |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt                      |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt                    |    23 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt                        |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt               |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt                            |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt                   |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt               |     2 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt               |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml                                     |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt                   |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt                         |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt                          |    28 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt                      |     2 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml                                     |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html                      |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html                |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html                   |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt                                 |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt                              |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt                             |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html                                   |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt                                    |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt                                     |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt                                     |    18 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt                                     |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt                                     |    14 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt                                     |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt                                  |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt                                  |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt                                     |    22 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt                                     |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt                                  |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt                                  |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt                                     |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt                                  |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt                                     |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt                                  |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt                                     |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt                                     |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt                                     |    14 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt                                     |    23 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt                                     |    10 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt                                     |     0 
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt                                     |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt                                     |    12 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt                                     |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt                                     |     4 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt                                     |     7 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt                                     |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt                                     |    27 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt                                     |    13 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt                                     |     6 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt                                     |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt                                  |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt                                  |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt                                     |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt                                     |    19 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt                                     |    19 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt                                     |    17 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt                                  |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt                                     |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt                                     |    11 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt                                  |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt                                     |    16 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt                                     |     3 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt                                     |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt                                     |    15 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt                                  |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt                                     |     9 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt                                     |    18 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt                                     |    25 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt                                     |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html                                   |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html                                   |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html                                   |     8 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt                                |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt                             |     5 +
  lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt                            |     1 +
  lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py                                   |    40 +
  lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py                                     |    79 +
  lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py                                     |    92 +
  lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py                                   |   124 +
  lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py                                  |   679 ++++
  lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py                                  |    47 +
  lib/Chameleon-2.9.2/src/chameleon/tokenize.py                                              |   144 +
  lib/Chameleon-2.9.2/src/chameleon/utils.py                                                 |   429 ++
  lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py                                          |     1 +
  lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py                                            |    30 +
  lib/Chameleon-2.9.2/src/chameleon/zpt/program.py                                           |   751 ++++
  lib/Chameleon-2.9.2/src/chameleon/zpt/template.py                                          |   409 ++
  lib/Chameleon-2.9.2/src/ordereddict.py                                                     |   127 +
  lib/Chameleon-2.9.2/tox.ini                                                                |    53 +
  make_perf3.sh                                                                              |     9 +-
  perf.py                                                                                    |    16 +-
  performance/bm_chameleon.py                                                                |    40 +
  385 files changed, 18931 insertions(+), 3 deletions(-)


diff --git a/lib/Chameleon-2.9.2/.gitignore b/lib/Chameleon-2.9.2/.gitignore
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/.gitignore
@@ -0,0 +1,12 @@
+*.pyc
+*.egg
+*.egg-info
+.coverage
+.tox/
+coverage.xml
+nosetests.xml
+*.tar.gz
+env25/
+env26/
+env27/
+env32/
diff --git a/lib/Chameleon-2.9.2/CHANGES.rst b/lib/Chameleon-2.9.2/CHANGES.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/CHANGES.rst
@@ -0,0 +1,1075 @@
+Changes
+=======
+
+2.9.2 (2012-06-06)
+------------------
+
+Bugfixes:
+
+- Fixed a PyPy incompatibility.
+
+- Fixed issue #109 which caused testing failures on some platforms.
+
+2.9.1 (2012-06-01)
+------------------
+
+Bugfixes:
+
+- Fixed issue #103. The ``tal:on-error`` statement now always adds an
+  explicit end-tag to the element, even with a substitution content of
+  nothing.
+
+- Fixed issue #113. The ``tal:on-error`` statement now works correctly
+  also for dynamic attributes. That is, the fallback tag now includes
+  only static attributes.
+
+- Fixed name error which prevented the benchmark from running
+  correctly.
+
+Compatibility:
+
+- Fixed deprecation warning on Python 3 for zope interface implements
+  declaration. This fixes issue #116.
+
+2.9.0 (2012-05-31)
+------------------
+
+Features:
+
+- The translation function now gets the ``econtext`` argument as the
+  value for ``context``. Note that historically, this was usually an
+  HTTP request which might provide language negotiation data through a
+  dictionary interface.
+  [alvinyue]
+
+Bugfixes:
+
+- Fixed import alias issue which would lead to a syntax error in
+  generated Python code. Fixes issue #114.
+
+2.8.5 (2012-05-02)
+------------------
+
+Bugfixes:
+
+- Fixed minor installation issues on Python 2.5 and 3.
+  [ppaez]
+
+- Ensure output is unicode even when trivial (an empty string).
+
+2.8.4 (2012-04-18)
+------------------
+
+Features:
+
+- In exception output, long filenames are now truncated to 60
+  characters of output, preventing line wrap which makes it difficult
+  to scan the exception output.
+
+Bugfixes:
+
+- Include filename and location in exception output for exceptions
+  raised during compilation.
+
+- If a trivial translation substitution variable is given (i.e. an
+  empty string), simply ignore it. This fixes issue #106.
+
+2.8.3 (2012-04-16)
+------------------
+
+Features:
+
+- Log template source on debug-level before cooking.
+
+- The `target_language` argument, if given, is now available as a
+  variable in templates.
+
+2.8.2 (2012-03-30)
+------------------
+
+Features:
+
+- Temporary caches used in debug mode are cleaned up eagerly, rather
+  than waiting for process termination.
+  [mitchellrj]
+
+Bugfixes:
+
+- The `index`, `start` and `end` methods on the TAL repeat object are
+  now callable. This fixes an incompatibility with ZPT.
+
+- The loader now correctly handles absolute paths on Windows.
+  [rdale]
+
+2.8.1 (2012-03-29)
+------------------
+
+Features:
+
+- The exception formatter now lists errors in 'wrapping order'. This
+  means that the innermost, and presumably most relevant exception is
+  shown last.
+
+Bugfixes:
+
+- The exception formatter now correctly recognizes nested errors and
+  does not rewrap the dynamically generated exception class.
+
+- The exception formatter now correctly sets the ``__module__``
+  attribute to that of the original exception class.
+
+2.8.0 (2012-02-29)
+------------------
+
+Features:
+
+- Added support for code blocks using the `<?python ... ?>` processing
+  instruction syntax.
+
+  The scope is name assignments is up until the nearest macro
+  definition, or the template itself if macros are not used.
+
+Bugfixes:
+
+- Fall back to the exception class' ``__new__`` method to safely
+  create an exception object that is not implemented in Python.
+
+- The exception formatter now keeps track of already formatted
+  exceptions, and ignores them from further output.
+
+2.7.4 (2012-02-27)
+------------------
+
+- The error handler now invokes the ``__init__`` method of
+  ``BaseException`` instead of the possibly overriden method (which
+  may take required arguments). This fixes issue #97.
+  [j23d, malthe]
+
+2.7.3 (2012-01-16)
+------------------
+
+Bugfixes:
+
+- The trim whitespace option now correctly trims actual whitespace to
+  a single character, appearing either to the left or to the right of
+  an element prefix or suffix string.
+
+2.7.2 (2012-01-08)
+------------------
+
+Features:
+
+- Added option ``trim_attribute_space`` that decides whether attribute
+  whitespace is stripped (at most down to a single space). This option
+  exists to provide compatibility with the reference
+  implementation. Fixes issue #85.
+
+Bugfixes:
+
+- Ignore unhashable builtins when generating a reverse builtin
+  map to quickly look up a builtin value.
+  [malthe]
+
+- Apply translation mapping even when a translation function is not
+  available. This fixes issue #83.
+  [malthe]
+
+- Fixed issue #80. The translation domain for a slot is defined by the
+  source document, i.e. the template providing the content for a slot
+  whether it be the default or provided through ``metal:fill-slot``.
+  [jcbrand]
+
+- In certain circumstances, a Unicode non-breaking space character would cause
+  a define clause to fail to parse.
+
+2.7.1 (2011-12-29)
+------------------
+
+Features:
+
+- Enable expression interpolation in CDATA.
+
+- The page template class now implements dictionary access to macros::
+
+     template[name]
+
+  This is a short-hand for::
+
+     template.macros[name]
+
+Bugfixes:
+
+- An invalid define clause would be silently ignored; we now raise a
+  language error exception. This fixes issue #79.
+
+- Fixed regression where ``${...}`` interpolation expressions could
+  not span multiple lines. This fixes issue #77.
+
+2.7.0 (2011-12-13)
+------------------
+
+Features:
+
+- The ``load:`` expression now derives from the string expression such
+  that the ``${...}`` operator can be used for expression
+  interpolation.
+
+- The ``load:`` expression now accepts asset specs; these are resolved
+  by the ``pkg_resources.resource_filename`` function::
+
+    <package_name>:<path>
+
+  An example from the test suite::
+
+    chameleon:tests/inputs/hello_world.pt
+
+Bugfixes:
+
+- If an attribute name for translation was not a valid Python
+  identifier, the compiler would generate invalid code. This has been
+  fixed, and the compiler now also throws an exception if an attribute
+  specification contains a comma. (Note that the only valid separator
+  character is the semicolon, when specifying attributes for
+  translation via the ``i18n:translate`` statement). This addresses
+  issue #76.
+
+2.6.2 (2011-12-08)
+------------------
+
+Bugfixes:
+
+- Fixed issue where ``tal:on-error`` would not respect
+  ``tal:omit-tag`` or namespace elements which are omitted by default
+  (such as ``<tal:block />``).
+
+- Fixed issue where ``macros`` attribute would not be available on
+  file-based templates due to incorrect initialization.
+
+- The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+  Python 3.3. These have been aliased to ``Try``. This fixes issue
+  #75.
+
+Features:
+
+- The TAL repeat item now makes a security declaration that grants
+  access to unprotected subobjects on the Zope 2 platform::
+
+    __allow_access_to_unprotected_subobjects__ = True
+
+  This is required for legacy compatibility and does not affect other
+  environments.
+
+- The template object now has a method ``write(body)`` which
+  explicitly decodes and cooks a string input.
+
+- Added configuration option ``loader_class`` which sets the class
+  used to create the template loader object.
+
+  The class (essentially a callable) is created at template
+  construction time.
+
+2.6.1 (2011-11-30)
+------------------
+
+Bugfixes:
+
+- Decode HTML entities in expression interpolation strings. This fixes
+  issue #74.
+
+- Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+  namespace elements. This fixes issue #73.
+
+2.6.0 (2011-11-24)
+------------------
+
+Features:
+
+- Added support for implicit translation:
+
+  The ``implicit_i18n_translate`` option enables implicit translation
+  of text. The ``implicit_i18n_attributes`` enables implicit
+  translation of attributes. The latter must be a set and for an
+  attribute to be implicitly translated, its lowercase string value
+  must be included in the set.
+
+- Added option ``strict`` (enabled by default) which decides whether
+  expressions are required to be valid at compile time. That is, if
+  not set, an exception is only raised for an invalid expression at
+  evaluation time.
+
+- An expression error now results in an exception only if the
+  expression is attempted evaluated during a rendering.
+
+- Added a configuration option ``prepend_relative_search_path`` which
+  decides whether the path relative to a file-based template is
+  prepended to the load search path. The default is ``True``.
+
+- Added a configuration option ``search_path`` to the file-based
+  template class, which adds additional paths to the template load
+  instance bound to the ``load:`` expression. The option takes a
+  string path or an iterable yielding string paths. The default value
+  is the empty set.
+
+Bugfixes:
+
+- Exception instances now support pickle/unpickle.
+
+- An attributes in i18n:attributes no longer needs to match an
+  existing or dynamic attribute in order to appear in the
+  element. This fixes issue #66.
+
+2.5.3 (2011-10-23)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where a nested macro slot definition would fail even
+  though there existed a parent macro definition. This fixes issue
+  #69.
+
+2.5.2 (2011-10-12)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where technically invalid input would result in a
+  compiler error.
+
+Features:
+
+- The markup class now inherits from the unicode string type such that
+  it's compatible with the string interface.
+
+2.5.1 (2011-09-29)
+------------------
+
+Bugfixes:
+
+- The symbol names "convert", "decode" and "translate" are now no
+  longer set as read-only *compiler internals*. This fixes issue #65.
+
+- Fixed an issue where a macro extension chain nested two levels (a
+  template uses a macro that extends a macro) would lose the middle
+  slot definitions if slots were defined nested.
+
+  The compiler now throws an error if a nested slot definition is used
+  outside a macro extension context.
+
+2.5.0 (2011-09-23)
+------------------
+
+Features:
+
+- An expression type ``structure:`` is now available which wraps the
+  expression result as *structure* such that it is not escaped on
+  insertion, e.g.::
+
+    <div id="content">
+       ${structure: context.body}
+    </div>
+
+  This also means that the ``structure`` keyword for ``tal:content``
+  and ``tal:replace`` now has an alternative spelling via the
+  expression type ``structure:``.
+
+- The string-based template constructor now accepts encoded input.
+
+2.4.6 (2011-09-23)
+------------------
+
+Bugfixes:
+
+- The ``tal:on-error`` statement should catch all exceptions.
+
+- Fixed issue that would prevent escaping of interpolation expression
+  values appearing in text.
+
+2.4.5 (2011-09-21)
+------------------
+
+Bugfixes:
+
+- The ``tal:on-error`` handler should have a ``error`` variable
+  defined that has the value of the exception thrown.
+
+- The ``tal:on-error`` statement is a substitution statement and
+  should support the "text" and "structure" insertion methods.
+
+2.4.4 (2011-09-15)
+------------------
+
+Bugfixes:
+
+- An encoding specified in the XML document preamble is now read and
+  used to decode the template input to unicode. This fixes issue #55.
+
+- Encoded expression input on Python 3 is now correctly
+  decoded. Previously, the string representation output would be
+  included instead of an actually decoded string.
+
+- Expression result conversion steps are now correctly included in
+  error handling such that the exception output points to the
+  expression location.
+
+2.4.3 (2011-09-13)
+------------------
+
+Features:
+
+- When an encoding is provided, pass the 'ignore' flag to avoid
+  decoding issues with bad input.
+
+Bugfixes:
+
+- Fixed pypy compatibility issue (introduced in previous release).
+
+2.4.2 (2011-09-13)
+------------------
+
+Bugfixes:
+
+- Fixed an issue in the compiler where an internal variable (such as a
+  translation default value) would be cached, resulting in variable
+  scope corruption (see issue #49).
+
+2.4.1 (2011-09-08)
+------------------
+
+Bugfixes:
+
+- Fixed an issue where a default value for an attribute would
+  sometimes spill over into another attribute.
+
+- Fixed issue where the use of the ``default`` name in an attribute
+  interpolation expression would print the attribute value. This is
+  unexpected, because it's an expression, not a static text suitable
+  for output. An attribute value of ``default`` now correctly drops
+  the attribute.
+
+2.4.0 (2011-08-22)
+------------------
+
+Features:
+
+- Added an option ``boolean_attributes`` to evaluate and render a
+  provided set of attributes using a boolean logic: if the attribute
+  is a true value, the value will be the attribute name, otherwise the
+  attribute is dropped.
+
+  In the reference implementation, the following attributes are
+  configured as boolean values when the template is rendered in
+  HTML-mode::
+
+      "compact", "nowrap", "ismap", "declare", "noshade",
+      "checked", "disabled", "readonly", "multiple", "selected",
+      "noresize", "defer"
+
+  Note that in Chameleon, these attributes must be manually provided.
+
+Bugfixes:
+
+- The carriage return character (used on Windows platforms) would
+  incorrectly be included in Python comments.
+
+  It is now replaced with a line break.
+
+  This fixes issue #44.
+
+2.3.8 (2011-08-19)
+------------------
+
+- Fixed import error that affected Python 2.5 only.
+
+2.3.7 (2011-08-19)
+------------------
+
+Features:
+
+- Added an option ``literal_false`` that disables the default behavior
+  of dropping an attribute for a value of ``False`` (in addition to
+  ``None``). This modified behavior is the behavior exhibited in
+  reference implementation.
+
+Bugfixes:
+
+- Undo attribute special HTML attribute behavior (see previous
+  release).
+
+  This turned out not to be a compatible behavior; rather, boolean
+  values should simply be coerced to a string.
+
+  Meanwhile, the reference implementation does support an HTML mode in
+  which the special attribute behavior is exhibited.
+
+  We do not currently support this mode.
+
+2.3.6 (2011-08-18)
+------------------
+
+Features:
+
+- Certain HTML attribute names now have a special behavior for a
+  attribute value of ``True`` (or ``default`` if no default is
+  defined). For these attributes, this return value will result in the
+  name being printed as the value::
+
+    <input type="input" tal:attributes="checked True" />
+
+  will be rendered as::
+
+    <input type="input" checked="checked" />
+
+  This behavior is compatible with the reference implementation.
+
+2.3.5 (2011-08-18)
+------------------
+
+Features:
+
+- Added support for the set operator (``{item, item, ...}``).
+
+Bugfixes:
+
+- If macro is defined on the same element as a translation name, this
+  no longer results in a "translation name not allowed outside
+  translation" error. This fixes issue #43.
+
+- Attribute fallback to dictionary lookup now works on multiple items
+  (e.g. ``d1.d2.d2``). This fixes issue #42.
+
+2.3.4 (2011-08-16)
+------------------
+
+Features:
+
+- When inserting content in either attributes or text, a value of
+  ``True`` (like ``False`` and ``None``) will result in no
+  action.
+
+- Use statically assigned variables for ``"attrs"`` and
+  ``"default"``. This change yields a performance improvement of
+  15-20%.
+
+- The template loader class now accepts an optional argument
+  ``default_extension`` which accepts a filename extension which will
+  be appended to the filename if there's not already an extension.
+
+Bugfixes:
+
+- The default symbol is now ``True`` for an attribute if the attribute
+  default is not provided. Note that the result is that the attribute
+  is dropped. This fixes issue #41.
+
+- Fixed an issue where assignment to a variable ``"type"`` would
+  fail. This fixes issue #40.
+
+- Fixed an issue where an (unsuccesful) assignment for a repeat loop
+  to a compiler internal name would not result in an error.
+
+- If the translation function returns the identical object, manually
+  coerce it to string. This fixes a compatibility issue with
+  translation functions which do not convert non-string objects to a
+  string value, but simply return them unchanged.
+
+2.3.3 (2011-08-15)
+------------------
+
+Features:
+
+- The ``load:`` expression now passes the initial keyword arguments to
+  its template loader (e.g. ``auto_reload`` and ``encoding``).
+
+- In the exception output, string variable values are now limited to a
+  limited output of characters, single line only.
+
+Bugfixes:
+
+- Fixed horizontal alignment of exception location info
+  (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+  the template exception formatter.
+
+2.3.2 (2011-08-11)
+------------------
+
+Bugfixes:
+
+- Fixed issue where i18n:domain would not be inherited through macros
+  and slots. This fixes issue #37.
+
+2.3.1 (2011-08-11)
+------------------
+
+Features:
+
+- The ``Builtin`` node type may now be used to represent any Python
+  local or global name. This allows expression compilers to refer to
+  e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+  such as one from the ``extra_builtins`` dictionary.
+
+Bugfixes:
+
+- Builtins which are not explicitly disallowed may now be redefined
+  and used as variables (e.g. ``nothing``).
+
+- Fixed compiler issue with circular node annotation loop.
+
+2.3 (2011-08-10)
+----------------
+
+Features:
+
+- Added support for the following syntax to disable inline evaluation
+  in a comment:
+
+    <!--? comment appears verbatim (no ${...} evaluation) -->
+
+  Note that the initial question mark character (?) will be omitted
+  from output.
+
+- The parser now accepts '<' and '>' in attributes. Note that this is
+  invalid markup. Previously, the '<' would not be accepted as a valid
+  attribute value, but this would result in an 'unexpected end tag'
+  error elsewhere. This fixes issue #38.
+
+- The expression compiler now provides methods ``assign_text`` and
+  ``assign_value`` such that a template engine might configure this
+  value conversion to support e.g. encoded strings.
+
+  Note that currently, the only client for the ``assign_text`` method
+  is the string expression type.
+
+- Enable template loader for string-based template classes. Note that
+  the ``filename`` keyword argument may be provided on initialization
+  to identify the template source by filename. This fixes issue #36.
+
+- Added ``extra_builtins`` option to the page template class. These
+  builtins are added to the default builtins dictionary at cook time
+  and may be provided at initialization using the ``extra_builtins``
+  keyword argument.
+
+Bugfixes:
+
+- If a translation domain is set for a fill slot, use this setting
+  instead of the macro template domain.
+
+- The Python expression compiler now correctly decodes HTML entities
+  ``'gt'`` and ``'lt'``. This fixes issue #32.
+
+- The string expression compiler now correctly handles encoded text
+  (when support for encoded strings is enabled). This fixes issue #35.
+
+- Fixed an issue where setting the ``filename`` attribute on a
+  file-based template would not automatically cause an invalidation.
+
+- Exceptions raised by Chameleon can now be copied via
+  ``copy.copy``. This fixes issue #36.
+  [leorochael]
+
+- If copying the exception fails in the exception handler, simply
+  re-raise the original exception and log a warning.
+
+2.2 (2011-07-28)
+----------------
+
+Features:
+
+- Added new expression type ``load:`` that allows loading a
+  template. Both relative and absolute paths are supported. If the
+  path given is relative, then it will be resolved with respect to the
+  directory of the template.
+
+- Added support for dynamic evaluation of expressions.
+
+  Note that this is to support legacy applications. It is not
+  currently wired into the provided template classes.
+
+- Template classes now have a ``builtins`` attribute which may be used
+  to define built-in variables always available in the template
+  variable scope.
+
+Incompatibilities:
+
+- The file-based template class no longer accepts a parameter
+  ``loader``. This parameter would be used to load a template from a
+  relative path, using a ``find(filename)`` method. This was however,
+  undocumented, and probably not very useful since we have the
+  ``TemplateLoader`` mechanism already.
+
+- The compiled template module now contains an ``initialize`` function
+  which takes values that map to the template builtins. The return
+  value of this function is a dictionary that contains the render
+  functions.
+
+Bugfixes:
+
+- The file-based template class no longer verifies the existance of a
+  template file (using ``os.lstat``). This now happens implicitly if
+  eager parsing is enabled, or otherwise when first needed (e.g. at
+  render time).
+
+  This is classified as a bug fix because the previous behavior was
+  probably not what you'd expect, especially if an application
+  initializes a lot of templates without needing to render them
+  immediately.
+
+2.1.1 (2011-07-28)
+------------------
+
+Features:
+
+- Improved exception display. The expression string is now shown in
+  the context of the original source (if available) with a marker
+  string indicating the location of the expression in the template
+  source.
+
+Bugfixes:
+
+- The ``structure`` insertion mode now correctly decodes entities for
+  any expression type (including ``string:``). This fixes issue #30.
+
+- Don't show internal variables in the exception formatter variable
+  listing.
+
+2.1 (2011-07-25)
+----------------
+
+Features:
+
+- Expression interpolation (using the ``${...}`` operator and
+  previously also ``$identifier``) now requires braces everywhere
+  except inside the ``string:`` expression type.
+
+  This change is motivated by a number of legacy templates in which
+  the interpolation format without braces ``$identifier`` appears as
+  text.
+
+2.0.2 (2011-07-25)
+------------------
+
+Bugfixes:
+
+- Don't use dynamic variable scope for lambda-scoped variables (#27).
+
+- Avoid duplication of exception class and message in traceback.
+
+- Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+  was set to be used on the same element (#16).
+
+2.0.1 (2011-07-23)
+------------------
+
+Bugfixes:
+
+- Fixed issue where global variable definition from macro slots would
+  fail (they would instead be local). This also affects error
+  reporting from inside slots because this would be recorded
+  internally as a global.
+
+- Fixed issue with template cache digest (used for filenames); modules
+  are now invalidated whenever any changes are made to the
+  distribution set available (packages on ``sys.path``).
+
+- Fixed exception handler to better let exceptions propagate through
+  the renderer.
+
+- The disk-based module compiler now mangles template source filenames
+  such that the output Python module is valid and at root level (dots
+  and hyphens are replaced by an underscore). This fixes issue #17.
+
+- Fixed translations (i18n) on Python 2.5.
+
+2.0 (2011-07-14)
+----------------
+
+- Point release.
+
+2.0-rc14 (2011-07-13)
+---------------------
+
+Bugfixes:
+
+- The tab character (``\t``) is now parsed correctly when used inside
+  tags.
+
+Features:
+
+- The ``RepeatDict`` class now works as a proxy behind a seperate
+  dictionary instance.
+
+- Added template constructor option ``keep_body`` which is a flag
+  (also available as a class attribute) that controls whether to save
+  the template body input in the ``body`` attribute.
+
+  This is disabled by default, unless debug-mode is enabled.
+
+- The page template loader class now accepts an optional ``formats``
+  argument which can be used to select an alternative template class.
+
+2.0-rc13 (2011-07-07)
+---------------------
+
+Bugfixes:
+
+- The backslash character (followed by optional whitespace and a line
+  break) was not correctly interpreted as a continuation for Python
+  expressions.
+
+Features:
+
+- The Python expression implementation is now more flexible for
+  external subclassing via a new ``parse`` method.
+
+2.0-rc12 (2011-07-04)
+---------------------
+
+Bugfixes:
+
+- Initial keyword arguments passed to a template now no longer "leak"
+  into the template variable space after a macro call.
+
+- An unexpected end tag is now an unrecoverable error.
+
+Features:
+
+- Improve exception output.
+
+2.0-rc11 (2011-05-26)
+---------------------
+
+Bugfixes:
+
+- Fixed issue where variable names that begin with an underscore were
+  seemingly allowed, but their use resulted in a compiler error.
+
+Features:
+
+- Template variable names are now allowed to be prefixed with a single
+  underscore, but not two or more (reserved for internal use).
+
+  Examples of valid names::
+
+    item
+    ITEM
+    _item
+    camelCase
+    underscore_delimited
+    help
+
+- Added support for Genshi's comment "drop" syntax::
+
+    <!--! This comment will be dropped -->
+
+  Note the additional exclamation (!) character.
+
+  This fixes addresses issue #10.
+
+2.0-rc10 (2011-05-24)
+---------------------
+
+Bugfixes:
+
+- The ``tal:attributes`` statement now correctly operates
+  case-insensitive. The attribute name given in the statement will
+  replace an existing attribute with the same name, without respect to
+  case.
+
+Features:
+
+- Added ``meta:interpolation`` statement to control expression
+  interpolation setting.
+
+  Strings that disable the setting: ``"off"`` and ``"false"``.
+  Strings that enable the setting: ``"on"`` and ``"true"``.
+
+- Expression interpolation now works inside XML comments.
+
+2.0-rc9 (2011-05-05)
+--------------------
+
+Features:
+
+- Better debugging support for string decode and conversion. If a
+  naive join fails, each element in the output will now be attempted
+  coerced to unicode to try and trigger the failure near to the bad
+  string.
+
+2.0-rc8 (2011-04-11)
+--------------------
+
+Bugfixes:
+
+- If a macro defines two slots with the same name, a caller will now
+  fill both with a single usage.
+
+- If a valid of ``None`` is provided as the translation function
+  argument, we now fall back to the class default.
+
+2.0-rc7 (2011-03-29)
+--------------------
+
+Bugfixes:
+
+- Fixed issue with Python 2.5 compatibility AST. This affected at
+  least PyPy 1.4.
+
+Features:
+
+- The ``auto_reload`` setting now defaults to the class value; the
+  base template class gives a default value of
+  ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+  provide a custom default value (such as an application-specific
+  debug mode setting).
+
+
+2.0-rc6 (2011-03-19)
+--------------------
+
+Features:
+
+- Added support for ``target_language`` keyword argument to render
+  method. If provided, the argument will be curried onto the
+  translation function.
+
+Bugfixes:
+
+- The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+  subtition expressions are now translated into their native character
+  values. This fixes an issue where you could not dynamically create
+  elements using the ``structure`` (which is possible in ZPT). The
+  need to create such structure stems from the lack of an expression
+  interpolation operator in ZPT.
+
+- Fixed duplicate file pointer issue with test suite (affected Windows
+  platforms only). This fixes issue #9.
+  [oliora]
+
+- Use already open file using ``os.fdopen`` when trying to write out
+  the module source. This fixes LP #731803.
+
+
+2.0-rc5 (2011-03-07)
+--------------------
+
+Bugfixes:
+
+- Fixed a number of issues concerning the escaping of attribute
+  values:
+
+  1) Static attribute values are now included as they appear in the
+     source.
+
+     This means that invalid attribute values such as ``"true &&
+     false"`` are now left alone. It's not the job of the template
+     engine to correct such markup, at least not in the default mode
+     of operation.
+
+  2) The string expression compiler no longer unescapes
+     values. Instead, this is left to each expression
+     compiler. Currently only the Python expression compiler unescapes
+     its input.
+
+  3) The dynamic escape code sequence now correctly only replaces
+     ampersands that are part of an HTML escape format.
+
+Imports:
+
+- The page template classes and the loader class can now be imported
+  directly from the ``chameleon`` module.
+
+Features:
+
+- If a custom template loader is not provided, relative paths are now
+  resolved using ``os.abspath`` (i.e. to the current working
+  directory).
+
+- Absolute paths are normalized using ``os.path.normpath`` and
+  ``os.path.expanduser``. This ensures that all paths are kept in
+  their "canonical" form.
+
+
+2.0-rc4 (2011-03-03)
+--------------------
+
+Bugfixes:
+
+- Fixed an issue where the output of an end-to-end string expression
+  would raise an exception if the expression evaluated to ``None`` (it
+  should simply output nothing).
+
+- The ``convert`` function (which is configurable on the template
+  class level) now defaults to the ``translate`` function (at
+  run-time).
+
+  This fixes an issue where message objects were not translated (and
+  thus converted to a string) using the a provided ``translate``
+  function.
+
+- Fixed string interpolation issue where an expression immediately
+  succeeded by a right curly bracket would not parse.
+
+  This fixes issue #5.
+
+- Fixed error where ``tal:condition`` would be evaluated after
+  ``tal:repeat``.
+
+Features:
+
+- Python expression is now a TALES expression. That means that the
+  pipe operator can be used to chain two or more expressions in a
+  try-except sequence.
+
+  This behavior was ported from the 1.x series. Note that while it's
+  still possible to use the pipe character ("|") in an expression, it
+  must now be escaped.
+
+- The template cache can now be shared by multiple processes.
+
+
+2.0-rc3 (2011-03-02)
+--------------------
+
+Bugfixes:
+
+- Fixed ``atexit`` handler.
+
+  This fixes issue #3.
+
+- If a cache directory is specified, it will now be used even when not
+  in debug mode.
+
+- Allow "comment" attribute in the TAL namespace.
+
+  This fixes an issue in the sense that the reference engine allows
+  any attribute within the TAL namespace. However, only "comment" is
+  in common use.
+
+- The template constructor now accepts a flag ``debug`` which puts the
+  template *instance* into debug-mode regardless of the global
+  setting.
+
+  This fixes issue #1.
+
+Features:
+
+- Added exception handler for exceptions raised while evaluating an
+  expression.
+
+  This handler raises (or attempts to) a new exception of the type
+  ``RenderError``, with an additional base class of the original
+  exception class. The string value of the exception is a formatted
+  error message which includes the expression that caused the
+  exception.
+
+  If we are unable to create the exception class, the original
+  exception is re-raised.
+
+2.0-rc2 (2011-02-28)
+--------------------
+
+- Fixed upload issue.
+
+2.0-rc1 (2011-02-28)
+--------------------
+
+- Initial public release. See documentation for what's new in this
+  series.
diff --git a/lib/Chameleon-2.9.2/COPYRIGHT.txt b/lib/Chameleon-2.9.2/COPYRIGHT.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/COPYRIGHT.txt
@@ -0,0 +1,7 @@
+Copyright (c) 2011 Malthe Borch and Contributors. All Rights Reserved.
+
+Portions (c) Zope Foundation and contributors (http://www.zope.org/).
+
+Portions (c) Edgewall Software.
+
+Portions (c) 2008 Armin Ronacher.
diff --git a/lib/Chameleon-2.9.2/LICENSE.txt b/lib/Chameleon-2.9.2/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/LICENSE.txt
@@ -0,0 +1,185 @@
+The majority of the code in Chameleon is supplied under this license:
+
+  A copyright notice accompanies this license document that identifies
+  the copyright holders.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+  1.  Redistributions in source code must retain the accompanying
+      copyright notice, this list of conditions, and the following
+      disclaimer.
+
+  2.  Redistributions in binary form must reproduce the accompanying
+      copyright notice, this list of conditions, and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+  3.  Names of the copyright holders must not be used to endorse or
+      promote products derived from this software without prior
+      written permission from the copyright holders.
+
+  4.  If any files are modified, you must cause the modified files to
+      carry prominent notices stating that you changed the files and
+      the date of any change.
+
+  Disclaimer
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND
+    ANY EXPRESSED 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 COPYRIGHT
+    HOLDERS 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.
+
+Portions of the code in Chameleon are supplied under the ZPL (headers
+within individiual files indicate that these portions are licensed
+under the ZPL):
+
+  Zope Public License (ZPL) Version 2.1
+  -------------------------------------
+
+  A copyright notice accompanies this license document that
+  identifies the copyright holders.
+
+  This license has been certified as open source. It has also
+  been designated as GPL compatible by the Free Software
+  Foundation (FSF).
+
+  Redistribution and use in source and binary forms, with or
+  without modification, are permitted provided that the
+  following conditions are met:
+
+  1. Redistributions in source code must retain the
+     accompanying copyright notice, this list of conditions,
+     and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the accompanying
+     copyright notice, this list of conditions, and the
+     following disclaimer in the documentation and/or other
+     materials provided with the distribution.
+
+  3. Names of the copyright holders must not be used to
+     endorse or promote products derived from this software
+     without prior written permission from the copyright
+     holders.
+
+  4. The right to distribute this software or to use it for
+     any purpose does not give you the right to use
+     Servicemarks (sm) or Trademarks (tm) of the copyright
+     holders. Use of them is covered by separate agreement
+     with the copyright holders.
+
+  5. If any files are modified, you must cause the modified
+     files to carry prominent notices stating that you changed
+     the files and the date of any change.
+
+  Disclaimer
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+    AND ANY EXPRESSED 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 COPYRIGHT HOLDERS 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.
+
+Portions of the code in Chameleon are supplied under the BSD license
+(headers within individiual files indicate that these portions are
+licensed under this license):
+
+  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.
+
+
+Portions of the code in Chameleon are supplied under the Python
+License (headers within individiual files indicate that these portions
+are licensed under this license):
+
+  PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+  --------------------------------------------
+
+  1. This LICENSE AGREEMENT is between the Python Software Foundation
+  ("PSF"), and the Individual or Organization ("Licensee") accessing and
+  otherwise using this software ("Python") in source or binary form and
+  its associated documentation.
+
+  2. Subject to the terms and conditions of this License Agreement, PSF
+  hereby grants Licensee a nonexclusive, royalty-free, world-wide
+  license to reproduce, analyze, test, perform and/or display publicly,
+  prepare derivative works, distribute, and otherwise use Python
+  alone or in any derivative version, provided, however, that PSF's
+  License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+  2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved"
+  are retained in Python alone or in any derivative version prepared
+  by Licensee.
+
+  3. In the event Licensee prepares a derivative work that is based on
+  or incorporates Python or any part thereof, and wants to make
+  the derivative work available to others as provided herein, then
+  Licensee hereby agrees to include in any such work a brief summary of
+  the changes made to Python.
+
+  4. PSF is making Python available to Licensee on an "AS IS"
+  basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+  IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+  DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+  FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+  INFRINGE ANY THIRD PARTY RIGHTS.
+
+  5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+  FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+  A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+  OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+  6. This License Agreement will automatically terminate upon a material
+  breach of its terms and conditions.
+
+  7. Nothing in this License Agreement shall be deemed to create any
+  relationship of agency, partnership, or joint venture between PSF and
+  Licensee.  This License Agreement does not grant permission to use PSF
+  trademarks or trade name in a trademark sense to endorse or promote
+  products or services of Licensee, or any third party.
+
+  8. By copying, installing or otherwise using Python, Licensee
+  agrees to be bound by the terms and conditions of this License
+  Agreement.
diff --git a/lib/Chameleon-2.9.2/Makefile b/lib/Chameleon-2.9.2/Makefile
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/Makefile
@@ -0,0 +1,89 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    = docs
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# 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 pickle json htmlhelp qthelp latex changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html      to make standalone HTML files"
+	@echo "  dirhtml   to make HTML files named index.html in directories"
+	@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 "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@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 $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+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/Chameleon.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Chameleon.qhc"
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+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) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/lib/Chameleon-2.9.2/PKG-INFO b/lib/Chameleon-2.9.2/PKG-INFO
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/PKG-INFO
@@ -0,0 +1,1122 @@
+Metadata-Version: 1.1
+Name: Chameleon
+Version: 2.9.2
+Summary: Fast HTML/XML Template Compiler.
+Home-page: http://www.pagetemplates.org/
+Author: Malthe Borch
+Author-email: mborch at gmail.com
+License: BSD-like (http://repoze.org/license.html)
+Description: Overview
+        ========
+        
+        Chameleon is an HTML/XML template engine for `Python
+        <http://www.python.org>`_. It uses the *page templates* language.
+        
+        You can use it in any Python web application with just about any
+        version of Python (2.5 and up, including 3.x and `pypy
+        <http://pypy.org>`_).
+        
+        Visit the `website <http://pagetemplates.org>`_ for more information
+        or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+        
+        License and Copyright
+        ---------------------
+        
+        This software is made available as-is under a BSD-like license [1]_
+        (see included copyright notice).
+        
+        
+        Notes
+        -----
+        
+        .. [1] This software is licensed under the `Repoze
+               <http://repoze.org/license.html>`_ license.
+        
+        
+        Changes
+        =======
+        
+        2.9.2 (2012-06-06)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed a PyPy incompatibility.
+        
+        - Fixed issue #109 which caused testing failures on some platforms.
+        
+        2.9.1 (2012-06-01)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue #103. The ``tal:on-error`` statement now always adds an
+          explicit end-tag to the element, even with a substitution content of
+          nothing.
+        
+        - Fixed issue #113. The ``tal:on-error`` statement now works correctly
+          also for dynamic attributes. That is, the fallback tag now includes
+          only static attributes.
+        
+        - Fixed name error which prevented the benchmark from running
+          correctly.
+        
+        Compatibility:
+        
+        - Fixed deprecation warning on Python 3 for zope interface implements
+          declaration. This fixes issue #116.
+        
+        2.9.0 (2012-05-31)
+        ------------------
+        
+        Features:
+        
+        - The translation function now gets the ``econtext`` argument as the
+          value for ``context``. Note that historically, this was usually an
+          HTTP request which might provide language negotiation data through a
+          dictionary interface.
+          [alvinyue]
+        
+        Bugfixes:
+        
+        - Fixed import alias issue which would lead to a syntax error in
+          generated Python code. Fixes issue #114.
+        
+        2.8.5 (2012-05-02)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed minor installation issues on Python 2.5 and 3.
+          [ppaez]
+        
+        - Ensure output is unicode even when trivial (an empty string).
+        
+        2.8.4 (2012-04-18)
+        ------------------
+        
+        Features:
+        
+        - In exception output, long filenames are now truncated to 60
+          characters of output, preventing line wrap which makes it difficult
+          to scan the exception output.
+        
+        Bugfixes:
+        
+        - Include filename and location in exception output for exceptions
+          raised during compilation.
+        
+        - If a trivial translation substitution variable is given (i.e. an
+          empty string), simply ignore it. This fixes issue #106.
+        
+        2.8.3 (2012-04-16)
+        ------------------
+        
+        Features:
+        
+        - Log template source on debug-level before cooking.
+        
+        - The `target_language` argument, if given, is now available as a
+          variable in templates.
+        
+        2.8.2 (2012-03-30)
+        ------------------
+        
+        Features:
+        
+        - Temporary caches used in debug mode are cleaned up eagerly, rather
+          than waiting for process termination.
+          [mitchellrj]
+        
+        Bugfixes:
+        
+        - The `index`, `start` and `end` methods on the TAL repeat object are
+          now callable. This fixes an incompatibility with ZPT.
+        
+        - The loader now correctly handles absolute paths on Windows.
+          [rdale]
+        
+        2.8.1 (2012-03-29)
+        ------------------
+        
+        Features:
+        
+        - The exception formatter now lists errors in 'wrapping order'. This
+          means that the innermost, and presumably most relevant exception is
+          shown last.
+        
+        Bugfixes:
+        
+        - The exception formatter now correctly recognizes nested errors and
+          does not rewrap the dynamically generated exception class.
+        
+        - The exception formatter now correctly sets the ``__module__``
+          attribute to that of the original exception class.
+        
+        2.8.0 (2012-02-29)
+        ------------------
+        
+        Features:
+        
+        - Added support for code blocks using the `<?python ... ?>` processing
+          instruction syntax.
+        
+          The scope is name assignments is up until the nearest macro
+          definition, or the template itself if macros are not used.
+        
+        Bugfixes:
+        
+        - Fall back to the exception class' ``__new__`` method to safely
+          create an exception object that is not implemented in Python.
+        
+        - The exception formatter now keeps track of already formatted
+          exceptions, and ignores them from further output.
+        
+        2.7.4 (2012-02-27)
+        ------------------
+        
+        - The error handler now invokes the ``__init__`` method of
+          ``BaseException`` instead of the possibly overriden method (which
+          may take required arguments). This fixes issue #97.
+          [j23d, malthe]
+        
+        2.7.3 (2012-01-16)
+        ------------------
+        
+        Bugfixes:
+        
+        - The trim whitespace option now correctly trims actual whitespace to
+          a single character, appearing either to the left or to the right of
+          an element prefix or suffix string.
+        
+        2.7.2 (2012-01-08)
+        ------------------
+        
+        Features:
+        
+        - Added option ``trim_attribute_space`` that decides whether attribute
+          whitespace is stripped (at most down to a single space). This option
+          exists to provide compatibility with the reference
+          implementation. Fixes issue #85.
+        
+        Bugfixes:
+        
+        - Ignore unhashable builtins when generating a reverse builtin
+          map to quickly look up a builtin value.
+          [malthe]
+        
+        - Apply translation mapping even when a translation function is not
+          available. This fixes issue #83.
+          [malthe]
+        
+        - Fixed issue #80. The translation domain for a slot is defined by the
+          source document, i.e. the template providing the content for a slot
+          whether it be the default or provided through ``metal:fill-slot``.
+          [jcbrand]
+        
+        - In certain circumstances, a Unicode non-breaking space character would cause
+          a define clause to fail to parse.
+        
+        2.7.1 (2011-12-29)
+        ------------------
+        
+        Features:
+        
+        - Enable expression interpolation in CDATA.
+        
+        - The page template class now implements dictionary access to macros::
+        
+             template[name]
+        
+          This is a short-hand for::
+        
+             template.macros[name]
+        
+        Bugfixes:
+        
+        - An invalid define clause would be silently ignored; we now raise a
+          language error exception. This fixes issue #79.
+        
+        - Fixed regression where ``${...}`` interpolation expressions could
+          not span multiple lines. This fixes issue #77.
+        
+        2.7.0 (2011-12-13)
+        ------------------
+        
+        Features:
+        
+        - The ``load:`` expression now derives from the string expression such
+          that the ``${...}`` operator can be used for expression
+          interpolation.
+        
+        - The ``load:`` expression now accepts asset specs; these are resolved
+          by the ``pkg_resources.resource_filename`` function::
+        
+            <package_name>:<path>
+        
+          An example from the test suite::
+        
+            chameleon:tests/inputs/hello_world.pt
+        
+        Bugfixes:
+        
+        - If an attribute name for translation was not a valid Python
+          identifier, the compiler would generate invalid code. This has been
+          fixed, and the compiler now also throws an exception if an attribute
+          specification contains a comma. (Note that the only valid separator
+          character is the semicolon, when specifying attributes for
+          translation via the ``i18n:translate`` statement). This addresses
+          issue #76.
+        
+        2.6.2 (2011-12-08)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where ``tal:on-error`` would not respect
+          ``tal:omit-tag`` or namespace elements which are omitted by default
+          (such as ``<tal:block />``).
+        
+        - Fixed issue where ``macros`` attribute would not be available on
+          file-based templates due to incorrect initialization.
+        
+        - The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+          Python 3.3. These have been aliased to ``Try``. This fixes issue
+          #75.
+        
+        Features:
+        
+        - The TAL repeat item now makes a security declaration that grants
+          access to unprotected subobjects on the Zope 2 platform::
+        
+            __allow_access_to_unprotected_subobjects__ = True
+        
+          This is required for legacy compatibility and does not affect other
+          environments.
+        
+        - The template object now has a method ``write(body)`` which
+          explicitly decodes and cooks a string input.
+        
+        - Added configuration option ``loader_class`` which sets the class
+          used to create the template loader object.
+        
+          The class (essentially a callable) is created at template
+          construction time.
+        
+        2.6.1 (2011-11-30)
+        ------------------
+        
+        Bugfixes:
+        
+        - Decode HTML entities in expression interpolation strings. This fixes
+          issue #74.
+        
+        - Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+          namespace elements. This fixes issue #73.
+        
+        2.6.0 (2011-11-24)
+        ------------------
+        
+        Features:
+        
+        - Added support for implicit translation:
+        
+          The ``implicit_i18n_translate`` option enables implicit translation
+          of text. The ``implicit_i18n_attributes`` enables implicit
+          translation of attributes. The latter must be a set and for an
+          attribute to be implicitly translated, its lowercase string value
+          must be included in the set.
+        
+        - Added option ``strict`` (enabled by default) which decides whether
+          expressions are required to be valid at compile time. That is, if
+          not set, an exception is only raised for an invalid expression at
+          evaluation time.
+        
+        - An expression error now results in an exception only if the
+          expression is attempted evaluated during a rendering.
+        
+        - Added a configuration option ``prepend_relative_search_path`` which
+          decides whether the path relative to a file-based template is
+          prepended to the load search path. The default is ``True``.
+        
+        - Added a configuration option ``search_path`` to the file-based
+          template class, which adds additional paths to the template load
+          instance bound to the ``load:`` expression. The option takes a
+          string path or an iterable yielding string paths. The default value
+          is the empty set.
+        
+        Bugfixes:
+        
+        - Exception instances now support pickle/unpickle.
+        
+        - An attributes in i18n:attributes no longer needs to match an
+          existing or dynamic attribute in order to appear in the
+          element. This fixes issue #66.
+        
+        2.5.3 (2011-10-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where a nested macro slot definition would fail even
+          though there existed a parent macro definition. This fixes issue
+          #69.
+        
+        2.5.2 (2011-10-12)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where technically invalid input would result in a
+          compiler error.
+        
+        Features:
+        
+        - The markup class now inherits from the unicode string type such that
+          it's compatible with the string interface.
+        
+        2.5.1 (2011-09-29)
+        ------------------
+        
+        Bugfixes:
+        
+        - The symbol names "convert", "decode" and "translate" are now no
+          longer set as read-only *compiler internals*. This fixes issue #65.
+        
+        - Fixed an issue where a macro extension chain nested two levels (a
+          template uses a macro that extends a macro) would lose the middle
+          slot definitions if slots were defined nested.
+        
+          The compiler now throws an error if a nested slot definition is used
+          outside a macro extension context.
+        
+        2.5.0 (2011-09-23)
+        ------------------
+        
+        Features:
+        
+        - An expression type ``structure:`` is now available which wraps the
+          expression result as *structure* such that it is not escaped on
+          insertion, e.g.::
+        
+            <div id="content">
+               ${structure: context.body}
+            </div>
+        
+          This also means that the ``structure`` keyword for ``tal:content``
+          and ``tal:replace`` now has an alternative spelling via the
+          expression type ``structure:``.
+        
+        - The string-based template constructor now accepts encoded input.
+        
+        2.4.6 (2011-09-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - The ``tal:on-error`` statement should catch all exceptions.
+        
+        - Fixed issue that would prevent escaping of interpolation expression
+          values appearing in text.
+        
+        2.4.5 (2011-09-21)
+        ------------------
+        
+        Bugfixes:
+        
+        - The ``tal:on-error`` handler should have a ``error`` variable
+          defined that has the value of the exception thrown.
+        
+        - The ``tal:on-error`` statement is a substitution statement and
+          should support the "text" and "structure" insertion methods.
+        
+        2.4.4 (2011-09-15)
+        ------------------
+        
+        Bugfixes:
+        
+        - An encoding specified in the XML document preamble is now read and
+          used to decode the template input to unicode. This fixes issue #55.
+        
+        - Encoded expression input on Python 3 is now correctly
+          decoded. Previously, the string representation output would be
+          included instead of an actually decoded string.
+        
+        - Expression result conversion steps are now correctly included in
+          error handling such that the exception output points to the
+          expression location.
+        
+        2.4.3 (2011-09-13)
+        ------------------
+        
+        Features:
+        
+        - When an encoding is provided, pass the 'ignore' flag to avoid
+          decoding issues with bad input.
+        
+        Bugfixes:
+        
+        - Fixed pypy compatibility issue (introduced in previous release).
+        
+        2.4.2 (2011-09-13)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue in the compiler where an internal variable (such as a
+          translation default value) would be cached, resulting in variable
+          scope corruption (see issue #49).
+        
+        2.4.1 (2011-09-08)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where a default value for an attribute would
+          sometimes spill over into another attribute.
+        
+        - Fixed issue where the use of the ``default`` name in an attribute
+          interpolation expression would print the attribute value. This is
+          unexpected, because it's an expression, not a static text suitable
+          for output. An attribute value of ``default`` now correctly drops
+          the attribute.
+        
+        2.4.0 (2011-08-22)
+        ------------------
+        
+        Features:
+        
+        - Added an option ``boolean_attributes`` to evaluate and render a
+          provided set of attributes using a boolean logic: if the attribute
+          is a true value, the value will be the attribute name, otherwise the
+          attribute is dropped.
+        
+          In the reference implementation, the following attributes are
+          configured as boolean values when the template is rendered in
+          HTML-mode::
+        
+              "compact", "nowrap", "ismap", "declare", "noshade",
+              "checked", "disabled", "readonly", "multiple", "selected",
+              "noresize", "defer"
+        
+          Note that in Chameleon, these attributes must be manually provided.
+        
+        Bugfixes:
+        
+        - The carriage return character (used on Windows platforms) would
+          incorrectly be included in Python comments.
+        
+          It is now replaced with a line break.
+        
+          This fixes issue #44.
+        
+        2.3.8 (2011-08-19)
+        ------------------
+        
+        - Fixed import error that affected Python 2.5 only.
+        
+        2.3.7 (2011-08-19)
+        ------------------
+        
+        Features:
+        
+        - Added an option ``literal_false`` that disables the default behavior
+          of dropping an attribute for a value of ``False`` (in addition to
+          ``None``). This modified behavior is the behavior exhibited in
+          reference implementation.
+        
+        Bugfixes:
+        
+        - Undo attribute special HTML attribute behavior (see previous
+          release).
+        
+          This turned out not to be a compatible behavior; rather, boolean
+          values should simply be coerced to a string.
+        
+          Meanwhile, the reference implementation does support an HTML mode in
+          which the special attribute behavior is exhibited.
+        
+          We do not currently support this mode.
+        
+        2.3.6 (2011-08-18)
+        ------------------
+        
+        Features:
+        
+        - Certain HTML attribute names now have a special behavior for a
+          attribute value of ``True`` (or ``default`` if no default is
+          defined). For these attributes, this return value will result in the
+          name being printed as the value::
+        
+            <input type="input" tal:attributes="checked True" />
+        
+          will be rendered as::
+        
+            <input type="input" checked="checked" />
+        
+          This behavior is compatible with the reference implementation.
+        
+        2.3.5 (2011-08-18)
+        ------------------
+        
+        Features:
+        
+        - Added support for the set operator (``{item, item, ...}``).
+        
+        Bugfixes:
+        
+        - If macro is defined on the same element as a translation name, this
+          no longer results in a "translation name not allowed outside
+          translation" error. This fixes issue #43.
+        
+        - Attribute fallback to dictionary lookup now works on multiple items
+          (e.g. ``d1.d2.d2``). This fixes issue #42.
+        
+        2.3.4 (2011-08-16)
+        ------------------
+        
+        Features:
+        
+        - When inserting content in either attributes or text, a value of
+          ``True`` (like ``False`` and ``None``) will result in no
+          action.
+        
+        - Use statically assigned variables for ``"attrs"`` and
+          ``"default"``. This change yields a performance improvement of
+          15-20%.
+        
+        - The template loader class now accepts an optional argument
+          ``default_extension`` which accepts a filename extension which will
+          be appended to the filename if there's not already an extension.
+        
+        Bugfixes:
+        
+        - The default symbol is now ``True`` for an attribute if the attribute
+          default is not provided. Note that the result is that the attribute
+          is dropped. This fixes issue #41.
+        
+        - Fixed an issue where assignment to a variable ``"type"`` would
+          fail. This fixes issue #40.
+        
+        - Fixed an issue where an (unsuccesful) assignment for a repeat loop
+          to a compiler internal name would not result in an error.
+        
+        - If the translation function returns the identical object, manually
+          coerce it to string. This fixes a compatibility issue with
+          translation functions which do not convert non-string objects to a
+          string value, but simply return them unchanged.
+        
+        2.3.3 (2011-08-15)
+        ------------------
+        
+        Features:
+        
+        - The ``load:`` expression now passes the initial keyword arguments to
+          its template loader (e.g. ``auto_reload`` and ``encoding``).
+        
+        - In the exception output, string variable values are now limited to a
+          limited output of characters, single line only.
+        
+        Bugfixes:
+        
+        - Fixed horizontal alignment of exception location info
+          (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+          the template exception formatter.
+        
+        2.3.2 (2011-08-11)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where i18n:domain would not be inherited through macros
+          and slots. This fixes issue #37.
+        
+        2.3.1 (2011-08-11)
+        ------------------
+        
+        Features:
+        
+        - The ``Builtin`` node type may now be used to represent any Python
+          local or global name. This allows expression compilers to refer to
+          e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+          such as one from the ``extra_builtins`` dictionary.
+        
+        Bugfixes:
+        
+        - Builtins which are not explicitly disallowed may now be redefined
+          and used as variables (e.g. ``nothing``).
+        
+        - Fixed compiler issue with circular node annotation loop.
+        
+        2.3 (2011-08-10)
+        ----------------
+        
+        Features:
+        
+        - Added support for the following syntax to disable inline evaluation
+          in a comment:
+        
+            <!--? comment appears verbatim (no ${...} evaluation) -->
+        
+          Note that the initial question mark character (?) will be omitted
+          from output.
+        
+        - The parser now accepts '<' and '>' in attributes. Note that this is
+          invalid markup. Previously, the '<' would not be accepted as a valid
+          attribute value, but this would result in an 'unexpected end tag'
+          error elsewhere. This fixes issue #38.
+        
+        - The expression compiler now provides methods ``assign_text`` and
+          ``assign_value`` such that a template engine might configure this
+          value conversion to support e.g. encoded strings.
+        
+          Note that currently, the only client for the ``assign_text`` method
+          is the string expression type.
+        
+        - Enable template loader for string-based template classes. Note that
+          the ``filename`` keyword argument may be provided on initialization
+          to identify the template source by filename. This fixes issue #36.
+        
+        - Added ``extra_builtins`` option to the page template class. These
+          builtins are added to the default builtins dictionary at cook time
+          and may be provided at initialization using the ``extra_builtins``
+          keyword argument.
+        
+        Bugfixes:
+        
+        - If a translation domain is set for a fill slot, use this setting
+          instead of the macro template domain.
+        
+        - The Python expression compiler now correctly decodes HTML entities
+          ``'gt'`` and ``'lt'``. This fixes issue #32.
+        
+        - The string expression compiler now correctly handles encoded text
+          (when support for encoded strings is enabled). This fixes issue #35.
+        
+        - Fixed an issue where setting the ``filename`` attribute on a
+          file-based template would not automatically cause an invalidation.
+        
+        - Exceptions raised by Chameleon can now be copied via
+          ``copy.copy``. This fixes issue #36.
+          [leorochael]
+        
+        - If copying the exception fails in the exception handler, simply
+          re-raise the original exception and log a warning.
+        
+        2.2 (2011-07-28)
+        ----------------
+        
+        Features:
+        
+        - Added new expression type ``load:`` that allows loading a
+          template. Both relative and absolute paths are supported. If the
+          path given is relative, then it will be resolved with respect to the
+          directory of the template.
+        
+        - Added support for dynamic evaluation of expressions.
+        
+          Note that this is to support legacy applications. It is not
+          currently wired into the provided template classes.
+        
+        - Template classes now have a ``builtins`` attribute which may be used
+          to define built-in variables always available in the template
+          variable scope.
+        
+        Incompatibilities:
+        
+        - The file-based template class no longer accepts a parameter
+          ``loader``. This parameter would be used to load a template from a
+          relative path, using a ``find(filename)`` method. This was however,
+          undocumented, and probably not very useful since we have the
+          ``TemplateLoader`` mechanism already.
+        
+        - The compiled template module now contains an ``initialize`` function
+          which takes values that map to the template builtins. The return
+          value of this function is a dictionary that contains the render
+          functions.
+        
+        Bugfixes:
+        
+        - The file-based template class no longer verifies the existance of a
+          template file (using ``os.lstat``). This now happens implicitly if
+          eager parsing is enabled, or otherwise when first needed (e.g. at
+          render time).
+        
+          This is classified as a bug fix because the previous behavior was
+          probably not what you'd expect, especially if an application
+          initializes a lot of templates without needing to render them
+          immediately.
+        
+        2.1.1 (2011-07-28)
+        ------------------
+        
+        Features:
+        
+        - Improved exception display. The expression string is now shown in
+          the context of the original source (if available) with a marker
+          string indicating the location of the expression in the template
+          source.
+        
+        Bugfixes:
+        
+        - The ``structure`` insertion mode now correctly decodes entities for
+          any expression type (including ``string:``). This fixes issue #30.
+        
+        - Don't show internal variables in the exception formatter variable
+          listing.
+        
+        2.1 (2011-07-25)
+        ----------------
+        
+        Features:
+        
+        - Expression interpolation (using the ``${...}`` operator and
+          previously also ``$identifier``) now requires braces everywhere
+          except inside the ``string:`` expression type.
+        
+          This change is motivated by a number of legacy templates in which
+          the interpolation format without braces ``$identifier`` appears as
+          text.
+        
+        2.0.2 (2011-07-25)
+        ------------------
+        
+        Bugfixes:
+        
+        - Don't use dynamic variable scope for lambda-scoped variables (#27).
+        
+        - Avoid duplication of exception class and message in traceback.
+        
+        - Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+          was set to be used on the same element (#16).
+        
+        2.0.1 (2011-07-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where global variable definition from macro slots would
+          fail (they would instead be local). This also affects error
+          reporting from inside slots because this would be recorded
+          internally as a global.
+        
+        - Fixed issue with template cache digest (used for filenames); modules
+          are now invalidated whenever any changes are made to the
+          distribution set available (packages on ``sys.path``).
+        
+        - Fixed exception handler to better let exceptions propagate through
+          the renderer.
+        
+        - The disk-based module compiler now mangles template source filenames
+          such that the output Python module is valid and at root level (dots
+          and hyphens are replaced by an underscore). This fixes issue #17.
+        
+        - Fixed translations (i18n) on Python 2.5.
+        
+        2.0 (2011-07-14)
+        ----------------
+        
+        - Point release.
+        
+        2.0-rc14 (2011-07-13)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The tab character (``\t``) is now parsed correctly when used inside
+          tags.
+        
+        Features:
+        
+        - The ``RepeatDict`` class now works as a proxy behind a seperate
+          dictionary instance.
+        
+        - Added template constructor option ``keep_body`` which is a flag
+          (also available as a class attribute) that controls whether to save
+          the template body input in the ``body`` attribute.
+        
+          This is disabled by default, unless debug-mode is enabled.
+        
+        - The page template loader class now accepts an optional ``formats``
+          argument which can be used to select an alternative template class.
+        
+        2.0-rc13 (2011-07-07)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The backslash character (followed by optional whitespace and a line
+          break) was not correctly interpreted as a continuation for Python
+          expressions.
+        
+        Features:
+        
+        - The Python expression implementation is now more flexible for
+          external subclassing via a new ``parse`` method.
+        
+        2.0-rc12 (2011-07-04)
+        ---------------------
+        
+        Bugfixes:
+        
+        - Initial keyword arguments passed to a template now no longer "leak"
+          into the template variable space after a macro call.
+        
+        - An unexpected end tag is now an unrecoverable error.
+        
+        Features:
+        
+        - Improve exception output.
+        
+        2.0-rc11 (2011-05-26)
+        ---------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where variable names that begin with an underscore were
+          seemingly allowed, but their use resulted in a compiler error.
+        
+        Features:
+        
+        - Template variable names are now allowed to be prefixed with a single
+          underscore, but not two or more (reserved for internal use).
+        
+          Examples of valid names::
+        
+            item
+            ITEM
+            _item
+            camelCase
+            underscore_delimited
+            help
+        
+        - Added support for Genshi's comment "drop" syntax::
+        
+            <!--! This comment will be dropped -->
+        
+          Note the additional exclamation (!) character.
+        
+          This fixes addresses issue #10.
+        
+        2.0-rc10 (2011-05-24)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The ``tal:attributes`` statement now correctly operates
+          case-insensitive. The attribute name given in the statement will
+          replace an existing attribute with the same name, without respect to
+          case.
+        
+        Features:
+        
+        - Added ``meta:interpolation`` statement to control expression
+          interpolation setting.
+        
+          Strings that disable the setting: ``"off"`` and ``"false"``.
+          Strings that enable the setting: ``"on"`` and ``"true"``.
+        
+        - Expression interpolation now works inside XML comments.
+        
+        2.0-rc9 (2011-05-05)
+        --------------------
+        
+        Features:
+        
+        - Better debugging support for string decode and conversion. If a
+          naive join fails, each element in the output will now be attempted
+          coerced to unicode to try and trigger the failure near to the bad
+          string.
+        
+        2.0-rc8 (2011-04-11)
+        --------------------
+        
+        Bugfixes:
+        
+        - If a macro defines two slots with the same name, a caller will now
+          fill both with a single usage.
+        
+        - If a valid of ``None`` is provided as the translation function
+          argument, we now fall back to the class default.
+        
+        2.0-rc7 (2011-03-29)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed issue with Python 2.5 compatibility AST. This affected at
+          least PyPy 1.4.
+        
+        Features:
+        
+        - The ``auto_reload`` setting now defaults to the class value; the
+          base template class gives a default value of
+          ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+          provide a custom default value (such as an application-specific
+          debug mode setting).
+        
+        
+        2.0-rc6 (2011-03-19)
+        --------------------
+        
+        Features:
+        
+        - Added support for ``target_language`` keyword argument to render
+          method. If provided, the argument will be curried onto the
+          translation function.
+        
+        Bugfixes:
+        
+        - The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+          subtition expressions are now translated into their native character
+          values. This fixes an issue where you could not dynamically create
+          elements using the ``structure`` (which is possible in ZPT). The
+          need to create such structure stems from the lack of an expression
+          interpolation operator in ZPT.
+        
+        - Fixed duplicate file pointer issue with test suite (affected Windows
+          platforms only). This fixes issue #9.
+          [oliora]
+        
+        - Use already open file using ``os.fdopen`` when trying to write out
+          the module source. This fixes LP #731803.
+        
+        
+        2.0-rc5 (2011-03-07)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed a number of issues concerning the escaping of attribute
+          values:
+        
+          1) Static attribute values are now included as they appear in the
+             source.
+        
+             This means that invalid attribute values such as ``"true &&
+             false"`` are now left alone. It's not the job of the template
+             engine to correct such markup, at least not in the default mode
+             of operation.
+        
+          2) The string expression compiler no longer unescapes
+             values. Instead, this is left to each expression
+             compiler. Currently only the Python expression compiler unescapes
+             its input.
+        
+          3) The dynamic escape code sequence now correctly only replaces
+             ampersands that are part of an HTML escape format.
+        
+        Imports:
+        
+        - The page template classes and the loader class can now be imported
+          directly from the ``chameleon`` module.
+        
+        Features:
+        
+        - If a custom template loader is not provided, relative paths are now
+          resolved using ``os.abspath`` (i.e. to the current working
+          directory).
+        
+        - Absolute paths are normalized using ``os.path.normpath`` and
+          ``os.path.expanduser``. This ensures that all paths are kept in
+          their "canonical" form.
+        
+        
+        2.0-rc4 (2011-03-03)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where the output of an end-to-end string expression
+          would raise an exception if the expression evaluated to ``None`` (it
+          should simply output nothing).
+        
+        - The ``convert`` function (which is configurable on the template
+          class level) now defaults to the ``translate`` function (at
+          run-time).
+        
+          This fixes an issue where message objects were not translated (and
+          thus converted to a string) using the a provided ``translate``
+          function.
+        
+        - Fixed string interpolation issue where an expression immediately
+          succeeded by a right curly bracket would not parse.
+        
+          This fixes issue #5.
+        
+        - Fixed error where ``tal:condition`` would be evaluated after
+          ``tal:repeat``.
+        
+        Features:
+        
+        - Python expression is now a TALES expression. That means that the
+          pipe operator can be used to chain two or more expressions in a
+          try-except sequence.
+        
+          This behavior was ported from the 1.x series. Note that while it's
+          still possible to use the pipe character ("|") in an expression, it
+          must now be escaped.
+        
+        - The template cache can now be shared by multiple processes.
+        
+        
+        2.0-rc3 (2011-03-02)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed ``atexit`` handler.
+        
+          This fixes issue #3.
+        
+        - If a cache directory is specified, it will now be used even when not
+          in debug mode.
+        
+        - Allow "comment" attribute in the TAL namespace.
+        
+          This fixes an issue in the sense that the reference engine allows
+          any attribute within the TAL namespace. However, only "comment" is
+          in common use.
+        
+        - The template constructor now accepts a flag ``debug`` which puts the
+          template *instance* into debug-mode regardless of the global
+          setting.
+        
+          This fixes issue #1.
+        
+        Features:
+        
+        - Added exception handler for exceptions raised while evaluating an
+          expression.
+        
+          This handler raises (or attempts to) a new exception of the type
+          ``RenderError``, with an additional base class of the original
+          exception class. The string value of the exception is a formatted
+          error message which includes the expression that caused the
+          exception.
+        
+          If we are unable to create the exception class, the original
+          exception is re-raised.
+        
+        2.0-rc2 (2011-02-28)
+        --------------------
+        
+        - Fixed upload issue.
+        
+        2.0-rc1 (2011-02-28)
+        --------------------
+        
+        - Initial public release. See documentation for what's new in this
+          series.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
diff --git a/lib/Chameleon-2.9.2/README.rst b/lib/Chameleon-2.9.2/README.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/README.rst
@@ -0,0 +1,25 @@
+Overview
+========
+
+Chameleon is an HTML/XML template engine for `Python
+<http://www.python.org>`_. It uses the *page templates* language.
+
+You can use it in any Python web application with just about any
+version of Python (2.5 and up, including 3.x and `pypy
+<http://pypy.org>`_).
+
+Visit the `website <http://pagetemplates.org>`_ for more information
+or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+
+License and Copyright
+---------------------
+
+This software is made available as-is under a BSD-like license [1]_
+(see included copyright notice).
+
+
+Notes
+-----
+
+.. [1] This software is licensed under the `Repoze
+       <http://repoze.org/license.html>`_ license.
diff --git a/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py b/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/bm_chameleon.py
@@ -0,0 +1,128 @@
+#!/usr/bin/python2
+
+"""
+Benchmark for test the performance of Chameleon page template engine.
+"""
+
+__author__ = "mborch at gmail.com (Malthe Borch)"
+
+# Python imports
+import os
+import sys
+import optparse
+import time
+
+# Local imports
+import util
+
+
+def relative(*args):
+    return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
+
+sys.path.insert(0, relative('..', 'src'))
+
+# Chameleon imports
+from chameleon import PageTemplate
+
+
+LOREM_IPSUM = """Quisque lobortis hendrerit posuere. Curabitur
+aliquet consequat sapien molestie pretium. Nunc adipiscing luc
+tus mi, viverra porttitor lorem vulputate et. Ut at purus sem,
+sed tincidunt ante. Vestibulum ante ipsum primis in faucibus
+orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar
+sodales justo at congue. Praesent aliquet facilisis nisl a
+molestie. Sed tempus nisl ut augue eleifend tincidunt. Sed a
+lacinia nulla. Cras tortor est, mollis et consequat at,
+vulputate et orci. Nulla sollicitudin"""
+
+BASE_TEMPLATE = '''
+<tal:macros condition="False">
+    <table metal:define-macro="table">
+       <tr tal:repeat="row table">
+          <td tal:repeat="col row">${col}</td>
+       </tr>
+    </table>
+    <img metal:define-macro="img" src="${src}" alt="${alt}" />
+</tal:macros>
+<html metal:define-macro="master">
+    <head><title>${title.strip()}</title></head>
+    <body metal:define-slot="body" />
+</html>
+'''
+
+PAGE_TEMPLATE = '''
+<html metal:define-macro="master" metal:extend-macro="base.macros['master']">
+<body metal:fill-slot="body">
+<table metal:use-macro="base.macros['table']" />
+images:
+<tal:images repeat="nr xrange(img_count)">
+    <img tal:define="src '/foo/bar/baz.png';
+                     alt 'no image :o'"
+         metal:use-macro="base.macros['img']" />
+</tal:images>
+<metal:body define-slot="body" />
+<p tal:repeat="nr paragraphs">${lorem}</p>
+<table metal:use-macro="base.macros['table']" />
+</body>
+</html>
+'''
+
+CONTENT_TEMPLATE = '''
+<html metal:use-macro="page.macros['master']">
+<span metal:define-macro="fun1">fun1</span>
+<span metal:define-macro="fun2">fun2</span>
+<span metal:define-macro="fun3">fun3</span>
+<span metal:define-macro="fun4">fun4</span>
+<span metal:define-macro="fun5">fun5</span>
+<span metal:define-macro="fun6">fun6</span>
+<body metal:fill-slot="body">
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Nam laoreet justo in velit faucibus lobortis. Sed dictum sagittis
+volutpat. Sed adipiscing vestibulum consequat. Nullam laoreet, ante
+nec pretium varius, libero arcu porttitor orci, id cursus odio nibh
+nec leo. Vestibulum dapibus pellentesque purus, sed bibendum tortor
+laoreet id. Praesent quis sodales ipsum. Fusce ut ligula sed diam
+pretium sagittis vel at ipsum. Nulla sagittis sem quam, et volutpat
+velit. Fusce dapibus ligula quis lectus ultricies tempor. Pellente</p>
+<span metal:use-macro="template.macros['fun1']" />
+<span metal:use-macro="template.macros['fun2']" />
+<span metal:use-macro="template.macros['fun3']" />
+<span metal:use-macro="template.macros['fun4']" />
+<span metal:use-macro="template.macros['fun5']" />
+<span metal:use-macro="template.macros['fun6']" />
+</body>
+</html>
+'''
+
+
+def test_mako(count):
+    template = PageTemplate(CONTENT_TEMPLATE)
+    base = PageTemplate(BASE_TEMPLATE)
+    page = PageTemplate(PAGE_TEMPLATE)
+
+    table = [xrange(150) for i in xrange(150)]
+    paragraphs = xrange(50)
+    title = 'Hello world!'
+
+    times = []
+    for i in range(count):
+        t0 = time.time()
+        data = template.render(
+            table=table, paragraphs=paragraphs,
+            lorem=LOREM_IPSUM, title=title,
+            img_count=50,
+            base=base,
+            page=page,
+            )
+        t1 = time.time()
+        times.append(t1-t0)
+    return times
+
+if __name__ == "__main__":
+    parser = optparse.OptionParser(
+        usage="%prog [options]",
+        description=("Test the performance of Chameleon templates."))
+    util.add_standard_options_to(parser)
+    (options, args) = parser.parse_args()
+
+    util.run_benchmark(options, options.num_runs, test_mako)
diff --git a/lib/Chameleon-2.9.2/benchmarks/bm_mako.py b/lib/Chameleon-2.9.2/benchmarks/bm_mako.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/bm_mako.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+
+"""
+Benchmark for test the performance of Mako templates engine.
+Includes:
+    -two template inherences
+    -HTML escaping, XML escaping, URL escaping, whitespace trimming
+    -function defitions and calls
+    -forloops
+"""
+
+__author__ = "virhilo at gmail.com (Lukasz Fidosz)"
+
+# Python imports
+import os
+import sys
+import optparse
+import time
+
+# Local imports
+import util
+
+def relative(*args):
+    return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
+
+sys.path.insert(0, relative('..', 'lib'))
+
+# Mako imports
+from mako.template import Template
+from mako.lookup import TemplateLookup
+
+
+LOREM_IPSUM = """Quisque lobortis hendrerit posuere. Curabitur
+aliquet consequat sapien molestie pretium. Nunc adipiscing luc
+tus mi, viverra porttitor lorem vulputate et. Ut at purus sem,
+sed tincidunt ante. Vestibulum ante ipsum primis in faucibus 
+orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar
+sodales justo at congue. Praesent aliquet facilisis nisl a
+molestie. Sed tempus nisl ut augue eleifend tincidunt. Sed a
+lacinia nulla. Cras tortor est, mollis et consequat at,
+vulputate et orci. Nulla sollicitudin"""
+
+BASE_TEMPLATE = """
+<%def name="render_table(table)">
+    <table>
+    % for row in table:
+        <tr>
+        % for col in row:
+            <td>${col|h}</td>
+        % endfor
+        </tr>
+    % endfor
+    </table>
+</%def>
+<%def name="img(src, alt)">
+    <img src="${src|u}" alt="${alt}" />
+</%def>
+<html>
+    <head><title>${title|h,trim}</title></head>
+    <body>
+        ${next.body()}
+    </body>
+<html>
+"""
+
+PAGE_TEMPLATE = """
+<%inherit file="base.mako"/>
+<table>
+    % for row in table:
+        <tr>
+            % for col in row:
+                <td>${col}</td>
+            % endfor
+        </tr>
+    % endfor
+</table>
+% for nr in xrange(img_count):
+    ${parent.img('/foo/bar/baz.png', 'no image :o')}
+% endfor
+${next.body()}
+% for nr in paragraphs:
+    <p>${lorem|x}</p>
+% endfor
+${parent.render_table(table)}
+"""
+
+CONTENT_TEMPLATE = """
+<%inherit file="page.mako"/>
+<%def name="fun1()">
+    <span>fun1</span>
+</%def>
+<%def name="fun2()">
+    <span>fun2</span>
+</%def>
+<%def name="fun3()">
+    <span>foo3</span>
+</%def>
+<%def name="fun4()">
+    <span>foo4</span>
+</%def>
+<%def name="fun5()">
+    <span>foo5</span>
+</%def>
+<%def name="fun6()">
+    <span>foo6</span>
+</%def>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Nam laoreet justo in velit faucibus lobortis. Sed dictum sagittis
+volutpat. Sed adipiscing vestibulum consequat. Nullam laoreet, ante
+nec pretium varius, libero arcu porttitor orci, id cursus odio nibh
+nec leo. Vestibulum dapibus pellentesque purus, sed bibendum tortor
+laoreet id. Praesent quis sodales ipsum. Fusce ut ligula sed diam
+pretium sagittis vel at ipsum. Nulla sagittis sem quam, et volutpat
+velit. Fusce dapibus ligula quis lectus ultricies tempor. Pellente</p>
+${fun1()}
+${fun2()}
+${fun3()}
+${fun4()}
+${fun5()}
+${fun6()}
+"""
+
+
+def test_mako(count):
+
+    lookup = TemplateLookup()
+    lookup.put_string('base.mako', BASE_TEMPLATE)
+    lookup.put_string('page.mako', PAGE_TEMPLATE)
+
+    template = Template(CONTENT_TEMPLATE, lookup=lookup)
+    
+    table = [xrange(150) for i in xrange(150)]
+    paragraphs = xrange(50)
+    title = 'Hello world!'
+
+    times = []
+    for i in range(count):
+        t0 = time.time()
+        data = template.render(table=table, paragraphs=paragraphs,
+                               lorem=LOREM_IPSUM, title=title,
+                               img_count=50)
+        t1 = time.time()
+        times.append(t1-t0)
+    return times
+
+if __name__ == "__main__":
+    parser = optparse.OptionParser(
+        usage="%prog [options]",
+        description=("Test the performance of Mako templates."))
+    util.add_standard_options_to(parser)
+    (options, args) = parser.parse_args()
+
+    util.run_benchmark(options, options.num_runs, test_mako)
diff --git a/lib/Chameleon-2.9.2/benchmarks/util.py b/lib/Chameleon-2.9.2/benchmarks/util.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/benchmarks/util.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+"""Utility code for benchmark scripts."""
+
+__author__ = "collinwinter at google.com (Collin Winter)"
+
+import math
+import operator
+
+
+def run_benchmark(options, num_runs, bench_func, *args):
+    """Run the given benchmark, print results to stdout.
+
+    Args:
+        options: optparse.Values instance.
+        num_runs: number of times to run the benchmark
+        bench_func: benchmark function. `num_runs, *args` will be passed to this
+            function. This should return a list of floats (benchmark execution
+            times).
+    """
+    if options.profile:
+        import cProfile
+        prof = cProfile.Profile()
+        prof.runcall(bench_func, num_runs, *args)
+        prof.print_stats(sort=options.profile_sort)
+    else:
+        data = bench_func(num_runs, *args)
+        if options.take_geo_mean:
+            product = reduce(operator.mul, data, 1)
+            print math.pow(product, 1.0 / len(data))
+        else:
+            for x in data:
+                print x
+
+
+def add_standard_options_to(parser):
+    """Add a bunch of common command-line flags to an existing OptionParser.
+
+    This function operates on `parser` in-place.
+
+    Args:
+        parser: optparse.OptionParser instance.
+    """
+    parser.add_option("-n", action="store", type="int", default=100,
+                      dest="num_runs", help="Number of times to run the test.")
+    parser.add_option("--profile", action="store_true",
+                      help="Run the benchmark through cProfile.")
+    parser.add_option("--profile_sort", action="store", type="str",
+                      default="time", help="Column to sort cProfile output by.")
+    parser.add_option("--take_geo_mean", action="store_true",
+                      help="Return the geo mean, rather than individual data.")
diff --git a/lib/Chameleon-2.9.2/distribute_setup.py b/lib/Chameleon-2.9.2/distribute_setup.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/distribute_setup.py
@@ -0,0 +1,485 @@
+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from distribute_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+    from site import USER_SITE
+except ImportError:
+    USER_SITE = None
+
+try:
+    import subprocess
+
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        return subprocess.call(args) == 0
+
+except ImportError:
+    # will be used for python 2.3
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        # quoting arguments if windows
+        if sys.platform == 'win32':
+            def quote(arg):
+                if ' ' in arg:
+                    return '"%s"' % arg
+                return arg
+            args = [quote(arg) for arg in args]
+        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.14"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # installing
+        log.warn('Installing Distribute')
+        if not _python_cmd('setup.py', 'install'):
+            log.warn('Something went wrong during the installation.')
+            log.warn('See the error message above.')
+    finally:
+        os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # building an egg
+        log.warn('Building a Distribute egg in %s', to_dir)
+        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+    finally:
+        os.chdir(old_wd)
+    # returning the result
+    log.warn(egg)
+    if not os.path.exists(egg):
+        raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+                       % (version, sys.version_info[0], sys.version_info[1]))
+    if not os.path.exists(egg):
+        tarball = download_setuptools(version, download_base,
+                                      to_dir, download_delay)
+        _build_egg(egg, tarball, to_dir)
+    sys.path.insert(0, egg)
+    import setuptools
+    setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                   to_dir=os.curdir, download_delay=15, no_fake=True):
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    was_imported = 'pkg_resources' in sys.modules or \
+        'setuptools' in sys.modules
+    try:
+        try:
+            import pkg_resources
+            if not hasattr(pkg_resources, '_distribute'):
+                if not no_fake:
+                    _fake_setuptools()
+                raise ImportError
+        except ImportError:
+            return _do_download(version, download_base, to_dir, download_delay)
+        try:
+            pkg_resources.require("distribute>="+version)
+            return
+        except pkg_resources.VersionConflict:
+            e = sys.exc_info()[1]
+            if was_imported:
+                sys.stderr.write(
+                "The required version of distribute (>=%s) is not available,\n"
+                "and can't be installed while this script is running. Please\n"
+                "install a more recent version first, using\n"
+                "'easy_install -U distribute'."
+                "\n\n(Currently using %r)\n" % (version, e.args[0]))
+                sys.exit(2)
+            else:
+                del pkg_resources, sys.modules['pkg_resources']    # reload ok
+                return _do_download(version, download_base, to_dir,
+                                    download_delay)
+        except pkg_resources.DistributionNotFound:
+            return _do_download(version, download_base, to_dir,
+                                download_delay)
+    finally:
+        if not no_fake:
+            _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                        to_dir=os.curdir, delay=15):
+    """Download distribute from a specified location and return its filename
+
+    `version` should be a valid distribute version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download
+    attempt.
+    """
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    try:
+        from urllib.request import urlopen
+    except ImportError:
+        from urllib2 import urlopen
+    tgz_name = "distribute-%s.tar.gz" % version
+    url = download_base + tgz_name
+    saveto = os.path.join(to_dir, tgz_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            log.warn("Downloading %s", url)
+            src = urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = src.read()
+            dst = open(saveto, "wb")
+            dst.write(data)
+        finally:
+            if src:
+                src.close()
+            if dst:
+                dst.close()
+    return os.path.realpath(saveto)
+
+def _no_sandbox(function):
+    def __no_sandbox(*args, **kw):
+        try:
+            from setuptools.sandbox import DirectorySandbox
+            if not hasattr(DirectorySandbox, '_old'):
+                def violation(*args):
+                    pass
+                DirectorySandbox._old = DirectorySandbox._violation
+                DirectorySandbox._violation = violation
+                patched = True
+            else:
+                patched = False
+        except ImportError:
+            patched = False
+
+        try:
+            return function(*args, **kw)
+        finally:
+            if patched:
+                DirectorySandbox._violation = DirectorySandbox._old
+                del DirectorySandbox._old
+
+    return __no_sandbox
+
+def _patch_file(path, content):
+    """Will backup the file then patch it"""
+    existing_content = open(path).read()
+    if existing_content == content:
+        # already patched
+        log.warn('Already patched.')
+        return False
+    log.warn('Patching...')
+    _rename_path(path)
+    f = open(path, 'w')
+    try:
+        f.write(content)
+    finally:
+        f.close()
+    return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+def _same_content(path, content):
+    return open(path).read() == content
+
+def _rename_path(path):
+    new_name = path + '.OLD.%s' % time.time()
+    log.warn('Renaming %s into %s', path, new_name)
+    os.rename(path, new_name)
+    return new_name
+
+def _remove_flat_installation(placeholder):
+    if not os.path.isdir(placeholder):
+        log.warn('Unkown installation at %s', placeholder)
+        return False
+    found = False
+    for file in os.listdir(placeholder):
+        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+            found = True
+            break
+    if not found:
+        log.warn('Could not locate setuptools*.egg-info')
+        return
+
+    log.warn('Removing elements out of the way...')
+    pkg_info = os.path.join(placeholder, file)
+    if os.path.isdir(pkg_info):
+        patched = _patch_egg_dir(pkg_info)
+    else:
+        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+    if not patched:
+        log.warn('%s already patched.', pkg_info)
+        return False
+    # now let's move the files out of the way
+    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+        element = os.path.join(placeholder, element)
+        if os.path.exists(element):
+            _rename_path(element)
+        else:
+            log.warn('Could not find the %s element of the '
+                     'Setuptools distribution', element)
+    return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+def _after_install(dist):
+    log.warn('After install bootstrap.')
+    placeholder = dist.get_command_obj('install').install_purelib
+    _create_fake_setuptools_pkg_info(placeholder)
+
+def _create_fake_setuptools_pkg_info(placeholder):
+    if not placeholder or not os.path.exists(placeholder):
+        log.warn('Could not find the install location')
+        return
+    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+    setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+            (SETUPTOOLS_FAKED_VERSION, pyver)
+    pkg_info = os.path.join(placeholder, setuptools_file)
+    if os.path.exists(pkg_info):
+        log.warn('%s already exists', pkg_info)
+        return
+
+    log.warn('Creating %s', pkg_info)
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+
+    pth_file = os.path.join(placeholder, 'setuptools.pth')
+    log.warn('Creating %s', pth_file)
+    f = open(pth_file, 'w')
+    try:
+        f.write(os.path.join(os.curdir, setuptools_file))
+    finally:
+        f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
+
+def _patch_egg_dir(path):
+    # let's check if it's already patched
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    if os.path.exists(pkg_info):
+        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+            log.warn('%s already patched.', pkg_info)
+            return False
+    _rename_path(path)
+    os.mkdir(path)
+    os.mkdir(os.path.join(path, 'EGG-INFO'))
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+    return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+def _before_install():
+    log.warn('Before install bootstrap.')
+    _fake_setuptools()
+
+
+def _under_prefix(location):
+    if 'install' not in sys.argv:
+        return True
+    args = sys.argv[sys.argv.index('install')+1:]
+    for index, arg in enumerate(args):
+        for option in ('--root', '--prefix'):
+            if arg.startswith('%s=' % option):
+                top_dir = arg.split('root=')[-1]
+                return location.startswith(top_dir)
+            elif arg == option:
+                if len(args) > index:
+                    top_dir = args[index+1]
+                    return location.startswith(top_dir)
+        if arg == '--user' and USER_SITE is not None:
+            return location.startswith(USER_SITE)
+    return True
+
+
+def _fake_setuptools():
+    log.warn('Scanning installed packages')
+    try:
+        import pkg_resources
+    except ImportError:
+        # we're cool
+        log.warn('Setuptools or Distribute does not seem to be installed.')
+        return
+    ws = pkg_resources.working_set
+    try:
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+                                  replacement=False))
+    except TypeError:
+        # old distribute API
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+    if setuptools_dist is None:
+        log.warn('No setuptools distribution found')
+        return
+    # detecting if it was already faked
+    setuptools_location = setuptools_dist.location
+    log.warn('Setuptools installation detected at %s', setuptools_location)
+
+    # if --root or --preix was provided, and if
+    # setuptools is not located in them, we don't patch it
+    if not _under_prefix(setuptools_location):
+        log.warn('Not patching, --root or --prefix is installing Distribute'
+                 ' in another location')
+        return
+
+    # let's see if its an egg
+    if not setuptools_location.endswith('.egg'):
+        log.warn('Non-egg installation')
+        res = _remove_flat_installation(setuptools_location)
+        if not res:
+            return
+    else:
+        log.warn('Egg installation')
+        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+        if (os.path.exists(pkg_info) and
+            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+            log.warn('Already patched.')
+            return
+        log.warn('Patching...')
+        # let's create a fake egg replacing setuptools one
+        res = _patch_egg_dir(setuptools_location)
+        if not res:
+            return
+    log.warn('Patched done.')
+    _relaunch()
+
+
+def _relaunch():
+    log.warn('Relaunching...')
+    # we have to relaunch the process
+    # pip marker to avoid a relaunch bug
+    if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
+        sys.argv[0] = 'setup.py'
+    args = [sys.executable] + sys.argv
+    sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+    """Extract all members from the archive to the current working
+       directory and set owner, modification time and permissions on
+       directories afterwards. `path' specifies a different directory
+       to extract to. `members' is optional and must be a subset of the
+       list returned by getmembers().
+    """
+    import copy
+    import operator
+    from tarfile import ExtractError
+    directories = []
+
+    if members is None:
+        members = self
+
+    for tarinfo in members:
+        if tarinfo.isdir():
+            # Extract directories with a safe mode.
+            directories.append(tarinfo)
+            tarinfo = copy.copy(tarinfo)
+            tarinfo.mode = 448 # decimal for oct 0700
+        self.extract(tarinfo, path)
+
+    # Reverse sort directories.
+    if sys.version_info < (2, 4):
+        def sorter(dir1, dir2):
+            return cmp(dir1.name, dir2.name)
+        directories.sort(sorter)
+        directories.reverse()
+    else:
+        directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+    # Set correct owner, mtime and filemode on directories.
+    for tarinfo in directories:
+        dirpath = os.path.join(path, tarinfo.name)
+        try:
+            self.chown(tarinfo, dirpath)
+            self.utime(tarinfo, dirpath)
+            self.chmod(tarinfo, dirpath)
+        except ExtractError:
+            e = sys.exc_info()[1]
+            if self.errorlevel > 1:
+                raise
+            else:
+                self._dbg(1, "tarfile: %s" % e)
+
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    tarball = download_setuptools()
+    _install(tarball)
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
diff --git a/lib/Chameleon-2.9.2/docs/conf.py b/lib/Chameleon-2.9.2/docs/conf.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/conf.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+#
+# Chameleon documentation build configuration file, created by
+# sphinx-quickstart on Sun Nov  1 16:08:00 2009.
+#
+# 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.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# 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']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Chameleon'
+copyright = u'2008-2011 by Malthe Borch and the Repoze Community'
+
+# 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 = '2.8'
+# The full version, including alpha/beta/rc tags.
+release = '2.8.0'
+
+# 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 documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_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.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+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 name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "Chameleon %s documentation" % version
+
+# 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 = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bchameleonm,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# 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_use_modindex = True
+
+# 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, links to the reST sources are added to the pages.
+#html_show_sourcelink = 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 = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'chameleondoc'
+
+
+# -- 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', 'chameleon.tex', u'Chameleon Documentation',
+   u'Malthe Borch et. al', '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
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/lib/Chameleon-2.9.2/docs/configuration.rst b/lib/Chameleon-2.9.2/docs/configuration.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/configuration.rst
@@ -0,0 +1,43 @@
+Configuration
+=============
+
+Most settings can be provided as keyword-arguments to the template
+constructor classes.
+
+There are certain settings which are required at environment
+level. Acceptable values are ``"0"``, ``"1"``, or the literals
+``"true"`` or ``"false"`` (case-insensitive).
+
+General usage
+-------------
+
+The following settings are useful in general.
+
+``CHAMELEON_EAGER``
+   Parse and compile templates on instantiation.
+
+``CHAMELEON_CACHE``
+
+   When set to a file system path, the template compiler will write
+   its output to files in this directory and use it as a cache.
+
+   This not only enables you to see the compiler output, but also
+   speeds up startup.
+
+``CHAMELEON_RELOAD``
+   This setting controls the default value of the ``auto_reload``
+   parameter.
+
+Development
+-----------
+
+The following settings are mostly useful during development or
+debugging of the library itself.
+
+``CHAMELEON_DEBUG``
+
+   Enables a set of debugging settings which make it easier to
+   discover and research issues with the engine itself.
+
+   This implicitly enables auto-reload for any template.
+
diff --git a/lib/Chameleon-2.9.2/docs/index.rst b/lib/Chameleon-2.9.2/docs/index.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/index.rst
@@ -0,0 +1,217 @@
+Chameleon
+=========
+
+Chameleon is an HTML/XML template engine for `Python
+<http://www.python.org>`_.
+
+It's designed to generate the document output of a web application,
+typically HTML markup or XML.
+
+The language used is *page templates*, originally a `Zope
+<http://www.zope.org>`_ invention [1]_, but available here as a
+:ref:`standalone library <no-dependencies>` that you can use in any
+script or application running Python 2.5 and up (including 3.x and
+`pypy <http://pypy.org>`_). It comes with a set of :ref:`new features
+<new-features>`, too.
+
+The template engine compiles templates into Python byte-code and is optimized
+for speed. For a complex template language, the performance is
+:ref:`very good <fast>`.
+
+  *Found a bug?* Please report issues to the `issue tracker <http://github.com/malthe/chameleon/issues>`_.
+
+  *Need help?* Post to the Pylons `discussion list <http://groups.google.com/group/pylons-discuss/>`_ or join the ``#pyramid`` channel on `Freenode IRC <http://freenode.net/>`_.
+
+Getting the code
+----------------
+
+You can `download <http://pypi.python.org/pypi/Chameleon#downloads>`_ the
+package from the Python package index or install the latest release
+using setuptools or the newer `distribute
+<http://packages.python.org/distribute/>`_ (required for Python 3.x)::
+
+  $ easy_install Chameleon
+
+.. _no-dependencies:
+
+There are no required library dependencies on Python 2.7 and up
+[2]_. On 2.5 and 2.6, the `ordereddict
+<http://pypi.python.org/pypi/ordereddict>`_ and `unittest2
+<http://pypi.python.org/pypi/unittest2>`_ packages are set as
+dependencies.
+
+The project is hosted in a `GitHub repository
+<http://github.com/malthe/chameleon>`_. Code contributions are
+welcome. The easiest way is to use the `pull request
+<http://help.github.com/pull-requests/>`_ interface.
+
+
+Introduction
+------------
+
+The *page templates* language is used within your document structure
+as special element attributes and text markup. Using a set of simple
+language constructs, you control the document flow, element
+repetition, text replacement and translation.
+
+.. note:: If you've used page templates in a Zope environment previously, note that Chameleon uses Python as the default expression language (instead of *path* expressions).
+
+The basic language (known as the *template attribute language* or TAL)
+is simple enough to grasp from an example:
+
+.. code-block:: genshi
+
+  <html>
+    <body>
+      <h1>Hello, ${'world'}!</h1>
+      <table>
+        <tr tal:repeat="row 'apple', 'banana', 'pineapple'">
+          <td tal:repeat="col 'juice', 'muffin', 'pie'">
+             ${row.capitalize()} ${col}
+          </td>
+        </tr>
+      </table>
+    </body>
+  </html>
+
+The ``${...}`` notation is short-hand for text insertion [3]_. The
+Python-expression inside the braces is evaluated and the result
+included in the output. By default, the string is escaped before
+insertion. To avoid this, use the ``structure:`` prefix:
+
+.. code-block:: genshi
+
+  <div>${structure: ...}</div>
+
+Note that if the expression result is an object that implements an
+``__html__()`` method [4]_, this method will be called and the result
+treated as "structure". An example of such an object is the
+``Markup`` class that's included as a utility::
+
+  from chameleon.utils import Markup
+  username = "<tt>%s</tt>" % username
+
+The macro language (known as the *macro expansion language* or METAL)
+provides a means of filling in portions of a generic template.
+
+On the left, the macro template; on the right, a template that loads
+and uses the macro, filling in the "content" slot:
+
+.. code-block:: genshi
+
+  <html xmlns="http://www.w3.org/1999/xhtml">             <metal:main use-macro="load: main.pt">
+    <head>                                                   <p metal:fill-slot="content">${structure: document.body}<p/>
+      <title>Example — ${document.title}</title>    </metal:main>
+    </head>
+    <body>
+      <h1>${document.title}</h1>
+
+      <div id="content">
+        <metal:content define-slot="content" />
+      </div>
+    </body>
+  </html>
+
+In the example, the expression type :ref:`load <load-expression>` is
+used to retrieve a template from the file system using a path relative
+to the calling template.
+
+The METAL system works with TAL such that you can for instance fill in
+a slot that appears in a ``tal:repeat`` loop, or refer to variables
+defined using ``tal:define``.
+
+The third language subset is the translation system (known as the
+*internationalization language* or I18N):
+
+.. code-block:: genshi
+
+  <html i18n:domain="example">
+
+    ...
+
+    <div i18n:translate="">
+       You have <span i18n:name="amount">${round(amount, 2)}</span> dollars in your account.
+    </div>
+
+    ...
+
+  </html>
+
+Each translation message is marked up using ``i18n:translate`` and
+values can be mapped using ``i18n:name``. Attributes are marked for
+translation using ``i18n:attributes``. The template engine generates
+`gettext <http://www.gnu.org/s/gettext/>`_ translation strings from
+the markup::
+
+  "You have ${amount} dollars in your account."
+
+If you use a web framework such as `Pyramid
+<https://docs.pylonsproject.org/docs/pyramid.html>`_, the translation
+system is set up automatically and will negotiate on a *target
+language* based on the HTTP request or other parameter. If not, then
+you need to configure this manually.
+
+Next steps
+----------
+
+This was just an introduction. There are a number of other basic
+statements that you need to know in order to use the language. This is
+all covered in the :ref:`language reference <language-reference>`.
+
+If you're already familiar with the page template language, you can
+skip ahead to the :ref:`getting started <getting-started-with-cpt>`
+section to learn how to use the template engine in your code.
+
+To learn about integration with your favorite web framework see the
+section on :ref:`framework integration <framework-integration>`.
+
+License
+-------
+
+This software is made available under a BSD-like license.
+
+
+Contents
+========
+
+.. toctree::
+   :maxdepth: 2
+
+   library.rst
+   reference.rst
+   integration.rst
+   configuration.rst
+
+Indices and Tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+Notes
+=====
+
+.. [1] The template language specifications and API for the Page
+       Templates engine are based on Zope Page Templates (see in
+       particular `zope.pagetemplate
+       <http://pypi.python.org/pypi/zope.pagetemplate>`_). However,
+       the Chameleon compiler and Page Templates engine is an entirely
+       new codebase, packaged as a standalone distribution. It does
+       not require a Zope software environment.
+
+.. [2] The translation system in Chameleon is pluggable and based on
+       `gettext <http://www.gnu.org/s/gettext/>`_.
+       There is built-in support for the `zope.i18n
+       <http://pypi.python.org/pypi/zope.i18n>`_ package. If this
+       package is installed, it will be used by default. The
+       `translationstring
+       <http://pypi.python.org/pypi/translationstring>`_ package
+       offers some of the same helper and utility classes, without the
+       Zope application interface.
+
+.. [3] This syntax was taken from `Genshi <http://genshi.edgewall.org/>`_.
+
+.. [4] See the `WebHelpers
+       <https://docs.pylonsproject.org/projects/webhelpers/dev/modules/html/__init__.html>`_
+       library which provide a simple wrapper around this method.
diff --git a/lib/Chameleon-2.9.2/docs/integration.rst b/lib/Chameleon-2.9.2/docs/integration.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/integration.rst
@@ -0,0 +1,41 @@
+.. _framework-integration:
+
+Integration
+===========
+
+Integration with Chameleon is available for a number of popular web
+frameworks. The framework will usually provide loading mechanisms and
+translation (internationalization) configuration.
+
+Pyramid
+-------
+
+Chameleon is the default template engine for the `Pyramid
+<http://pylonsproject.org/projects/pyramid/about>`_ framework. See the
+section on `Page Templates
+<http://docs.pylonsproject.org/projects/pyramid/1.1/narr/templates.html#chameleon-zpt-templates>`_ for a complete reference.
+
+Zope 2 / Plone
+--------------
+
+Install the `five.pt <http://pypi.python.org/pypi/five.pt>`_ package
+to replace the reference template engine (globally).
+
+Zope Toolkit (ZTK)
+------------------
+
+Install the `z3c.pt <http://pypi.python.org/pypi/z3c.pt>`_ package for
+applications based on the `Zope Toolkit
+<http://docs.zope.org/zopetoolkit/>`_ (ZTK). Note that you need to
+explicit use the template classes from this package.
+
+Grok
+----
+
+Support for the `Grok <http://grok.zope.org/>`_ framework is available
+in the `grokcore.chameleon
+<http://pypi.python.org/pypi/grokcore.chameleon>`_ package.
+
+This package will setup Grok's policy for templating integration and
+associate the Chameleon template components for the ``.cpt`` template
+filename extension.
diff --git a/lib/Chameleon-2.9.2/docs/library.rst b/lib/Chameleon-2.9.2/docs/library.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/library.rst
@@ -0,0 +1,238 @@
+Library Documentation
+=====================
+
+This section documents the package as a Python library. To learn about
+the page template language, consult the :ref:`language reference
+<language-reference>`.
+
+.. _getting-started-with-cpt:
+
+Getting started
+---------------
+
+There are several template constructor classes available, one for each
+of the combinations *text* or *xml*, and *string* or *file*.
+
+The file-based constructor requires an absolute path. To set up a
+templates directory *once*, use the template loader class::
+
+  import os
+
+  path = os.path.dirname(__file__)
+
+  from chameleon import PageTemplateLoader
+  templates = PageTemplateLoader(os.path.join(path, "templates"))
+
+Then, to load a template relative to the provided path, use dictionary
+syntax::
+
+  template = templates['hello.pt']
+
+Alternatively, use the appropriate template class directly. Let's try
+with a string input::
+
+  from chameleon import PageTemplate
+  template = PageTemplate("<div>Hello, ${name}.</div>")
+
+All template instances are callable. Provide variables by keyword
+argument::
+
+  >>> template(name='John')
+  '<div>Hello, John.</div>'
+
+.. _fast:
+
+Performance
+-----------
+
+The template engine compiles (or *translates*) template source code
+into Python byte-code. In simple templates this yields an increase in
+performance of about 7 times in comparison to the reference
+implementation.
+
+In benchmarks for the content management system `Plone
+<http://www.plone.org>`_, switching to Chameleon yields a request to
+response improvement of 20-50%.
+
+Extension
+---------
+
+You can extend the language through the expression engine by writing
+your own expression compiler.
+
+Let's try and write an expression compiler for an expression type that
+will simply uppercase the supplied value. We'll call it ``upper``.
+
+You can write such a compiler as a closure:
+
+.. code-block:: python
+
+   import ast
+
+   def uppercase_expression(string):
+       def compiler(target, engine):
+           uppercased = self.string.uppercase()
+           value = ast.Str(uppercased)
+           return [ast.Assign(targets=[target], value=value)]
+       return compiler
+
+To make it available under a certain prefix, we'll add it to the
+expression types dictionary.
+
+.. code-block:: python
+
+   from chameleon import PageTemplate
+   PageTemplate.expression_types['upper'] = uppercase_expression
+
+Alternatively, you could subclass the template class and set the
+attribute ``expression_types`` to a dictionary that includes your
+expression:
+
+.. code-block:: python
+
+   from chameleon import PageTemplateFile
+   from chameleon.tales import PythonExpr
+
+   class MyPageTemplateFile(PageTemplateFile):
+       expression_types = {
+           'python': PythonExpr,
+           'upper': uppercase_expression
+           }
+
+You can now uppercase strings *natively* in your templates::
+
+  <div tal:content="upper: hello, world" />
+
+It's probably best to stick with a Python expression::
+
+  <div tal:content="'hello, world'.upper()" />
+
+
+.. _whats-new:
+
+Changes between 1.x and 2.x
+---------------------------
+
+This sections describes new features, improvements and changes from
+1.x to 2.x.
+
+New parser
+~~~~~~~~~~
+
+This series features a new, custom-built parser, implemented in pure
+Python. It parses both HTML and XML inputs (the previous parser relied
+on the expat system library and was more strict about its input).
+
+The main benefit of the new parser is that the compiler is now able to
+point to the source location of parse- and compilation errors much
+more accurately. This should be a great aid in debugging these errors.
+
+Compatible output
+~~~~~~~~~~~~~~~~~
+
+The 2.x engine matches the output of the reference implementation more
+closely (usually exactly). There are less differences altogether; for
+instance, the method of escaping TALES expression (usually a
+semicolon) has been changed to match that of the reference
+implementation.
+
+New language features
+~~~~~~~~~~~~~~~~~~~~~
+
+This series also introduces a number of new language features:
+
+1. Support for the ``tal:on-error`` from the reference specification
+   has been added.
+
+2. Two new attributes ``tal:switch`` and ``tal:case`` have been added
+   to make element conditions more flexible.
+
+
+Code improvements
+~~~~~~~~~~~~~~~~~
+
+The template classes have been refactored and simplified allowing
+better reuse of code and more intuitive APIs on the lower levels.
+
+Expression engine
+~~~~~~~~~~~~~~~~~
+
+The expression engine has been redesigned to make it easier to
+understand and extend. The new engine is based on the ``ast`` module
+(available since Python 2.6; backports included for Python 2.5). This
+means that expression compilers now need to return a valid list of AST
+statements that include an assignment to the target node.
+
+Compiler
+~~~~~~~~
+
+The new compiler has been optimized for complex templates. As a
+result, in the benchmark suite included with the package, this
+compiler scores about half of the 1.x series. For most real world
+applications, the engine should still perform as well as the 1.x
+series.
+
+
+API reference
+-------------
+
+This section describes the documented API of the library.
+
+Template classes
+~~~~~~~~~~~~~~~~
+
+Use the ``PageTemplate*`` template classes to define a template from a
+string or file input:
+
+.. automodule:: chameleon
+
+  .. autoclass:: chameleon.PageTemplate
+
+     Note: The remaining classes take the same general configuration
+     arguments.
+
+     .. automethod:: render
+
+  .. autoclass:: chameleon.PageTemplateFile(filename, **config)
+
+  .. autoclass:: chameleon.PageTextTemplate
+
+  .. autoclass:: chameleon.PageTextTemplateFile
+
+Template loader
+~~~~~~~~~~~~~~~
+
+Some systems have framework support for loading templates from
+files. The following loader class is directly compatible with the
+Pylons framework and may be adapted to other frameworks:
+
+.. class:: chameleon.PageTemplateLoader(search_path=None, default_extension=None, **config)
+
+   Load templates from ``search_path`` (must be a string or a list of
+   strings)::
+
+     templates = PageTemplateLoader(path)
+     example = templates['example.pt']
+
+   If ``default_extension`` is provided, this will be added to inputs
+   that do not already have an extension::
+
+     templates = PageTemplateLoader(path, ".pt")
+     example = templates['example']
+
+   Any additional keyword arguments will be passed to the template
+   constructor::
+
+     templates = PageTemplateLoader(path, debug=True, encoding="utf-8")
+
+   .. automethod:: load
+
+Expression engine
+~~~~~~~~~~~~~~~~~
+
+For advanced integration, the compiler module provides support for
+dynamic expression evaluation:
+
+.. automodule:: chameleon.compiler
+
+  .. autoclass:: chameleon.compiler.ExpressionEvaluator
diff --git a/lib/Chameleon-2.9.2/docs/reference.rst b/lib/Chameleon-2.9.2/docs/reference.rst
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/docs/reference.rst
@@ -0,0 +1,1695 @@
+:tocdepth: 4
+
+.. _language-reference:
+
+.. highlight:: xml
+
+Language Reference
+==================
+
+The language reference is structured such that it can be read as a
+general introduction to the *page templates* language.
+
+It's split into parts that correspond to each of the main language
+features.
+
+Syntax
+######
+
+You can safely :ref:`skip this section <tal>` if you're familiar with
+how template languages work or just want to learn by example.
+
+An *attribute language* is a programming language designed to render
+documents written in XML or HTML markup.  The input must be a
+well-formed document.  The output from the template is usually
+XML-like but isn't required to be well-formed.
+
+The statements of the language are document tags with special
+attributes, and look like this::
+
+    <p namespace-prefix:command="argument"> ... </p>
+
+In the above example, the attribute
+``namespace-prefix:command="argument"`` is the statement, and the
+entire paragraph tag is the statement's element.  The statement's
+element is the portion of the document on which this statement
+operates.
+
+The namespace prefixes are typically declared once, at the top of a
+template (note that prefix declarations for the template language
+namespaces are omitted from the template output)::
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:tal="http://xml.zope.org/namespaces/tal"
+        xmlns:metal="http://xml.zope.org/namespaces/metal"
+        xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+    ...
+  </html>
+
+Thankfully, sane namespace prefix defaults are in place to let us skip
+most of the boilerplate::
+
+  <html xmlns="http://www.w3.org/1999/xhtml">
+    <body>
+      <p tal:content="text"> ... </p>
+    </body>
+  </html>
+
+Note how ``tal`` is used without an explicit namespace
+declaration. Chameleon sets up defaults for ``metal`` and ``i18n`` as
+well.
+
+.. note:: Default prefixes are a special feature of Chameleon.
+
+.. _tal:
+
+Basics (TAL)
+############
+
+The *template attribute language* is used to create dynamic XML-like
+content.  It allows elements of a document to be replaced, repeated,
+or omitted.
+
+Statements
+----------
+
+These are the available statements:
+
+==================  ==============
+ Statement           Description
+==================  ==============
+``tal:define``      Define variables.
+``tal:switch``      Defines a switch condition
+``tal:condition``   Include element only if expression is true.
+``tal:repeat``      Repeat an element.
+``tal:case``        Includes element only if expression is equal to parent switch.
+``tal:content``     Substitute the content of an element.
+``tal:replace``     Replace the element with dynamic content.
+``tal:omit-tag``    Omit the element tags, leaving only the inner content.
+``tal:attributes``  Dynamically change or insert element attributes.
+``tal:on-error``    Substitute the content of an element if processing fails.
+==================  ==============
+
+When there is only one TAL statement per element, the order in which
+they are executed is simple.  Starting with the root element, each
+element's statements are executed, then each of its child elements is
+visited, in order, to do the same::
+
+  <html>
+    <meta>
+      <title tal:content="context.title" />
+    </meta>
+    <body>
+      <div tal:condition="items">
+        <p>These are your items:</p>
+        <ul>
+          <li tal:repeat="item items" tal:content="item" />
+        </ul>
+      </div>
+    </body>
+  </html>
+
+Any combination of statements may appear on the same element, except
+that the ``tal:content`` and ``tal:replace`` statements may not be
+used on the same element.
+
+.. note:: The ``tal:case`` and ``tal:switch`` statements are available
+          in Chameleon only.
+
+TAL does not use use the order in which statements are written in the
+tag to determine the order in which they are executed.  When an
+element has multiple statements, they are executed in the order
+printed in the table above.
+
+There is a reasoning behind this ordering.  Because users often want
+to set up variables for use in other statements contained within this
+element or subelements, ``tal:define`` is executed first. Then any
+switch statement. ``tal:condition`` follows, then ``tal:repeat``, then
+``tal:case``. We are now rendering an element; first ``tal:content``
+or ``tal:replace``. Finally, before ``tal:attributes``, we have
+``tal:omit-tag`` (which is implied with ``tal:replace``).
+
+.. note:: *TALES* is used as the expression language for the "stuff in
+   the quotes". The default syntax is simply Python, but
+   other inputs are possible --- see the section on :ref:`expressions
+   <tales>`.
+
+``tal:attributes``
+^^^^^^^^^^^^^^^^^^
+
+Updates or inserts element attributes.
+
+::
+
+  tal:attributes="href request.url"
+
+Syntax
+~~~~~~
+
+``tal:attributes`` syntax::
+
+    argument             ::= attribute_statement [';' attribute_statement]*
+    attribute_statement  ::= attribute_name expression
+    attribute_name       ::= [namespace-prefix ':'] Name
+    namespace-prefix     ::= Name
+
+
+Description
+~~~~~~~~~~~
+
+The ``tal:attributes`` statement replaces the value of an attribute
+(or creates an attribute) with a dynamic value.  The
+value of each expression is converted to a string, if necessary.
+
+.. note:: You can qualify an attribute name with a namespace prefix,
+   for example ``html:table``, if you are generating an XML document
+   with multiple namespaces.
+
+If an attribute expression evaluates to ``None``, the attribute is
+deleted from the statement element (or simply not inserted).
+
+If the expression evaluates to the symbol ``default`` (a symbol which
+is always available when evaluating attributes), its value is defined
+as the default static attribute value. If there is no such default
+value, a return value of ``default`` will drop the attribute.
+
+If you use ``tal:attributes`` on an element with an active
+``tal:replace`` command, the ``tal:attributes`` statement is ignored.
+
+If you use ``tal:attributes`` on an element with a ``tal:repeat``
+statement, the replacement is made on each repetition of the element,
+and the replacement expression is evaluated fresh for each repetition.
+
+.. note:: If you want to include a semicolon (";") in an expression, it
+          must be escaped by doubling it (";;") [1]_.
+
+Examples
+~~~~~~~~
+
+Replacing a link::
+
+    <a href="/sample/link.html"
+       tal:attributes="href context.url()"
+       >
+       ...
+    </a>
+
+Replacing two attributes::
+
+    <textarea rows="80" cols="20"
+              tal:attributes="rows request.rows();cols request.cols()"
+        />
+
+A checkbox input::
+
+    <input type="input" tal:attributes="checked True" />
+
+``tal:condition``
+^^^^^^^^^^^^^^^^^
+
+Conditionally includes or omits an element::
+
+  <div tal:condition="comments">
+    ...
+  </div>
+
+Syntax
+~~~~~~
+
+``tal:condition`` syntax::
+
+    argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+ The ``tal:condition`` statement includes the statement element in the
+ template only if the condition is met, and omits it otherwise.  If
+ its expression evaluates to a *true* value, then normal processing of
+ the element continues, otherwise the statement element is immediately
+ removed from the template.  For these purposes, the value ``nothing``
+ is false, and ``default`` has the same effect as returning a true
+ value.
+
+.. note:: Like Python itself, ZPT considers None, zero, empty strings,
+   empty sequences, empty dictionaries, and instances which return a
+   nonzero value from ``__len__`` or ``__nonzero__`` false; all other
+   values are true, including ``default``.
+
+Examples
+~~~~~~~~
+
+Test a variable before inserting it::
+
+        <p tal:condition="request.message" tal:content="request.message" />
+
+Testing for odd/even in a repeat-loop::
+
+        <div tal:repeat="item range(10)">
+          <p tal:condition="repeat.item.even">Even</p>
+          <p tal:condition="repeat.item.odd">Odd</p>
+        </div>
+
+``tal:content``
+^^^^^^^^^^^^^^^
+
+Replaces the content of an element.
+
+Syntax
+~~~~~~
+
+``tal:content`` syntax::
+
+        argument ::= (['text'] | 'structure') expression
+
+Description
+~~~~~~~~~~~
+
+Rather than replacing an entire element, you can insert text or
+structure in place of its children with the ``tal:content`` statement.
+The statement argument is exactly like that of ``tal:replace``, and is
+interpreted in the same fashion.  If the expression evaluates to
+``nothing``, the statement element is left childless.  If the
+expression evaluates to ``default``, then the element's contents are
+evaluated.
+
+The default replacement behavior is ``text``, which replaces
+angle-brackets and ampersands with their HTML entity equivalents.  The
+``structure`` keyword passes the replacement text through unchanged,
+allowing HTML/XML markup to be inserted.  This can break your page if
+the text contains unanticipated markup (eg.  text submitted via a web
+form), which is the reason that it is not the default.
+
+.. note:: The ``structure`` keyword exists to provide backwards
+          compatibility.  In Chameleon, the ``structure:`` expression
+          type provides the same functionality (also for inline
+          expressions).
+
+
+Examples
+~~~~~~~~
+
+Inserting the user name::
+
+        <p tal:content="user.getUserName()">Fred Farkas</p>
+
+Inserting HTML/XML::
+
+        <p tal:content="structure context.getStory()">
+           Marked <b>up</b> content goes here.
+        </p>
+
+``tal:define``
+^^^^^^^^^^^^^^
+
+Defines local variables.
+
+Syntax
+~~~~~~
+
+``tal:define`` syntax::
+
+    argument ::= define_scope [';' define_scope]*
+    define_scope ::= (['local'] | 'global')
+    define_var define_var ::= variable_name
+    expression variable_name ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``tal:define`` statement defines variables.  When you define a
+local variable in a statement element, you can use that variable in
+that element and the elements it contains.  If you redefine a variable
+in a contained element, the new definition hides the outer element's
+definition within the inner element.
+
+Note that valid variable names are any Python identifier string
+including underscore, although two or more leading underscores are
+disallowed (used internally by the compiler). Further, names are
+case-sensitive.
+
+Python builtins are always "in scope", but most of them may be
+redefined (such as ``help``). Exceptions are:: ``float``, ``int``,
+``len``, ``long``, ``str``, ``None``, ``True`` and ``False``.
+
+In addition, the following names are reserved: ``econtext``,
+``rcontext``, ``translate``, ``decode`` and ``convert``.
+
+If the expression associated with a variable evaluates to ``nothing``,
+then that variable has the value ``nothing``, and may be used as such
+in further expressions. Likewise, if the expression evaluates to
+``default``, then the variable has the value ``default``, and may be
+used as such in further expressions.
+
+You can define two different kinds of variables: *local* and
+*global*. When you define a local variable in a statement element, you
+can only use that variable in that element and the elements it
+contains. If you redefine a local variable in a contained element, the
+new definition hides the outer element's definition within the inner
+element. When you define a global variables, you can use it in any
+element processed after the defining element. If you redefine a global
+variable, you replace its definition for the rest of the template.
+
+To set the definition scope of a variable, use the keywords ``local``
+or ``global`` in front of the assignment. The default setting is
+``local``; thus, in practice, only the ``global`` keyword is used.
+
+.. note:: If you want to include a semicolon (";") in an expression, it
+          must be escaped by doubling it (";;") [1]_.
+
+Examples
+~~~~~~~~
+
+Defining a variable::
+
+        tal:define="company_name 'Zope Corp, Inc.'"
+
+Defining two variables, where the second depends on the first::
+
+        tal:define="mytitle context.title; tlen len(mytitle)"
+
+
+``tal:switch`` and ``tal:case``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Defines a switch clause.
+
+::
+
+  <ul tal:switch="len(items) % 2">
+    <li tal:case="True">odd</li>
+    <li tal:case="False">even</li>
+  </ul>
+
+Syntax
+~~~~~~
+
+``tal:case`` and ``tal:switch`` syntax::
+
+    argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+The *switch* and *case* construct is a short-hand syntax for
+evaluating a set of expressions against a parent value.
+
+The ``tal:switch`` statement is used to set a new parent value and the
+``tal:case`` statement works like a condition and only allows content
+if the expression matches the value.
+
+Note that if the case expression is the symbol ``default``, it always
+matches the switch.
+
+.. note:: These statements are only available in Chameleon 2.x and not
+          part of the ZPT specification.
+
+Examples
+~~~~~~~~
+
+::
+
+  <ul tal:switch="item.type">
+    <li tal:case="'document'">
+      Document
+    </li>
+    <li tal:case="'folder'">
+      Folder
+    </li>
+  </ul>
+
+Note that any and all cases that match the switch will be included.
+
+
+``tal:omit-tag``
+^^^^^^^^^^^^^^^^
+
+Removes an element, leaving its contents.
+
+Syntax
+~~~~~~
+
+``tal:omit-tag`` syntax::
+
+        argument ::= [ expression ]
+
+Description
+~~~~~~~~~~~
+
+The ``tal:omit-tag`` statement leaves the contents of an element in
+place while omitting the surrounding start and end tags.
+
+If the expression evaluates to a *false* value, then normal processing
+of the element continues and the tags are not omitted.  If the
+expression evaluates to a *true* value, or no expression is provided,
+the statement element is replaced with its contents.
+
+.. note:: Like Python itself, ZPT considers None, zero, empty strings,
+   empty sequences, empty dictionaries, and instances which return a
+   nonzero value from ``__len__`` or ``__nonzero__`` false; all other
+   values are true, including ``default``.
+
+Examples
+~~~~~~~~
+
+Unconditionally omitting a tag::
+
+        <div tal:omit-tag="" comment="This tag will be removed">
+          <i>...but this text will remain.</i>
+        </div>
+
+Conditionally omitting a tag::
+
+        <b tal:omit-tag="not:bold">I may be bold.</b>
+
+The above example will omit the ``b`` tag if the variable ``bold`` is false.
+
+Creating ten paragraph tags, with no enclosing tag::
+
+        <span tal:repeat="n range(10)"
+              tal:omit-tag="">
+          <p tal:content="n">1</p>
+        </span>
+
+.. _tal_repeat:
+
+``tal:repeat``
+^^^^^^^^^^^^^^
+
+Repeats an element.
+
+Syntax
+~~~~~~
+
+``tal:repeat`` syntax::
+
+        argument      ::= variable_name expression
+        variable_name ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``tal:repeat`` statement replicates a sub-tree of your document
+once for each item in a sequence. The expression should evaluate to a
+sequence. If the sequence is empty, then the statement element is
+deleted, otherwise it is repeated for each value in the sequence.  If
+the expression is ``default``, then the element is left unchanged, and
+no new variables are defined.
+
+The ``variable_name`` is used to define a local variable and a repeat
+variable. For each repetition, the local variable is set to the
+current sequence element, and the repeat variable is set to an
+iteration object.
+
+Repeat variables
+~~~~~~~~~~~~~~~~~
+
+You use repeat variables to access information about the current
+repetition (such as the repeat index).  The repeat variable has the
+same name as the local variable, but is only accessible through the
+built-in variable named ``repeat``.
+
+The following information is available from the repeat variable:
+
+==================  ==============
+ Attribute           Description
+==================  ==============
+``index``           Repetition number, starting from zero.
+``number``          Repetition number, starting from one.
+``even``            True for even-indexed repetitions (0, 2, 4, ...).
+``odd``             True for odd-indexed repetitions (1, 3, 5, ...).
+``start``           True for the starting repetition (index 0).
+``end``             True for the ending, or final, repetition.
+``first``           True for the first item in a group - see note below
+``last``            True for the last item in a group - see note below
+``length``          Length of the sequence, which will be the total number of repetitions.
+``letter``          Repetition number as a lower-case letter: "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth.
+``Letter``          Upper-case version of *letter*.
+``roman``           Repetition number as a lower-case roman numeral: "i", "ii", "iii", "iv", "v", etc.
+``Roman``           Upper-case version of *roman*.
+==================  ==============
+
+You can access the contents of the repeat variable using either
+dictionary- or attribute-style access, e.g. ``repeat['item'].start``
+or ``repeat.item.start``.
+
+.. note:: For legacy compatibility, the attributes ``odd``, ``even``, ``number``, ``letter``, ``Letter``, ``roman``, and ``Roman`` are callable (returning ``self``).
+
+Note that ``first`` and ``last`` are intended for use with sorted
+sequences.  They try to divide the sequence into group of items with
+the same value.
+
+Examples
+~~~~~~~~
+
+Iterating over a sequence of strings::    
+
+        <p tal:repeat="txt ('one', 'two', 'three')">
+           <span tal:replace="txt" />
+        </p>
+
+Inserting a sequence of table rows, and using the repeat variable
+to number the rows::
+
+        <table>
+          <tr tal:repeat="item here.cart">
+              <td tal:content="repeat.item.number">1</td>
+              <td tal:content="item.description">Widget</td>
+              <td tal:content="item.price">$1.50</td>
+          </tr>
+        </table>
+
+Nested repeats::
+
+        <table border="1">
+          <tr tal:repeat="row range(10)">
+            <td tal:repeat="column range(10)">
+              <span tal:define="x repeat.row.number; 
+                                y repeat.column.number; 
+                                z x * y"
+                    tal:replace="string:$x * $y = $z">1 * 1 = 1</span>
+            </td>
+          </tr>
+        </table>
+
+Insert objects. Separates groups of objects by type by drawing a rule
+between them::
+
+        <div tal:repeat="object objects">
+          <h2 tal:condition="repeat.object.first.meta_type"
+            tal:content="object.type">Meta Type</h2>
+          <p tal:content="object.id">Object ID</p>
+          <hr tal:condition="object.last.meta_type" />
+        </div>
+
+.. note:: the objects in the above example should already be sorted by
+   type.
+
+``tal:replace``
+^^^^^^^^^^^^^^^
+
+Replaces an element.
+
+Syntax
+~~~~~~
+
+``tal:replace`` syntax::
+
+        argument ::= ['structure'] expression
+
+Description
+~~~~~~~~~~~
+
+
+The ``tal:replace`` statement replaces an element with dynamic
+content.  It replaces the statement element with either text or a
+structure (unescaped markup). The body of the statement is an
+expression with an optional type prefix. The value of the expression
+is converted into an escaped string unless you provide the 'structure' prefix. Escaping consists of converting ``&`` to
+``&amp;``, ``<`` to ``&lt;``, and ``>`` to ``&gt;``.
+
+.. note:: If the inserted object provides an ``__html__`` method, that method is called with the result inserted as structure. This feature is not implemented by ZPT.
+
+If the expression evaluates to ``None``, the element is simply removed.  If the value is ``default``, then the element is left unchanged.
+
+Examples
+~~~~~~~~
+
+Inserting a title::
+
+        <span tal:replace="context.title">Title</span>
+
+Inserting HTML/XML::
+
+        <div tal:replace="structure table" />
+
+.. _tales:
+
+Expressions (TALES)
+###################
+
+The *Template Attribute Language Expression Syntax* (TALES) standard
+describes expressions that supply :ref:`tal` and
+:ref:`metal` with data.  TALES is *one* possible expression
+syntax for these languages, but they are not bound to this definition.
+Similarly, TALES could be used in a context having nothing to do with
+TAL or METAL.
+
+TALES expressions are described below with any delimiter or quote
+markup from higher language layers removed.  Here is the basic
+definition of TALES syntax::
+
+      Expression  ::= [type_prefix ':'] String
+      type_prefix ::= Name
+
+Here are some simple examples::
+
+      1 + 2
+      None
+      string:Hello, ${view.user_name}
+
+The optional *type prefix* determines the semantics and syntax of the
+*expression string* that follows it.  A given implementation of TALES
+can define any number of expression types, with whatever syntax you
+like. It also determines which expression type is indicated by
+omitting the prefix.
+
+Types
+-----
+
+These are the available TALES expression types:
+
+=============  ==============
+ Prefix        Description
+=============  ==============
+``exists``     Evaluate the result inside an exception handler; if one of the exceptions ``AttributeError``, ``LookupError``, ``TypeError``, ``NameError``, or ``KeyError`` is raised during evaluation, the result is ``False``, otherwise ``True``. Note that the original result is discarded in any case.
+``import``     Import a global symbol using dotted notation.
+``load``       Load a template relative to the current template or absolute.
+``not``        Negate the expression result
+``python``     Evaluate a Python expression
+``string``     Format a string
+``structure``  Wraps the expression result as *structure*.
+=============  ==============
+
+.. note:: The default expression type is ``python``.
+
+.. warning:: The Zope reference engine defaults to a ``path``
+             expression type, which is closely tied to the Zope
+             framework. This expression is not implemented in
+             Chameleon (but it's available in a Zope framework
+             compatibility package).
+
+There's a mechanism to allow fallback to alternative expressions, if
+one should fail (raise an exception). The pipe character ('|') is used
+to separate two expressions::
+
+  <div tal:define="page request.GET['page'] | 0">
+
+This mechanism applies only to the ``python`` expression type, and by
+derivation ``string``.
+
+.. _tales_built_in_names:
+
+``python``
+^^^^^^^^^^
+
+Evaluates a Python expression.
+
+Syntax
+~~~~~~
+
+Python expression syntax::
+
+        Any valid Python language expression
+
+Description
+~~~~~~~~~~~
+
+Python expressions are executed natively within the translated
+template source code. There is no built-in security apparatus.
+
+``string``
+^^^^^^^^^^
+
+Syntax
+~~~~~~
+
+String expression syntax::
+
+        string_expression ::= ( plain_string | [ varsub ] )*
+        varsub            ::= ( '$' Variable ) | ( '${ Expression }' )
+        plain_string      ::= ( '$$' | non_dollar )*
+        non_dollar        ::= any character except '$'
+
+Description
+~~~~~~~~~~~
+
+String expressions interpret the expression string as text. If no
+expression string is supplied the resulting string is *empty*. The
+string can contain variable substitutions of the form ``$name`` or
+``${expression}``, where ``name`` is a variable name, and ``expression`` is a TALES-expression. The escaped string value of the expression is inserted into the string.
+
+.. note:: To prevent a ``$`` from being interpreted this
+   way, it must be escaped as ``$$``.
+
+Examples
+~~~~~~~~
+
+Basic string formatting::
+
+    <span tal:replace="string:$this and $that">
+      Spam and Eggs
+    </span>
+
+    <p tal:content="string:${request.form['total']}">
+      total: 12
+    </p>
+
+Including a dollar sign::
+
+    <p tal:content="string:$$$cost">
+      cost: $42.00
+    </p>
+
+.. _import-expression:
+
+``import``
+^^^^^^^^^^
+
+Imports a module global.
+
+.. _structure-expression:
+
+``structure``
+^^^^^^^^^^^^^
+
+Wraps the expression result as *structure*: The replacement text is
+inserted into the document without escaping, allowing HTML/XML markup
+to be inserted.  This can break your page if the text contains
+unanticipated markup (eg.  text submitted via a web form), which is
+the reason that it is not the default.
+
+.. _load-expression:
+
+``load``
+^^^^^^^^
+
+Loads a template instance.
+
+Syntax
+~~~~~~
+
+Load expression syntax::
+
+         Relative or absolute file path
+
+Description
+~~~~~~~~~~~
+
+The template will be loaded using the same template class as the
+calling template.
+
+Examples
+~~~~~~~~
+
+Loading a template and using it as a macro::
+
+  <div tal:define="master load: ../master.pt" metal:use-macro="master" />
+
+
+Built-in names
+--------------
+
+These are the names always available in the TALES expression namespace:
+
+- ``default`` - special value used to specify that existing text or attributes should not be replaced. See the documentation for individual TAL statements for details on how they interpret *default*.
+
+- ``repeat`` - the *repeat* variables; see :ref:`tal_repeat` for more
+  information.
+
+- ``template`` - reference to the template which was first called; this symbol is carried over when using macros.
+
+- ``macros`` - reference to the macros dictionary that corresponds to the current template.
+
+
+.. _metal:
+
+Macros (METAL)
+##############
+
+The *Macro Expansion Template Attribute Language* (METAL) standard is
+a facility for HTML/XML macro preprocessing. It can be used in
+conjunction with or independently of TAL and TALES.
+
+Macros provide a way to define a chunk of presentation in one
+template, and share it in others, so that changes to the macro are
+immediately reflected in all of the places that share it.
+Additionally, macros are always fully expanded, even in a template's
+source text, so that the template appears very similar to its final
+rendering.
+
+A single Page Template can accomodate multiple macros.
+
+Namespace
+---------
+
+The METAL namespace URI and recommended alias are currently defined
+as::
+
+        xmlns:metal="http://xml.zope.org/namespaces/metal"
+
+Just like the TAL namespace URI, this URI is not attached to a web
+page; it's just a unique identifier.  This identifier must be used in
+all templates which use METAL.
+
+Statements
+----------
+
+METAL defines a number of statements:
+
+* ``metal:define-macro`` Define a macro.
+* ``metal:use-macro`` Use a macro.
+* ``metal:extend-macro`` Extend a macro.
+* ``metal:define-slot`` Define a macro customization point.
+* ``metal:fill-slot`` Customize a macro.
+
+Although METAL does not define the syntax of expression non-terminals,
+leaving that up to the implementation, a canonical expression syntax
+for use in METAL arguments is described in TALES Specification.
+
+``define-macro``
+^^^^^^^^^^^^^^^^
+
+Defines a macro.
+
+Syntax
+~~~~~~
+
+``metal:define-macro`` syntax::
+
+        argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:define-macro`` statement defines a macro. The macro is named
+by the statement expression, and is defined as the element and its
+sub-tree.
+
+Examples
+~~~~~~~~
+
+Simple macro definition::
+
+        <p metal:define-macro="copyright">
+          Copyright 2011, <em>Foobar</em> Inc.
+        </p>
+
+``define-slot``
+^^^^^^^^^^^^^^^
+
+Defines a macro customization point.
+
+Syntax
+~~~~~~
+
+``metal:define-slot`` syntax::
+
+        argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:define-slot`` statement defines a macro customization
+point or *slot*. When a macro is used, its slots can be replaced, in
+order to customize the macro. Slot definitions provide default content
+for the slot. You will get the default slot contents if you decide not
+to customize the macro when using it.
+
+The ``metal:define-slot`` statement must be used inside a
+``metal:define-macro`` statement.
+
+Slot names must be unique within a macro.
+
+Examples
+~~~~~~~~
+
+Simple macro with slot::
+
+        <p metal:define-macro="hello">
+          Hello <b metal:define-slot="name">World</b>
+        </p>
+
+This example defines a macro with one slot named ``name``. When you use
+this macro you can customize the ``b`` element by filling the ``name``
+slot.
+
+``fill-slot``
+^^^^^^^^^^^^^
+
+Customize a macro.
+
+Syntax
+~~~~~~
+
+``metal:fill-slot`` syntax::
+
+        argument ::= Name
+
+Description
+~~~~~~~~~~~
+
+The ``metal:fill-slot`` statement customizes a macro by replacing a
+*slot* in the macro with the statement element (and its content).
+
+The ``metal:fill-slot`` statement must be used inside a
+``metal:use-macro`` statement.
+
+Slot names must be unique within a macro.
+
+If the named slot does not exist within the macro, the slot
+contents will be silently dropped.
+
+Examples
+~~~~~~~~
+
+Given this macro::
+
+        <p metal:define-macro="hello">
+          Hello <b metal:define-slot="name">World</b>
+        </p>
+
+You can fill the ``name`` slot like so::
+
+        <p metal:use-macro="container['master.html'].macros.hello">
+          Hello <b metal:fill-slot="name">Kevin Bacon</b>
+        </p>
+
+``use-macro``
+^^^^^^^^^^^^^
+
+Use a macro.
+
+Syntax
+~~~~~~
+
+``metal:use-macro`` syntax::
+
+        argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+The ``metal:use-macro`` statement replaces the statement element with
+a macro. The statement expression describes a macro definition.
+
+.. note:: In Chameleon the expression may point to a template instance; in this case it will be rendered in its entirety.
+
+``extend-macro``
+^^^^^^^^^^^^^^^^
+
+Extends a macro.
+
+Syntax
+~~~~~~
+
+``metal:extend-macro`` syntax::
+
+        argument ::= expression
+
+Description
+~~~~~~~~~~~
+
+To extend an existing macro, choose a name for the macro and add a
+define-macro attribute to a document element with the name as the
+argument. Add an extend-macro attribute to the document element with
+an expression referencing the base macro as the argument. The
+extend-macro must be used in conjunction with define-macro, and must
+not be used with use-macro. The element's subtree is the macro
+body.
+
+Examples
+~~~~~~~~
+
+::
+
+        <div metal:define-macro="page-header"
+             metal:extend-macro="standard_macros['page-header']">
+          <div metal:fill-slot="breadcrumbs">
+            You are here:
+            <div metal:define-slot="breadcrumbs"/>
+          </div>
+        </div>
+
+
+.. _i18n:
+
+Translation (I18N)
+##################
+
+Translation of template contents and attributes is supported via the
+``i18n`` namespace and message objects.
+
+Messages
+--------
+
+The translation machinery defines a message as *any object* which is
+not a string or a number and which does not provide an ``__html__``
+method.
+
+When any such object is inserted into the template, the translate
+function is invoked first to see if it needs translation. The result
+is always coerced to a native string before it's inserted into the
+template.
+
+Translation function
+--------------------
+
+The simplest way to hook into the translation machinery is to provide
+a translation function to the template constructor or at
+render-time. In either case it should be passed as the keyword
+argument ``translate``.
+
+The function has the following signature:
+
+.. code-block:: python
+
+   def translate(msgid, domain=None, mapping=None, context=None, target_language=None, default=None):
+       ...
+
+The result should be a string or ``None``. If another type of object
+is returned, it's automatically coerced into a string.
+
+If `zope.i18n <http://pypi.python.org/pypi/zope.i18n>`_ is available,
+the translation machinery defaults to using its translation
+function. Note that this function requires messages to conform to the
+message class from `zope.i18nmessageid
+<http://pypi.python.org/pypi/zope.i18nmessageid>`_; specifically,
+messages must have attributes ``domain``, ``mapping`` and
+``default``. Example use:
+
+.. code-block:: python
+
+   from zope.i18nmessageid import MessageFactory
+   _ = MessageFactory("food")
+
+   apple = _(u"Apple")
+
+There's currently no further support for other translation frameworks.
+
+Using Zope's translation framework
+-----------------------------------
+
+The translation function from ``zope.i18n`` relies on *translation
+domains* to provide translations.
+
+These are components that are registered for some translation domain
+identifier and which implement a ``translate`` method that translates
+messages for that domain.
+
+.. note:: To register translation domain components, the Zope Component Architecture must be used (see `zope.component <http://pypi.python.org/pypi/zope.component>`_).
+
+The easiest way to configure translation domains is to use the the
+``registerTranslations`` ZCML-directive; this requires the use of the
+`zope.configuration <http://pypi.python.org/pypi/zope.configuration>`_
+package. This will set up translation domains and gettext catalogs
+automatically:
+
+.. code-block:: xml
+
+  <configure xmlns="http://namespaces.zope.org/zope"
+             xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+
+     <i18n:registerTranslations directory="locales" />
+
+  </configure>
+
+The ``./locales`` directory must follow a particular directory
+structure:
+
+.. code-block:: bash
+
+  ./locales/en/LC_MESSAGES
+  ./locales/de/LC_MESSAGES
+  ...
+
+In each of the ``LC_MESSAGES`` directories, one `GNU gettext
+<http://en.wikipedia.org/wiki/GNU_gettext>`_ file in the ``.po``
+format must be present per translation domain:
+
+.. code-block:: po
+
+  # ./locales/de/LC_MESSAGES/food.po
+
+  msgid ""
+  msgstr ""
+  "MIME-Version: 1.0\n"
+  "Content-Type: text/plain; charset=UTF-8\n"
+  "Content-Transfer-Encoding: 8bit\n"
+
+  msgid "Apple"
+  msgstr "Apfel"
+
+It may be necessary to compile the message catalog using the
+``msgfmt`` utility. This will produce a ``.mo`` file.
+
+Translation domains without gettext
+-----------------------------------
+
+The following example demonstrates how to manually set up and
+configure a translation domain for which messages are provided
+directly::
+
+  from zope import component
+  from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+
+  food = SimpleTranslationDomain("food", {
+      ('de', u'Apple'): u'Apfel',
+      })
+
+  component.provideUtility(food, food.domain)
+
+An example of a custom translation domain class::
+
+  from zope import interface
+
+  class TranslationDomain(object):
+       interface.implements(ITranslationDomain)
+
+       def translate(self, msgid, mapping=None, context=None,
+                    target_language=None, default=None):
+
+           ...
+
+  component.provideUtility(TranslationDomain(), name="custom")
+
+This approach can be used to integrate other translation catalog
+implementations.
+
+.. highlight:: xml
+
+Namespace
+---------
+
+The ``i18n`` namespace URI and recommended prefix are currently
+defined as::
+
+  xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+
+This is not a URL, but merely a unique identifier.  Do not expect a
+browser to resolve it successfully.
+
+Statements
+----------
+
+The allowable ``i18n`` statements are:
+
+- ``i18n:translate``
+- ``i18n:domain``
+- ``i18n:source``
+- ``i18n:target``
+- ``i18n:name``
+- ``i18n:attributes``
+- ``i18n:data``
+
+``i18n:translate``
+^^^^^^^^^^^^^^^^^^
+
+This attribute is used to mark units of text for translation.  If this
+attribute is specified with an empty string as the value, the message
+ID is computed from the content of the element bearing this attribute.
+Otherwise, the value of the element gives the message ID.
+
+``i18n:domain``
+^^^^^^^^^^^^^^^
+
+The ``i18n:domain`` attribute is used to specify the domain to be used
+to get the translation.  If not specified, the translation services
+will use a default domain.  The value of the attribute is used
+directly; it is not a TALES expression.
+
+``i18n:source``
+^^^^^^^^^^^^^^^
+
+The ``i18n:source`` attribute specifies the language of the text to be
+translated.  The default is ``nothing``, which means we don't provide
+this information to the translation services.
+
+
+``i18n:target``
+^^^^^^^^^^^^^^^
+
+The ``i18n:target`` attribute specifies the language of the
+translation we want to get.  If the value is ``default``, the language
+negotiation services will be used to choose the destination language.
+If the value is ``nothing``, no translation will be performed; this
+can be used to suppress translation within a larger translated unit.
+Any other value must be a language code.
+
+The attribute value is a TALES expression; the result of evaluating
+the expression is the language code or one of the reserved values.
+
+.. note:: ``i18n:target`` is primarily used for hints to text
+   extraction tools and translation teams.  If you had some text that
+   should only be translated to e.g. German, then it probably
+   shouldn't be wrapped in an ``i18n:translate`` span.
+
+``i18n:name``
+^^^^^^^^^^^^^
+
+Name the content of the current element for use in interpolation
+within translated content.  This allows a replaceable component in
+content to be re-ordered by translation.  For example::
+
+    <span i18n:translate=''>
+      <span tal:replace='context.name' i18n:name='name' /> was born in
+      <span tal:replace='context.country_of_birth' i18n:name='country' />.
+    </span>
+
+would cause this text to be passed to the translation service::
+
+    "${name} was born in ${country}."
+
+``i18n:attributes``
+^^^^^^^^^^^^^^^^^^^
+
+This attribute will allow us to translate attributes of HTML tags,
+such as the ``alt`` attribute in the ``img`` tag. The
+``i18n:attributes`` attribute specifies a list of attributes to be
+translated with optional message IDs for each; if multiple attribute
+names are given, they must be separated by semicolons.  Message IDs
+used in this context must not include whitespace.
+
+Note that the value of the particular attributes come either from the
+HTML attribute value itself or from the data inserted by
+``tal:attributes``.
+
+If an attibute is to be both computed using ``tal:attributes`` and
+translated, the translation service is passed the result of the TALES
+expression for that attribute.
+
+An example::
+
+    <img src="http://foo.com/logo" alt="Visit us"
+         tal:attributes="alt context.greeting"
+         i18n:attributes="alt"
+         >
+
+In this example, we let ``tal:attributes`` set the value of the ``alt``
+attribute to the text "Stop by for a visit!".  This text will be
+passed to the translation service, which uses the result of language
+negotiation to translate "Stop by for a visit!" into the requested
+language.  The example text in the template, "Visit us", will simply
+be discarded.
+
+Another example, with explicit message IDs::
+
+    <img src="../icons/uparrow.png" alt="Up"
+         i18n:attributes="src up-arrow-icon; alt up-arrow-alttext"
+         >
+
+Here, the message ID ``up-arrow-icon`` will be used to generate the
+link to an icon image file, and the message ID 'up-arrow-alttext' will
+be used for the "alt" text.
+
+``i18n:data``
+^^^^^^^^^^^^^
+
+Since TAL always returns strings, we need a way in ZPT to translate
+objects, one of the most obvious cases being ``datetime`` objects. The
+``data`` attribute will allow us to specify such an object, and
+``i18n:translate`` will provide us with a legal format string for that
+object.  If ``data`` is used, ``i18n:translate`` must be used to give
+an explicit message ID, rather than relying on a message ID computed
+from the content.
+
+Relation with TAL processing
+----------------------------
+
+The attributes defined in the ``i18n`` namespace modify the behavior
+of the TAL interpreter for the ``tal:attributes``, ``tal:content``,
+``tal:repeat``, and ``tal:replace`` attributes, but otherwise do not
+affect TAL processing.
+
+Since these attributes only affect TAL processing by causing
+translations to occur at specific times, using these with a TAL
+processor which does not support the ``i18n`` namespace degrades well;
+the structural expectations for a template which uses the ``i18n``
+support is no different from those for a page which does not.  The
+only difference is that translations will not be performed in a legacy
+processor.
+
+Relation with METAL processing
+-------------------------------
+
+When using translation with METAL macros, the internationalization
+context is considered part of the specific documents that page
+components are retrieved from rather than part of the combined page.
+This makes the internationalization context lexical rather than
+dynamic, making it easier for a site builder to understand the
+behavior of each element with respect to internationalization.
+
+Let's look at an example to see what this means::
+
+    <html i18n:translate='' i18n:domain='EventsCalendar'
+          metal:use-macro="container['master.html'].macros.thismonth">
+
+      <div metal:fill-slot='additional-notes'>
+        <ol tal:condition="context.notes">
+          <li tal:repeat="note context.notes">
+             <tal:block tal:omit-tag=""
+                        tal:condition="note.heading">
+               <strong tal:content="note.heading">
+                 Note heading goes here
+               </strong>
+               <br />
+             </tal:block>
+             <span tal:replace="note/description">
+               Some longer explanation for the note goes here.
+             </span>
+          </li>
+        </ol>
+      </div>
+
+    </html>
+
+And the macro source::
+
+    <html i18n:domain='CalendarService'>
+      <div tal:replace='python:DateTime().Month()'
+           i18n:translate=''>January</div>
+
+      <!-- really hairy TAL code here ;-) -->
+
+      <div define-slot="additional-notes">
+        Place for the application to add additional notes if desired.
+      </div>
+
+    </html>
+
+Note that the macro is using a different domain than the application
+(which it should be).  With lexical scoping, no special markup needs
+to be applied to cause the slot-filler in the application to be part
+of the same domain as the rest of the application's page components.
+If dynamic scoping were used, the internationalization context would
+need to be re-established in the slot-filler.
+
+
+Extracting translatable message
+-------------------------------
+
+Translators use `PO files
+<http://www.gnu.org/software/hello/manual/gettext/PO-Files.html>`_
+when translating messages. To create and update PO files you need to
+do two things: *extract* all messages from python and templates files
+and store them in a ``.pot`` file, and for each language *update* its
+``.po`` file.  Chameleon facilitates this by providing extractors for
+`Babel <http://babel.edgewall.org/>`_.  To use this you need modify
+``setup.py``. For example:
+
+.. code-block:: python
+
+   from setuptools import setup
+
+   setup(name="mypackage",
+         install_requires = [
+               "Babel",
+               ],
+         message_extractors = { "src": [
+               ("**.py",   "chameleon_python", None ),
+               ("**.pt",   "chameleon_xml", None ),
+               ]},
+         )
+
+This tells Babel to scan the ``src`` directory while using the
+``chameleon_python`` extractor for all ``.py`` files and the
+``chameleon_xml`` extractor for all ``.pt`` files.
+
+You can now use Babel to manage your PO files:
+
+.. code-block:: bash
+
+   python setup.py extract_messages --output-file=i18n/mydomain.pot
+   python setup.py update_catalog \
+             -l nl \
+             -i i18n/mydomain.pot \
+             -o i18n/nl/LC_MESSAGES/mydomain.po
+   python setup.py compile_catalog \
+             --directory i18n --locale nl
+
+You can also configure default options in a ``setup.cfg`` file. For example::
+
+   [compile_catalog]
+   domain = mydomain
+   directory = i18n
+   
+   [extract_messages]
+   copyright_holder = Acme Inc.
+   output_file = i18n/mydomain.pot
+   charset = UTF-8
+
+   [init_catalog]
+   domain = mydomain
+   input_file = i18n/mydomain.pot
+   output_dir = i18n
+
+   [update_catalog]
+   domain = mydomain
+   input_file = i18n/mydomain.pot
+   output_dir = i18n
+   previous = true
+
+You can now use the Babel commands directly::
+
+   python setup.py extract_messages
+   python setup.py update_catalog
+   python setup.py compile_catalog
+
+
+${...} operator
+###############
+
+The ``${...}`` notation is short-hand for text insertion. The
+Python-expression inside the braces is evaluated and the result
+included in the output (all inserted text is escaped by default):
+
+.. code-block:: html
+
+  <div id="section-${index + 1}">
+    ${content}
+  </div>
+
+To escape this behavior, prefix the notation with a backslash
+character: ``\${...}``.
+
+Note that if an object implements the ``__html__`` method, the result
+of this method will be inserted as-is (without XML escaping).
+
+Code blocks
+###########
+
+The ``<?python ... ?>`` notation allows you to embed Python code in
+templates:
+
+.. code-block:: html
+
+  <div>
+    <?python numbers = map(str, range(1, 10)) ?>
+    Please input a number from the range ${", ".join(numbers)}.
+  </div>
+
+The scope of name assignments is up to the nearest macro definition,
+or the template, if macros are not used.
+
+Note that code blocks can span multiple line and start on the next
+line of where the processing instruction begins:
+
+.. code-block:: html
+
+  <?python
+    foo = [1, 2, 3]
+  ?>
+
+You can use this to debug templates:
+
+.. code-block:: html
+
+  <div>
+    <?python import pdb; pdb.set_trace() ?>
+  </div>
+
+
+Markup comments
+###############
+
+You can apply the "!" and "?" modifiers to change how comments are
+processed:
+
+Drop
+
+  ``<!--! This comment will be dropped from output -->``
+
+Verbatim
+
+  ``<!--? This comment will be included verbatim -->``
+
+  That is, evaluation of ``${...}`` expressions is disabled if the
+  comment opens with the "?" character.
+
+
+.. _new-features:
+
+Language extensions
+###################
+
+Chameleon extends the *page template* language with a new expression
+types and language features. Some take inspiration from `Genshi
+<http://genshi.edgewall.org/>`_.
+
+    *New expression types*
+
+       The :ref:`structure <structure-expression>` expression wraps an
+       expression result as *structure*::
+
+         <div>${structure: body.text}</div>
+
+       The :ref:`import <import-expression>` expression imports module globals::
+
+         <div tal:define="compile import: re.compile">
+           ...
+         </div>
+
+       The :ref:`load <load-expression>` expression loads templates
+       relative to the current template::
+
+         <div tal:define="compile load: main.pt">
+           ...
+         </div>
+
+    *Tuple unpacking*
+
+       The ``tal:define`` and ``tal:repeat`` statements support tuple
+       unpacking::
+
+          tal:define="(a, b, c) [1, 2, 3]"
+
+       Extended `iterable unpacking
+       <http://www.python.org/dev/peps/pep-3132/>`_ using the asterisk
+       character is not currently supported (even for versions of
+       Python that support it natively).
+
+    *Dictionary lookup as fallback after attribute error*
+
+       If attribute lookup (using the ``obj.<name>`` syntax) raises an
+       ``AttributeError`` exception, a secondary lookup is attempted
+       using dictionary lookup --- ``obj['<name>']``.
+
+       Behind the scenes, this is done by rewriting all
+       attribute-lookups to a custom lookup call:
+
+       .. code-block:: python
+
+            def lookup_attr(obj, key):
+                try:
+                    return getattr(obj, key)
+                except AttributeError as exc:
+                    try:
+                        get = obj.__getitem__
+                    except AttributeError:
+                        raise exc
+                    try:
+                        return get(key)
+                    except KeyError:
+                        raise exc
+
+    *Inline string substitution*
+
+       In element attributes and in the text or tail of an element,
+       string expression interpolation is available using the
+       ``${...}`` syntax::
+
+          <span class="content-${item_type}">
+             ${title or item_id}
+          </span>
+
+    *Code blocks*
+
+        Using ``<?python ... ?>`` notation, you can embed Python
+        statements in your templates:
+
+        .. code-block:: html
+
+          <div>
+            <?python numbers = map(str, range(1, 10)) ?>
+            Please input a number from the range ${", ".join(numbers)}.
+          </div>
+
+    *Literal content*
+
+       While the ``tal:content`` and ``tal:repeat`` attributes both
+       support the ``structure`` keyword which inserts the content as
+       a literal (without XML-escape), an object may also provide an
+       ``__html__`` method to the same effect.
+
+       The result of the method will be inserted as *structure*.
+
+       This is particularly useful for content which is substituted
+       using the expression operator: ``"${...}"`` since the
+       ``structure`` keyword is not allowed here.
+
+    *Switch statement*
+
+       Two new attributes have been added: ``tal:switch`` and
+       ``tal:case``. A case attribute works like a condition and only
+       allows content if the value matches that of the nearest parent
+       switch value.
+
+
+Incompatibilities and differences
+#################################
+
+There are a number of incompatibilities and differences between the
+Chameleon language implementation and the Zope reference
+implementation (ZPT):
+
+    *Default expression*
+
+       The default expression type is Python.
+
+    *Template arguments*
+
+      Arguments passed by keyword to the render- or call method are
+      inserted directly into the template execution namespace. This is
+      different from ZPT where these are only available through the
+      ``options`` dictionary.
+
+      Zope::
+
+        <div tal:content="options/title" />
+
+      Chameleon::
+
+        <div tal:content="title" />
+
+    *Special symbols*
+
+      The ``CONTEXTS`` symbol is not available.
+
+The `z3c.pt <http://pypi.python.org/pypi/z3c.pt>`_ package works as a
+compatibility layer. The template classes in this package provide a
+implementation which is fully compatible with ZPT.
+
+Notes
+#####
+
+.. [1] This has been changed in 2.x. Previously, it was up to the
+       expression engine to parse the expression values including any
+       semicolons and since for instance Python-expressions can never
+       end in a semicolon, it was possible to clearly distinguish
+       between the different uses of the symbol, e.g.
+
+       ::
+
+         tal:define="text 'Hello world; goodbye world'"
+
+       The semicolon appearing in the definition above is part of the
+       Python-expression simply because it makes the expression
+       valid. Meanwhile:
+
+       ::
+
+         tal:define="text1 'Hello world'; text2 'goodbye world'"
+
+       The semicolon here must denote a second variable definition
+       because there is no valid Python-expression that includes it.
+
+       While this behavior works well in practice, it is incompatible
+       with the reference specification, and also blurs the interface
+       between the compiler and the expression engine. In 2.x we
+       therefore have to escape the semicolon by doubling it (as
+       defined by the specification):
+
+       ::
+
+         tal:define="text 'Hello world;; goodbye world'"
+
diff --git a/lib/Chameleon-2.9.2/setup.cfg b/lib/Chameleon-2.9.2/setup.cfg
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/setup.cfg
@@ -0,0 +1,14 @@
+[easy_install]
+zip_ok = false
+
+[nosetests]
+match = ^test
+nocapture = 1
+cover-package = tree.codegen, tree.lexer, tree.parser, tree.nodes, tree.translation, tree.language, tree.tales, tree.expressions
+cover-erase = 1
+
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/lib/Chameleon-2.9.2/setup.py b/lib/Chameleon-2.9.2/setup.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/setup.py
@@ -0,0 +1,90 @@
+__version__ = '2.9.2'
+
+import os
+import sys
+
+try:
+    from distribute_setup import use_setuptools
+    use_setuptools()
+except:  # doesn't work under tox/pip
+    pass
+
+from setuptools import setup, find_packages
+from setuptools.command.test import test
+
+here = os.path.abspath(os.path.dirname(__file__))
+try:
+    README = open(os.path.join(here, 'README.rst')).read()
+    CHANGES = open(os.path.join(here, 'CHANGES.rst')).read()
+except:  # doesn't work under tox/pip
+    README = ''
+    CHANGES = ''
+
+install_requires = []
+
+version = sys.version_info[:3]
+if version < (2, 7, 0):
+    install_requires.append("ordereddict")
+    install_requires.append("unittest2")
+
+
+class Benchmark(test):
+    description = "Run benchmarks"
+    user_options = []
+    test_suite = None
+
+    def initialize_options(self):
+        """init options"""
+        pass
+
+    def finalize_options(self):
+        """finalize options"""
+
+        self.distribution.tests_require = [
+            'zope.pagetemplate',
+            'zope.component',
+            'zope.i18n',
+            'zope.testing']
+
+    def run(self):
+        test.run(self)
+        self.with_project_on_sys_path(self.run_benchmark)
+
+    def run_benchmark(self):
+        from chameleon import benchmark
+        print("running benchmark...")
+
+        benchmark.start()
+
+setup(
+    name="Chameleon",
+    version=__version__,
+    description="Fast HTML/XML Template Compiler.",
+    long_description="\n\n".join((README, CHANGES)),
+    classifiers=[
+       "Development Status :: 5 - Production/Stable",
+       "Intended Audience :: Developers",
+       "Programming Language :: Python",
+       "Programming Language :: Python :: 2",
+       "Programming Language :: Python :: 3",
+       "Programming Language :: Python :: 2.5",
+       "Programming Language :: Python :: 2.6",
+       "Programming Language :: Python :: 2.7",
+       "Programming Language :: Python :: 3.1",
+       "Programming Language :: Python :: 3.2",
+      ],
+    author="Malthe Borch",
+    author_email="mborch at gmail.com",
+    url="http://www.pagetemplates.org/",
+    license='BSD-like (http://repoze.org/license.html)',
+    packages=find_packages('src'),
+    package_dir = {'': 'src'},
+    include_package_data=True,
+    install_requires=install_requires,
+    zip_safe=False,
+    test_suite="chameleon.tests",
+    cmdclass={
+        'benchmark': Benchmark,
+        }
+    )
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/PKG-INFO
@@ -0,0 +1,1122 @@
+Metadata-Version: 1.1
+Name: Chameleon
+Version: 2.9.2
+Summary: Fast HTML/XML Template Compiler.
+Home-page: http://www.pagetemplates.org/
+Author: Malthe Borch
+Author-email: mborch at gmail.com
+License: BSD-like (http://repoze.org/license.html)
+Description: Overview
+        ========
+        
+        Chameleon is an HTML/XML template engine for `Python
+        <http://www.python.org>`_. It uses the *page templates* language.
+        
+        You can use it in any Python web application with just about any
+        version of Python (2.5 and up, including 3.x and `pypy
+        <http://pypy.org>`_).
+        
+        Visit the `website <http://pagetemplates.org>`_ for more information
+        or the `documentation <http://pagetemplates.org/docs/latest/>`_.
+        
+        License and Copyright
+        ---------------------
+        
+        This software is made available as-is under a BSD-like license [1]_
+        (see included copyright notice).
+        
+        
+        Notes
+        -----
+        
+        .. [1] This software is licensed under the `Repoze
+               <http://repoze.org/license.html>`_ license.
+        
+        
+        Changes
+        =======
+        
+        2.9.2 (2012-06-06)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed a PyPy incompatibility.
+        
+        - Fixed issue #109 which caused testing failures on some platforms.
+        
+        2.9.1 (2012-06-01)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue #103. The ``tal:on-error`` statement now always adds an
+          explicit end-tag to the element, even with a substitution content of
+          nothing.
+        
+        - Fixed issue #113. The ``tal:on-error`` statement now works correctly
+          also for dynamic attributes. That is, the fallback tag now includes
+          only static attributes.
+        
+        - Fixed name error which prevented the benchmark from running
+          correctly.
+        
+        Compatibility:
+        
+        - Fixed deprecation warning on Python 3 for zope interface implements
+          declaration. This fixes issue #116.
+        
+        2.9.0 (2012-05-31)
+        ------------------
+        
+        Features:
+        
+        - The translation function now gets the ``econtext`` argument as the
+          value for ``context``. Note that historically, this was usually an
+          HTTP request which might provide language negotiation data through a
+          dictionary interface.
+          [alvinyue]
+        
+        Bugfixes:
+        
+        - Fixed import alias issue which would lead to a syntax error in
+          generated Python code. Fixes issue #114.
+        
+        2.8.5 (2012-05-02)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed minor installation issues on Python 2.5 and 3.
+          [ppaez]
+        
+        - Ensure output is unicode even when trivial (an empty string).
+        
+        2.8.4 (2012-04-18)
+        ------------------
+        
+        Features:
+        
+        - In exception output, long filenames are now truncated to 60
+          characters of output, preventing line wrap which makes it difficult
+          to scan the exception output.
+        
+        Bugfixes:
+        
+        - Include filename and location in exception output for exceptions
+          raised during compilation.
+        
+        - If a trivial translation substitution variable is given (i.e. an
+          empty string), simply ignore it. This fixes issue #106.
+        
+        2.8.3 (2012-04-16)
+        ------------------
+        
+        Features:
+        
+        - Log template source on debug-level before cooking.
+        
+        - The `target_language` argument, if given, is now available as a
+          variable in templates.
+        
+        2.8.2 (2012-03-30)
+        ------------------
+        
+        Features:
+        
+        - Temporary caches used in debug mode are cleaned up eagerly, rather
+          than waiting for process termination.
+          [mitchellrj]
+        
+        Bugfixes:
+        
+        - The `index`, `start` and `end` methods on the TAL repeat object are
+          now callable. This fixes an incompatibility with ZPT.
+        
+        - The loader now correctly handles absolute paths on Windows.
+          [rdale]
+        
+        2.8.1 (2012-03-29)
+        ------------------
+        
+        Features:
+        
+        - The exception formatter now lists errors in 'wrapping order'. This
+          means that the innermost, and presumably most relevant exception is
+          shown last.
+        
+        Bugfixes:
+        
+        - The exception formatter now correctly recognizes nested errors and
+          does not rewrap the dynamically generated exception class.
+        
+        - The exception formatter now correctly sets the ``__module__``
+          attribute to that of the original exception class.
+        
+        2.8.0 (2012-02-29)
+        ------------------
+        
+        Features:
+        
+        - Added support for code blocks using the `<?python ... ?>` processing
+          instruction syntax.
+        
+          The scope is name assignments is up until the nearest macro
+          definition, or the template itself if macros are not used.
+        
+        Bugfixes:
+        
+        - Fall back to the exception class' ``__new__`` method to safely
+          create an exception object that is not implemented in Python.
+        
+        - The exception formatter now keeps track of already formatted
+          exceptions, and ignores them from further output.
+        
+        2.7.4 (2012-02-27)
+        ------------------
+        
+        - The error handler now invokes the ``__init__`` method of
+          ``BaseException`` instead of the possibly overriden method (which
+          may take required arguments). This fixes issue #97.
+          [j23d, malthe]
+        
+        2.7.3 (2012-01-16)
+        ------------------
+        
+        Bugfixes:
+        
+        - The trim whitespace option now correctly trims actual whitespace to
+          a single character, appearing either to the left or to the right of
+          an element prefix or suffix string.
+        
+        2.7.2 (2012-01-08)
+        ------------------
+        
+        Features:
+        
+        - Added option ``trim_attribute_space`` that decides whether attribute
+          whitespace is stripped (at most down to a single space). This option
+          exists to provide compatibility with the reference
+          implementation. Fixes issue #85.
+        
+        Bugfixes:
+        
+        - Ignore unhashable builtins when generating a reverse builtin
+          map to quickly look up a builtin value.
+          [malthe]
+        
+        - Apply translation mapping even when a translation function is not
+          available. This fixes issue #83.
+          [malthe]
+        
+        - Fixed issue #80. The translation domain for a slot is defined by the
+          source document, i.e. the template providing the content for a slot
+          whether it be the default or provided through ``metal:fill-slot``.
+          [jcbrand]
+        
+        - In certain circumstances, a Unicode non-breaking space character would cause
+          a define clause to fail to parse.
+        
+        2.7.1 (2011-12-29)
+        ------------------
+        
+        Features:
+        
+        - Enable expression interpolation in CDATA.
+        
+        - The page template class now implements dictionary access to macros::
+        
+             template[name]
+        
+          This is a short-hand for::
+        
+             template.macros[name]
+        
+        Bugfixes:
+        
+        - An invalid define clause would be silently ignored; we now raise a
+          language error exception. This fixes issue #79.
+        
+        - Fixed regression where ``${...}`` interpolation expressions could
+          not span multiple lines. This fixes issue #77.
+        
+        2.7.0 (2011-12-13)
+        ------------------
+        
+        Features:
+        
+        - The ``load:`` expression now derives from the string expression such
+          that the ``${...}`` operator can be used for expression
+          interpolation.
+        
+        - The ``load:`` expression now accepts asset specs; these are resolved
+          by the ``pkg_resources.resource_filename`` function::
+        
+            <package_name>:<path>
+        
+          An example from the test suite::
+        
+            chameleon:tests/inputs/hello_world.pt
+        
+        Bugfixes:
+        
+        - If an attribute name for translation was not a valid Python
+          identifier, the compiler would generate invalid code. This has been
+          fixed, and the compiler now also throws an exception if an attribute
+          specification contains a comma. (Note that the only valid separator
+          character is the semicolon, when specifying attributes for
+          translation via the ``i18n:translate`` statement). This addresses
+          issue #76.
+        
+        2.6.2 (2011-12-08)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where ``tal:on-error`` would not respect
+          ``tal:omit-tag`` or namespace elements which are omitted by default
+          (such as ``<tal:block />``).
+        
+        - Fixed issue where ``macros`` attribute would not be available on
+          file-based templates due to incorrect initialization.
+        
+        - The ``TryExcept`` and ``TryFinally`` AST nodes are not available on
+          Python 3.3. These have been aliased to ``Try``. This fixes issue
+          #75.
+        
+        Features:
+        
+        - The TAL repeat item now makes a security declaration that grants
+          access to unprotected subobjects on the Zope 2 platform::
+        
+            __allow_access_to_unprotected_subobjects__ = True
+        
+          This is required for legacy compatibility and does not affect other
+          environments.
+        
+        - The template object now has a method ``write(body)`` which
+          explicitly decodes and cooks a string input.
+        
+        - Added configuration option ``loader_class`` which sets the class
+          used to create the template loader object.
+        
+          The class (essentially a callable) is created at template
+          construction time.
+        
+        2.6.1 (2011-11-30)
+        ------------------
+        
+        Bugfixes:
+        
+        - Decode HTML entities in expression interpolation strings. This fixes
+          issue #74.
+        
+        - Allow ``xml`` and ``xmlns`` attributes on TAL, I18N and METAL
+          namespace elements. This fixes issue #73.
+        
+        2.6.0 (2011-11-24)
+        ------------------
+        
+        Features:
+        
+        - Added support for implicit translation:
+        
+          The ``implicit_i18n_translate`` option enables implicit translation
+          of text. The ``implicit_i18n_attributes`` enables implicit
+          translation of attributes. The latter must be a set and for an
+          attribute to be implicitly translated, its lowercase string value
+          must be included in the set.
+        
+        - Added option ``strict`` (enabled by default) which decides whether
+          expressions are required to be valid at compile time. That is, if
+          not set, an exception is only raised for an invalid expression at
+          evaluation time.
+        
+        - An expression error now results in an exception only if the
+          expression is attempted evaluated during a rendering.
+        
+        - Added a configuration option ``prepend_relative_search_path`` which
+          decides whether the path relative to a file-based template is
+          prepended to the load search path. The default is ``True``.
+        
+        - Added a configuration option ``search_path`` to the file-based
+          template class, which adds additional paths to the template load
+          instance bound to the ``load:`` expression. The option takes a
+          string path or an iterable yielding string paths. The default value
+          is the empty set.
+        
+        Bugfixes:
+        
+        - Exception instances now support pickle/unpickle.
+        
+        - An attributes in i18n:attributes no longer needs to match an
+          existing or dynamic attribute in order to appear in the
+          element. This fixes issue #66.
+        
+        2.5.3 (2011-10-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where a nested macro slot definition would fail even
+          though there existed a parent macro definition. This fixes issue
+          #69.
+        
+        2.5.2 (2011-10-12)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where technically invalid input would result in a
+          compiler error.
+        
+        Features:
+        
+        - The markup class now inherits from the unicode string type such that
+          it's compatible with the string interface.
+        
+        2.5.1 (2011-09-29)
+        ------------------
+        
+        Bugfixes:
+        
+        - The symbol names "convert", "decode" and "translate" are now no
+          longer set as read-only *compiler internals*. This fixes issue #65.
+        
+        - Fixed an issue where a macro extension chain nested two levels (a
+          template uses a macro that extends a macro) would lose the middle
+          slot definitions if slots were defined nested.
+        
+          The compiler now throws an error if a nested slot definition is used
+          outside a macro extension context.
+        
+        2.5.0 (2011-09-23)
+        ------------------
+        
+        Features:
+        
+        - An expression type ``structure:`` is now available which wraps the
+          expression result as *structure* such that it is not escaped on
+          insertion, e.g.::
+        
+            <div id="content">
+               ${structure: context.body}
+            </div>
+        
+          This also means that the ``structure`` keyword for ``tal:content``
+          and ``tal:replace`` now has an alternative spelling via the
+          expression type ``structure:``.
+        
+        - The string-based template constructor now accepts encoded input.
+        
+        2.4.6 (2011-09-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - The ``tal:on-error`` statement should catch all exceptions.
+        
+        - Fixed issue that would prevent escaping of interpolation expression
+          values appearing in text.
+        
+        2.4.5 (2011-09-21)
+        ------------------
+        
+        Bugfixes:
+        
+        - The ``tal:on-error`` handler should have a ``error`` variable
+          defined that has the value of the exception thrown.
+        
+        - The ``tal:on-error`` statement is a substitution statement and
+          should support the "text" and "structure" insertion methods.
+        
+        2.4.4 (2011-09-15)
+        ------------------
+        
+        Bugfixes:
+        
+        - An encoding specified in the XML document preamble is now read and
+          used to decode the template input to unicode. This fixes issue #55.
+        
+        - Encoded expression input on Python 3 is now correctly
+          decoded. Previously, the string representation output would be
+          included instead of an actually decoded string.
+        
+        - Expression result conversion steps are now correctly included in
+          error handling such that the exception output points to the
+          expression location.
+        
+        2.4.3 (2011-09-13)
+        ------------------
+        
+        Features:
+        
+        - When an encoding is provided, pass the 'ignore' flag to avoid
+          decoding issues with bad input.
+        
+        Bugfixes:
+        
+        - Fixed pypy compatibility issue (introduced in previous release).
+        
+        2.4.2 (2011-09-13)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue in the compiler where an internal variable (such as a
+          translation default value) would be cached, resulting in variable
+          scope corruption (see issue #49).
+        
+        2.4.1 (2011-09-08)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where a default value for an attribute would
+          sometimes spill over into another attribute.
+        
+        - Fixed issue where the use of the ``default`` name in an attribute
+          interpolation expression would print the attribute value. This is
+          unexpected, because it's an expression, not a static text suitable
+          for output. An attribute value of ``default`` now correctly drops
+          the attribute.
+        
+        2.4.0 (2011-08-22)
+        ------------------
+        
+        Features:
+        
+        - Added an option ``boolean_attributes`` to evaluate and render a
+          provided set of attributes using a boolean logic: if the attribute
+          is a true value, the value will be the attribute name, otherwise the
+          attribute is dropped.
+        
+          In the reference implementation, the following attributes are
+          configured as boolean values when the template is rendered in
+          HTML-mode::
+        
+              "compact", "nowrap", "ismap", "declare", "noshade",
+              "checked", "disabled", "readonly", "multiple", "selected",
+              "noresize", "defer"
+        
+          Note that in Chameleon, these attributes must be manually provided.
+        
+        Bugfixes:
+        
+        - The carriage return character (used on Windows platforms) would
+          incorrectly be included in Python comments.
+        
+          It is now replaced with a line break.
+        
+          This fixes issue #44.
+        
+        2.3.8 (2011-08-19)
+        ------------------
+        
+        - Fixed import error that affected Python 2.5 only.
+        
+        2.3.7 (2011-08-19)
+        ------------------
+        
+        Features:
+        
+        - Added an option ``literal_false`` that disables the default behavior
+          of dropping an attribute for a value of ``False`` (in addition to
+          ``None``). This modified behavior is the behavior exhibited in
+          reference implementation.
+        
+        Bugfixes:
+        
+        - Undo attribute special HTML attribute behavior (see previous
+          release).
+        
+          This turned out not to be a compatible behavior; rather, boolean
+          values should simply be coerced to a string.
+        
+          Meanwhile, the reference implementation does support an HTML mode in
+          which the special attribute behavior is exhibited.
+        
+          We do not currently support this mode.
+        
+        2.3.6 (2011-08-18)
+        ------------------
+        
+        Features:
+        
+        - Certain HTML attribute names now have a special behavior for a
+          attribute value of ``True`` (or ``default`` if no default is
+          defined). For these attributes, this return value will result in the
+          name being printed as the value::
+        
+            <input type="input" tal:attributes="checked True" />
+        
+          will be rendered as::
+        
+            <input type="input" checked="checked" />
+        
+          This behavior is compatible with the reference implementation.
+        
+        2.3.5 (2011-08-18)
+        ------------------
+        
+        Features:
+        
+        - Added support for the set operator (``{item, item, ...}``).
+        
+        Bugfixes:
+        
+        - If macro is defined on the same element as a translation name, this
+          no longer results in a "translation name not allowed outside
+          translation" error. This fixes issue #43.
+        
+        - Attribute fallback to dictionary lookup now works on multiple items
+          (e.g. ``d1.d2.d2``). This fixes issue #42.
+        
+        2.3.4 (2011-08-16)
+        ------------------
+        
+        Features:
+        
+        - When inserting content in either attributes or text, a value of
+          ``True`` (like ``False`` and ``None``) will result in no
+          action.
+        
+        - Use statically assigned variables for ``"attrs"`` and
+          ``"default"``. This change yields a performance improvement of
+          15-20%.
+        
+        - The template loader class now accepts an optional argument
+          ``default_extension`` which accepts a filename extension which will
+          be appended to the filename if there's not already an extension.
+        
+        Bugfixes:
+        
+        - The default symbol is now ``True`` for an attribute if the attribute
+          default is not provided. Note that the result is that the attribute
+          is dropped. This fixes issue #41.
+        
+        - Fixed an issue where assignment to a variable ``"type"`` would
+          fail. This fixes issue #40.
+        
+        - Fixed an issue where an (unsuccesful) assignment for a repeat loop
+          to a compiler internal name would not result in an error.
+        
+        - If the translation function returns the identical object, manually
+          coerce it to string. This fixes a compatibility issue with
+          translation functions which do not convert non-string objects to a
+          string value, but simply return them unchanged.
+        
+        2.3.3 (2011-08-15)
+        ------------------
+        
+        Features:
+        
+        - The ``load:`` expression now passes the initial keyword arguments to
+          its template loader (e.g. ``auto_reload`` and ``encoding``).
+        
+        - In the exception output, string variable values are now limited to a
+          limited output of characters, single line only.
+        
+        Bugfixes:
+        
+        - Fixed horizontal alignment of exception location info
+          (i.e. 'String:', 'Filename:' and 'Location:') such that they match
+          the template exception formatter.
+        
+        2.3.2 (2011-08-11)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where i18n:domain would not be inherited through macros
+          and slots. This fixes issue #37.
+        
+        2.3.1 (2011-08-11)
+        ------------------
+        
+        Features:
+        
+        - The ``Builtin`` node type may now be used to represent any Python
+          local or global name. This allows expression compilers to refer to
+          e.g. ``get`` or ``getitem``, or to explicit require a builtin object
+          such as one from the ``extra_builtins`` dictionary.
+        
+        Bugfixes:
+        
+        - Builtins which are not explicitly disallowed may now be redefined
+          and used as variables (e.g. ``nothing``).
+        
+        - Fixed compiler issue with circular node annotation loop.
+        
+        2.3 (2011-08-10)
+        ----------------
+        
+        Features:
+        
+        - Added support for the following syntax to disable inline evaluation
+          in a comment:
+        
+            <!--? comment appears verbatim (no ${...} evaluation) -->
+        
+          Note that the initial question mark character (?) will be omitted
+          from output.
+        
+        - The parser now accepts '<' and '>' in attributes. Note that this is
+          invalid markup. Previously, the '<' would not be accepted as a valid
+          attribute value, but this would result in an 'unexpected end tag'
+          error elsewhere. This fixes issue #38.
+        
+        - The expression compiler now provides methods ``assign_text`` and
+          ``assign_value`` such that a template engine might configure this
+          value conversion to support e.g. encoded strings.
+        
+          Note that currently, the only client for the ``assign_text`` method
+          is the string expression type.
+        
+        - Enable template loader for string-based template classes. Note that
+          the ``filename`` keyword argument may be provided on initialization
+          to identify the template source by filename. This fixes issue #36.
+        
+        - Added ``extra_builtins`` option to the page template class. These
+          builtins are added to the default builtins dictionary at cook time
+          and may be provided at initialization using the ``extra_builtins``
+          keyword argument.
+        
+        Bugfixes:
+        
+        - If a translation domain is set for a fill slot, use this setting
+          instead of the macro template domain.
+        
+        - The Python expression compiler now correctly decodes HTML entities
+          ``'gt'`` and ``'lt'``. This fixes issue #32.
+        
+        - The string expression compiler now correctly handles encoded text
+          (when support for encoded strings is enabled). This fixes issue #35.
+        
+        - Fixed an issue where setting the ``filename`` attribute on a
+          file-based template would not automatically cause an invalidation.
+        
+        - Exceptions raised by Chameleon can now be copied via
+          ``copy.copy``. This fixes issue #36.
+          [leorochael]
+        
+        - If copying the exception fails in the exception handler, simply
+          re-raise the original exception and log a warning.
+        
+        2.2 (2011-07-28)
+        ----------------
+        
+        Features:
+        
+        - Added new expression type ``load:`` that allows loading a
+          template. Both relative and absolute paths are supported. If the
+          path given is relative, then it will be resolved with respect to the
+          directory of the template.
+        
+        - Added support for dynamic evaluation of expressions.
+        
+          Note that this is to support legacy applications. It is not
+          currently wired into the provided template classes.
+        
+        - Template classes now have a ``builtins`` attribute which may be used
+          to define built-in variables always available in the template
+          variable scope.
+        
+        Incompatibilities:
+        
+        - The file-based template class no longer accepts a parameter
+          ``loader``. This parameter would be used to load a template from a
+          relative path, using a ``find(filename)`` method. This was however,
+          undocumented, and probably not very useful since we have the
+          ``TemplateLoader`` mechanism already.
+        
+        - The compiled template module now contains an ``initialize`` function
+          which takes values that map to the template builtins. The return
+          value of this function is a dictionary that contains the render
+          functions.
+        
+        Bugfixes:
+        
+        - The file-based template class no longer verifies the existance of a
+          template file (using ``os.lstat``). This now happens implicitly if
+          eager parsing is enabled, or otherwise when first needed (e.g. at
+          render time).
+        
+          This is classified as a bug fix because the previous behavior was
+          probably not what you'd expect, especially if an application
+          initializes a lot of templates without needing to render them
+          immediately.
+        
+        2.1.1 (2011-07-28)
+        ------------------
+        
+        Features:
+        
+        - Improved exception display. The expression string is now shown in
+          the context of the original source (if available) with a marker
+          string indicating the location of the expression in the template
+          source.
+        
+        Bugfixes:
+        
+        - The ``structure`` insertion mode now correctly decodes entities for
+          any expression type (including ``string:``). This fixes issue #30.
+        
+        - Don't show internal variables in the exception formatter variable
+          listing.
+        
+        2.1 (2011-07-25)
+        ----------------
+        
+        Features:
+        
+        - Expression interpolation (using the ``${...}`` operator and
+          previously also ``$identifier``) now requires braces everywhere
+          except inside the ``string:`` expression type.
+        
+          This change is motivated by a number of legacy templates in which
+          the interpolation format without braces ``$identifier`` appears as
+          text.
+        
+        2.0.2 (2011-07-25)
+        ------------------
+        
+        Bugfixes:
+        
+        - Don't use dynamic variable scope for lambda-scoped variables (#27).
+        
+        - Avoid duplication of exception class and message in traceback.
+        
+        - Fixed issue where a ``metal:fill-slot`` would be ignored if a macro
+          was set to be used on the same element (#16).
+        
+        2.0.1 (2011-07-23)
+        ------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where global variable definition from macro slots would
+          fail (they would instead be local). This also affects error
+          reporting from inside slots because this would be recorded
+          internally as a global.
+        
+        - Fixed issue with template cache digest (used for filenames); modules
+          are now invalidated whenever any changes are made to the
+          distribution set available (packages on ``sys.path``).
+        
+        - Fixed exception handler to better let exceptions propagate through
+          the renderer.
+        
+        - The disk-based module compiler now mangles template source filenames
+          such that the output Python module is valid and at root level (dots
+          and hyphens are replaced by an underscore). This fixes issue #17.
+        
+        - Fixed translations (i18n) on Python 2.5.
+        
+        2.0 (2011-07-14)
+        ----------------
+        
+        - Point release.
+        
+        2.0-rc14 (2011-07-13)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The tab character (``\t``) is now parsed correctly when used inside
+          tags.
+        
+        Features:
+        
+        - The ``RepeatDict`` class now works as a proxy behind a seperate
+          dictionary instance.
+        
+        - Added template constructor option ``keep_body`` which is a flag
+          (also available as a class attribute) that controls whether to save
+          the template body input in the ``body`` attribute.
+        
+          This is disabled by default, unless debug-mode is enabled.
+        
+        - The page template loader class now accepts an optional ``formats``
+          argument which can be used to select an alternative template class.
+        
+        2.0-rc13 (2011-07-07)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The backslash character (followed by optional whitespace and a line
+          break) was not correctly interpreted as a continuation for Python
+          expressions.
+        
+        Features:
+        
+        - The Python expression implementation is now more flexible for
+          external subclassing via a new ``parse`` method.
+        
+        2.0-rc12 (2011-07-04)
+        ---------------------
+        
+        Bugfixes:
+        
+        - Initial keyword arguments passed to a template now no longer "leak"
+          into the template variable space after a macro call.
+        
+        - An unexpected end tag is now an unrecoverable error.
+        
+        Features:
+        
+        - Improve exception output.
+        
+        2.0-rc11 (2011-05-26)
+        ---------------------
+        
+        Bugfixes:
+        
+        - Fixed issue where variable names that begin with an underscore were
+          seemingly allowed, but their use resulted in a compiler error.
+        
+        Features:
+        
+        - Template variable names are now allowed to be prefixed with a single
+          underscore, but not two or more (reserved for internal use).
+        
+          Examples of valid names::
+        
+            item
+            ITEM
+            _item
+            camelCase
+            underscore_delimited
+            help
+        
+        - Added support for Genshi's comment "drop" syntax::
+        
+            <!--! This comment will be dropped -->
+        
+          Note the additional exclamation (!) character.
+        
+          This fixes addresses issue #10.
+        
+        2.0-rc10 (2011-05-24)
+        ---------------------
+        
+        Bugfixes:
+        
+        - The ``tal:attributes`` statement now correctly operates
+          case-insensitive. The attribute name given in the statement will
+          replace an existing attribute with the same name, without respect to
+          case.
+        
+        Features:
+        
+        - Added ``meta:interpolation`` statement to control expression
+          interpolation setting.
+        
+          Strings that disable the setting: ``"off"`` and ``"false"``.
+          Strings that enable the setting: ``"on"`` and ``"true"``.
+        
+        - Expression interpolation now works inside XML comments.
+        
+        2.0-rc9 (2011-05-05)
+        --------------------
+        
+        Features:
+        
+        - Better debugging support for string decode and conversion. If a
+          naive join fails, each element in the output will now be attempted
+          coerced to unicode to try and trigger the failure near to the bad
+          string.
+        
+        2.0-rc8 (2011-04-11)
+        --------------------
+        
+        Bugfixes:
+        
+        - If a macro defines two slots with the same name, a caller will now
+          fill both with a single usage.
+        
+        - If a valid of ``None`` is provided as the translation function
+          argument, we now fall back to the class default.
+        
+        2.0-rc7 (2011-03-29)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed issue with Python 2.5 compatibility AST. This affected at
+          least PyPy 1.4.
+        
+        Features:
+        
+        - The ``auto_reload`` setting now defaults to the class value; the
+          base template class gives a default value of
+          ``chameleon.config.AUTO_RELOAD``. This change allows a subclass to
+          provide a custom default value (such as an application-specific
+          debug mode setting).
+        
+        
+        2.0-rc6 (2011-03-19)
+        --------------------
+        
+        Features:
+        
+        - Added support for ``target_language`` keyword argument to render
+          method. If provided, the argument will be curried onto the
+          translation function.
+        
+        Bugfixes:
+        
+        - The HTML entities 'lt', 'gt' and 'quot' appearing inside content
+          subtition expressions are now translated into their native character
+          values. This fixes an issue where you could not dynamically create
+          elements using the ``structure`` (which is possible in ZPT). The
+          need to create such structure stems from the lack of an expression
+          interpolation operator in ZPT.
+        
+        - Fixed duplicate file pointer issue with test suite (affected Windows
+          platforms only). This fixes issue #9.
+          [oliora]
+        
+        - Use already open file using ``os.fdopen`` when trying to write out
+          the module source. This fixes LP #731803.
+        
+        
+        2.0-rc5 (2011-03-07)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed a number of issues concerning the escaping of attribute
+          values:
+        
+          1) Static attribute values are now included as they appear in the
+             source.
+        
+             This means that invalid attribute values such as ``"true &&
+             false"`` are now left alone. It's not the job of the template
+             engine to correct such markup, at least not in the default mode
+             of operation.
+        
+          2) The string expression compiler no longer unescapes
+             values. Instead, this is left to each expression
+             compiler. Currently only the Python expression compiler unescapes
+             its input.
+        
+          3) The dynamic escape code sequence now correctly only replaces
+             ampersands that are part of an HTML escape format.
+        
+        Imports:
+        
+        - The page template classes and the loader class can now be imported
+          directly from the ``chameleon`` module.
+        
+        Features:
+        
+        - If a custom template loader is not provided, relative paths are now
+          resolved using ``os.abspath`` (i.e. to the current working
+          directory).
+        
+        - Absolute paths are normalized using ``os.path.normpath`` and
+          ``os.path.expanduser``. This ensures that all paths are kept in
+          their "canonical" form.
+        
+        
+        2.0-rc4 (2011-03-03)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed an issue where the output of an end-to-end string expression
+          would raise an exception if the expression evaluated to ``None`` (it
+          should simply output nothing).
+        
+        - The ``convert`` function (which is configurable on the template
+          class level) now defaults to the ``translate`` function (at
+          run-time).
+        
+          This fixes an issue where message objects were not translated (and
+          thus converted to a string) using the a provided ``translate``
+          function.
+        
+        - Fixed string interpolation issue where an expression immediately
+          succeeded by a right curly bracket would not parse.
+        
+          This fixes issue #5.
+        
+        - Fixed error where ``tal:condition`` would be evaluated after
+          ``tal:repeat``.
+        
+        Features:
+        
+        - Python expression is now a TALES expression. That means that the
+          pipe operator can be used to chain two or more expressions in a
+          try-except sequence.
+        
+          This behavior was ported from the 1.x series. Note that while it's
+          still possible to use the pipe character ("|") in an expression, it
+          must now be escaped.
+        
+        - The template cache can now be shared by multiple processes.
+        
+        
+        2.0-rc3 (2011-03-02)
+        --------------------
+        
+        Bugfixes:
+        
+        - Fixed ``atexit`` handler.
+        
+          This fixes issue #3.
+        
+        - If a cache directory is specified, it will now be used even when not
+          in debug mode.
+        
+        - Allow "comment" attribute in the TAL namespace.
+        
+          This fixes an issue in the sense that the reference engine allows
+          any attribute within the TAL namespace. However, only "comment" is
+          in common use.
+        
+        - The template constructor now accepts a flag ``debug`` which puts the
+          template *instance* into debug-mode regardless of the global
+          setting.
+        
+          This fixes issue #1.
+        
+        Features:
+        
+        - Added exception handler for exceptions raised while evaluating an
+          expression.
+        
+          This handler raises (or attempts to) a new exception of the type
+          ``RenderError``, with an additional base class of the original
+          exception class. The string value of the exception is a formatted
+          error message which includes the expression that caused the
+          exception.
+        
+          If we are unable to create the exception class, the original
+          exception is re-raised.
+        
+        2.0-rc2 (2011-02-28)
+        --------------------
+        
+        - Fixed upload issue.
+        
+        2.0-rc1 (2011-02-28)
+        --------------------
+        
+        - Initial public release. See documentation for what's new in this
+          series.
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.2
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/SOURCES.txt
@@ -0,0 +1,380 @@
+.gitignore
+CHANGES.rst
+COPYRIGHT.txt
+LICENSE.txt
+Makefile
+README.rst
+distribute_setup.py
+setup.cfg
+setup.py
+tox.ini
+benchmarks/bm_chameleon.py
+benchmarks/bm_mako.py
+benchmarks/util.py
+docs/conf.py
+docs/configuration.rst
+docs/index.rst
+docs/integration.rst
+docs/library.rst
+docs/reference.rst
+src/Chameleon.egg-info/PKG-INFO
+src/Chameleon.egg-info/SOURCES.txt
+src/Chameleon.egg-info/dependency_links.txt
+src/Chameleon.egg-info/not-zip-safe
+src/Chameleon.egg-info/top_level.txt
+src/chameleon/__init__.py
+src/chameleon/ast24.py
+src/chameleon/astutil.py
+src/chameleon/benchmark.py
+src/chameleon/codegen.py
+src/chameleon/compiler.py
+src/chameleon/config.py
+src/chameleon/exc.py
+src/chameleon/i18n.py
+src/chameleon/interfaces.py
+src/chameleon/loader.py
+src/chameleon/metal.py
+src/chameleon/namespaces.py
+src/chameleon/nodes.py
+src/chameleon/parser.py
+src/chameleon/program.py
+src/chameleon/py25.py
+src/chameleon/py26.py
+src/chameleon/tal.py
+src/chameleon/tales.py
+src/chameleon/template.py
+src/chameleon/tokenize.py
+src/chameleon/utils.py
+src/chameleon/tests/__init__.py
+src/chameleon/tests/test_doctests.py
+src/chameleon/tests/test_loader.py
+src/chameleon/tests/test_parser.py
+src/chameleon/tests/test_sniffing.py
+src/chameleon/tests/test_templates.py
+src/chameleon/tests/test_tokenizer.py
+src/chameleon/tests/inputs/001-interpolation.txt
+src/chameleon/tests/inputs/001-variable-scope.html
+src/chameleon/tests/inputs/001-variable-scope.pt
+src/chameleon/tests/inputs/001.xml
+src/chameleon/tests/inputs/002-repeat-scope.pt
+src/chameleon/tests/inputs/002.xml
+src/chameleon/tests/inputs/003-content.pt
+src/chameleon/tests/inputs/003.xml
+src/chameleon/tests/inputs/004-attributes.pt
+src/chameleon/tests/inputs/004.xml
+src/chameleon/tests/inputs/005-default.pt
+src/chameleon/tests/inputs/005.xml
+src/chameleon/tests/inputs/006-attribute-interpolation.pt
+src/chameleon/tests/inputs/006.xml
+src/chameleon/tests/inputs/007-content-interpolation.pt
+src/chameleon/tests/inputs/007.xml
+src/chameleon/tests/inputs/008-builtins.pt
+src/chameleon/tests/inputs/008.xml
+src/chameleon/tests/inputs/009-literals.pt
+src/chameleon/tests/inputs/009.xml
+src/chameleon/tests/inputs/010-structure.pt
+src/chameleon/tests/inputs/010.xml
+src/chameleon/tests/inputs/011-messages.pt
+src/chameleon/tests/inputs/011.xml
+src/chameleon/tests/inputs/012-translation.pt
+src/chameleon/tests/inputs/012.xml
+src/chameleon/tests/inputs/013-repeat-nested.pt
+src/chameleon/tests/inputs/013.xml
+src/chameleon/tests/inputs/014-repeat-nested-similar.pt
+src/chameleon/tests/inputs/014.xml
+src/chameleon/tests/inputs/015-translation-nested.pt
+src/chameleon/tests/inputs/015.xml
+src/chameleon/tests/inputs/016-explicit-translation.pt
+src/chameleon/tests/inputs/016.xml
+src/chameleon/tests/inputs/017-omit-tag.pt
+src/chameleon/tests/inputs/017.xml
+src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
+src/chameleon/tests/inputs/018.xml
+src/chameleon/tests/inputs/019-replace.pt
+src/chameleon/tests/inputs/019.xml
+src/chameleon/tests/inputs/020-on-error.pt
+src/chameleon/tests/inputs/020.xml
+src/chameleon/tests/inputs/021-translation-domain.pt
+src/chameleon/tests/inputs/021.xml
+src/chameleon/tests/inputs/022-switch.pt
+src/chameleon/tests/inputs/022.xml
+src/chameleon/tests/inputs/023-condition.pt
+src/chameleon/tests/inputs/023.xml
+src/chameleon/tests/inputs/024-namespace-elements.pt
+src/chameleon/tests/inputs/024.xml
+src/chameleon/tests/inputs/025-repeat-whitespace.pt
+src/chameleon/tests/inputs/025.xml
+src/chameleon/tests/inputs/026-repeat-variable.pt
+src/chameleon/tests/inputs/026.xml
+src/chameleon/tests/inputs/027-attribute-replacement.pt
+src/chameleon/tests/inputs/027.xml
+src/chameleon/tests/inputs/028-attribute-toggle.pt
+src/chameleon/tests/inputs/028.xml
+src/chameleon/tests/inputs/029-attribute-ordering.pt
+src/chameleon/tests/inputs/029.xml
+src/chameleon/tests/inputs/030-repeat-tuples.pt
+src/chameleon/tests/inputs/030.xml
+src/chameleon/tests/inputs/031-namespace-with-tal.pt
+src/chameleon/tests/inputs/031.xml
+src/chameleon/tests/inputs/032-master-template.pt
+src/chameleon/tests/inputs/032.xml
+src/chameleon/tests/inputs/033-use-macro-trivial.pt
+src/chameleon/tests/inputs/033.xml
+src/chameleon/tests/inputs/034-use-template-as-macro.pt
+src/chameleon/tests/inputs/034.xml
+src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
+src/chameleon/tests/inputs/035.xml
+src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
+src/chameleon/tests/inputs/036.xml
+src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
+src/chameleon/tests/inputs/037.xml
+src/chameleon/tests/inputs/038-use-macro-globals.pt
+src/chameleon/tests/inputs/038.xml
+src/chameleon/tests/inputs/039-globals.pt
+src/chameleon/tests/inputs/039.xml
+src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
+src/chameleon/tests/inputs/040.xml
+src/chameleon/tests/inputs/041-translate-nested-names.pt
+src/chameleon/tests/inputs/041.xml
+src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
+src/chameleon/tests/inputs/042.xml
+src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
+src/chameleon/tests/inputs/043.xml
+src/chameleon/tests/inputs/044-tuple-define.pt
+src/chameleon/tests/inputs/044.xml
+src/chameleon/tests/inputs/045-namespaces.pt
+src/chameleon/tests/inputs/045.xml
+src/chameleon/tests/inputs/046-extend-macro.pt
+src/chameleon/tests/inputs/046.xml
+src/chameleon/tests/inputs/047-use-extended-macro.pt
+src/chameleon/tests/inputs/047.xml
+src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
+src/chameleon/tests/inputs/048.xml
+src/chameleon/tests/inputs/049-entities-in-attributes.pt
+src/chameleon/tests/inputs/049.xml
+src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
+src/chameleon/tests/inputs/050.xml
+src/chameleon/tests/inputs/051-use-non-extended-macro.pt
+src/chameleon/tests/inputs/051.xml
+src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
+src/chameleon/tests/inputs/052.xml
+src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
+src/chameleon/tests/inputs/053.xml
+src/chameleon/tests/inputs/054-import-expression.pt
+src/chameleon/tests/inputs/054.xml
+src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
+src/chameleon/tests/inputs/055.xml
+src/chameleon/tests/inputs/056-comment-attribute.pt
+src/chameleon/tests/inputs/056.xml
+src/chameleon/tests/inputs/057-order.pt
+src/chameleon/tests/inputs/057.xml
+src/chameleon/tests/inputs/058-script.pt
+src/chameleon/tests/inputs/058.xml
+src/chameleon/tests/inputs/059-embedded-javascript.pt
+src/chameleon/tests/inputs/059.xml
+src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
+src/chameleon/tests/inputs/060.xml
+src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
+src/chameleon/tests/inputs/061.xml
+src/chameleon/tests/inputs/062-comments-and-expressions.pt
+src/chameleon/tests/inputs/062.xml
+src/chameleon/tests/inputs/063-continuation.pt
+src/chameleon/tests/inputs/063.xml
+src/chameleon/tests/inputs/064-tags-and-special-characters.pt
+src/chameleon/tests/inputs/064.xml
+src/chameleon/tests/inputs/065-use-macro-in-fill.pt
+src/chameleon/tests/inputs/065.xml
+src/chameleon/tests/inputs/066-load-expression.pt
+src/chameleon/tests/inputs/066.xml
+src/chameleon/tests/inputs/067-attribute-decode.pt
+src/chameleon/tests/inputs/067.xml
+src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
+src/chameleon/tests/inputs/068.xml
+src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
+src/chameleon/tests/inputs/069.xml
+src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
+src/chameleon/tests/inputs/070.xml
+src/chameleon/tests/inputs/071-html-attribute-defaults.pt
+src/chameleon/tests/inputs/071.xml
+src/chameleon/tests/inputs/072-repeat-interpolation.pt
+src/chameleon/tests/inputs/072.xml
+src/chameleon/tests/inputs/073-utf8-encoded.pt
+src/chameleon/tests/inputs/073.xml
+src/chameleon/tests/inputs/074-encoded-template.pt
+src/chameleon/tests/inputs/074.xml
+src/chameleon/tests/inputs/075-nested-macros.pt
+src/chameleon/tests/inputs/075.xml
+src/chameleon/tests/inputs/076-nested-macro-override.pt
+src/chameleon/tests/inputs/076.xml
+src/chameleon/tests/inputs/077-i18n-attributes.pt
+src/chameleon/tests/inputs/077.xml
+src/chameleon/tests/inputs/078-tags-and-newlines.pt
+src/chameleon/tests/inputs/078.xml
+src/chameleon/tests/inputs/079-implicit-i18n.pt
+src/chameleon/tests/inputs/079.xml
+src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
+src/chameleon/tests/inputs/080.xml
+src/chameleon/tests/inputs/081-load-spec.pt
+src/chameleon/tests/inputs/081.xml
+src/chameleon/tests/inputs/082-load-spec-computed.pt
+src/chameleon/tests/inputs/082.xml
+src/chameleon/tests/inputs/083-template-dict-to-macro.pt
+src/chameleon/tests/inputs/083.xml
+src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
+src/chameleon/tests/inputs/084.xml
+src/chameleon/tests/inputs/085-nested-translation.pt
+src/chameleon/tests/inputs/085.xml
+src/chameleon/tests/inputs/086-self-closing.pt
+src/chameleon/tests/inputs/086.xml
+src/chameleon/tests/inputs/087-code-blocks.pt
+src/chameleon/tests/inputs/087.xml
+src/chameleon/tests/inputs/088-python-newlines.pt
+src/chameleon/tests/inputs/088.xml
+src/chameleon/tests/inputs/089.xml
+src/chameleon/tests/inputs/090.xml
+src/chameleon/tests/inputs/091.xml
+src/chameleon/tests/inputs/092.xml
+src/chameleon/tests/inputs/093.xml
+src/chameleon/tests/inputs/094.xml
+src/chameleon/tests/inputs/095.xml
+src/chameleon/tests/inputs/096.xml
+src/chameleon/tests/inputs/097.xml
+src/chameleon/tests/inputs/098.xml
+src/chameleon/tests/inputs/099.xml
+src/chameleon/tests/inputs/100.xml
+src/chameleon/tests/inputs/101-unclosed-tags.html
+src/chameleon/tests/inputs/101.xml
+src/chameleon/tests/inputs/102-unquoted-attributes.html
+src/chameleon/tests/inputs/102.xml
+src/chameleon/tests/inputs/103-simple-attribute.html
+src/chameleon/tests/inputs/103.xml
+src/chameleon/tests/inputs/104.xml
+src/chameleon/tests/inputs/105.xml
+src/chameleon/tests/inputs/106.xml
+src/chameleon/tests/inputs/107.xml
+src/chameleon/tests/inputs/108.xml
+src/chameleon/tests/inputs/109.xml
+src/chameleon/tests/inputs/110.xml
+src/chameleon/tests/inputs/111.xml
+src/chameleon/tests/inputs/112.xml
+src/chameleon/tests/inputs/113.xml
+src/chameleon/tests/inputs/114.xml
+src/chameleon/tests/inputs/115.xml
+src/chameleon/tests/inputs/116.xml
+src/chameleon/tests/inputs/117.xml
+src/chameleon/tests/inputs/118.xml
+src/chameleon/tests/inputs/119.xml
+src/chameleon/tests/inputs/greeting.pt
+src/chameleon/tests/inputs/hello_world.pt
+src/chameleon/tests/inputs/hello_world.txt
+src/chameleon/tests/outputs/001.html
+src/chameleon/tests/outputs/001.pt
+src/chameleon/tests/outputs/001.txt
+src/chameleon/tests/outputs/002.pt
+src/chameleon/tests/outputs/003.pt
+src/chameleon/tests/outputs/004.pt
+src/chameleon/tests/outputs/005.pt
+src/chameleon/tests/outputs/006.pt
+src/chameleon/tests/outputs/007.pt
+src/chameleon/tests/outputs/008.pt
+src/chameleon/tests/outputs/009.pt
+src/chameleon/tests/outputs/010.pt
+src/chameleon/tests/outputs/011-en.pt
+src/chameleon/tests/outputs/011.pt
+src/chameleon/tests/outputs/012-en.pt
+src/chameleon/tests/outputs/012.pt
+src/chameleon/tests/outputs/013.pt
+src/chameleon/tests/outputs/014.pt
+src/chameleon/tests/outputs/015-en.pt
+src/chameleon/tests/outputs/015.pt
+src/chameleon/tests/outputs/016-en.pt
+src/chameleon/tests/outputs/016.pt
+src/chameleon/tests/outputs/017.pt
+src/chameleon/tests/outputs/018-en.pt
+src/chameleon/tests/outputs/018.pt
+src/chameleon/tests/outputs/019.pt
+src/chameleon/tests/outputs/020.pt
+src/chameleon/tests/outputs/021-en.pt
+src/chameleon/tests/outputs/021.pt
+src/chameleon/tests/outputs/022.pt
+src/chameleon/tests/outputs/023.pt
+src/chameleon/tests/outputs/024.pt
+src/chameleon/tests/outputs/025.pt
+src/chameleon/tests/outputs/026.pt
+src/chameleon/tests/outputs/027.pt
+src/chameleon/tests/outputs/028.pt
+src/chameleon/tests/outputs/029.pt
+src/chameleon/tests/outputs/030.pt
+src/chameleon/tests/outputs/031.pt
+src/chameleon/tests/outputs/032.pt
+src/chameleon/tests/outputs/033.pt
+src/chameleon/tests/outputs/034.pt
+src/chameleon/tests/outputs/035.pt
+src/chameleon/tests/outputs/036.pt
+src/chameleon/tests/outputs/037.pt
+src/chameleon/tests/outputs/038.pt
+src/chameleon/tests/outputs/039.pt
+src/chameleon/tests/outputs/040.pt
+src/chameleon/tests/outputs/041.pt
+src/chameleon/tests/outputs/042.pt
+src/chameleon/tests/outputs/043.pt
+src/chameleon/tests/outputs/044.pt
+src/chameleon/tests/outputs/045.pt
+src/chameleon/tests/outputs/046.pt
+src/chameleon/tests/outputs/047.pt
+src/chameleon/tests/outputs/048.pt
+src/chameleon/tests/outputs/049.pt
+src/chameleon/tests/outputs/050.pt
+src/chameleon/tests/outputs/051.pt
+src/chameleon/tests/outputs/052.pt
+src/chameleon/tests/outputs/053.pt
+src/chameleon/tests/outputs/054.pt
+src/chameleon/tests/outputs/055.pt
+src/chameleon/tests/outputs/056.pt
+src/chameleon/tests/outputs/057.pt
+src/chameleon/tests/outputs/058.pt
+src/chameleon/tests/outputs/059.pt
+src/chameleon/tests/outputs/060.pt
+src/chameleon/tests/outputs/061.pt
+src/chameleon/tests/outputs/062.pt
+src/chameleon/tests/outputs/063.pt
+src/chameleon/tests/outputs/064.pt
+src/chameleon/tests/outputs/065.pt
+src/chameleon/tests/outputs/066.pt
+src/chameleon/tests/outputs/067.pt
+src/chameleon/tests/outputs/068.pt
+src/chameleon/tests/outputs/069-en.pt
+src/chameleon/tests/outputs/069.pt
+src/chameleon/tests/outputs/070-en.pt
+src/chameleon/tests/outputs/070.pt
+src/chameleon/tests/outputs/071.pt
+src/chameleon/tests/outputs/072.pt
+src/chameleon/tests/outputs/073.pt
+src/chameleon/tests/outputs/074.pt
+src/chameleon/tests/outputs/075.pt
+src/chameleon/tests/outputs/076.pt
+src/chameleon/tests/outputs/077-en.pt
+src/chameleon/tests/outputs/077.pt
+src/chameleon/tests/outputs/078.pt
+src/chameleon/tests/outputs/079-en.pt
+src/chameleon/tests/outputs/079.pt
+src/chameleon/tests/outputs/080.pt
+src/chameleon/tests/outputs/081.pt
+src/chameleon/tests/outputs/082.pt
+src/chameleon/tests/outputs/083.pt
+src/chameleon/tests/outputs/084.pt
+src/chameleon/tests/outputs/085-en.pt
+src/chameleon/tests/outputs/085.pt
+src/chameleon/tests/outputs/086.pt
+src/chameleon/tests/outputs/087.pt
+src/chameleon/tests/outputs/088.pt
+src/chameleon/tests/outputs/101.html
+src/chameleon/tests/outputs/102.html
+src/chameleon/tests/outputs/103.html
+src/chameleon/tests/outputs/greeting.pt
+src/chameleon/tests/outputs/hello_world.pt
+src/chameleon/tests/outputs/hello_world.txt
+src/chameleon/zpt/__init__.py
+src/chameleon/zpt/loader.py
+src/chameleon/zpt/program.py
+src/chameleon/zpt/template.py
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/dependency_links.txt
@@ -0,0 +1,1 @@
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/not-zip-safe
@@ -0,0 +1,1 @@
+
diff --git a/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/Chameleon.egg-info/top_level.txt
@@ -0,0 +1,1 @@
+chameleon
diff --git a/lib/Chameleon-2.9.2/src/chameleon/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/__init__.py
@@ -0,0 +1,5 @@
+from .zpt.template import PageTemplate
+from .zpt.template import PageTemplateFile
+from .zpt.template import PageTextTemplate
+from .zpt.template import PageTextTemplateFile
+from .zpt.loader import TemplateLoader as PageTemplateLoader
diff --git a/lib/Chameleon-2.9.2/src/chameleon/ast24.py b/lib/Chameleon-2.9.2/src/chameleon/ast24.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/ast24.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 by Armin Ronacher.
+# License: Python License.
+#
+
+import _ast
+
+from _ast import *
+
+
+def fix_missing_locations(node):
+    """
+    When you compile a node tree with compile(), the compiler expects lineno and
+    col_offset attributes for every node that supports them.  This is rather
+    tedious to fill in for generated nodes, so this helper adds these attributes
+    recursively where not already set, by setting them to the values of the
+    parent node.  It works recursively starting at *node*.
+    """
+    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 iter_child_nodes(node):
+    """
+    Yield all direct child nodes of *node*, that is, all fields that are nodes
+    and all items of fields that are lists of nodes.
+    """
+    for name, field in iter_fields(node):
+        if isinstance(field, (AST, _ast.AST)):
+            yield field
+        elif isinstance(field, list):
+            for item in field:
+                if isinstance(item, (AST, _ast.AST)):
+                    yield item
+
+
+def iter_fields(node):
+    """
+    Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
+    that is present on *node*.
+    """
+
+    for field in node._fields or ():
+        try:
+            yield field, getattr(node, field)
+        except AttributeError:
+            pass
+
+
+def walk(node):
+    """
+    Recursively yield all child nodes of *node*, in no specified order.  This is
+    useful if you only want to modify nodes in place and don't care about the
+    context.
+    """
+    from collections import deque
+    todo = deque([node])
+    while todo:
+        node = todo.popleft()
+        todo.extend(iter_child_nodes(node))
+        yield node
+
+
+class NodeVisitor(object):
+    """
+    A node visitor base class that walks the abstract syntax tree and calls a
+    visitor function for every node found.  This function may return a value
+    which is forwarded by the `visit` method.
+
+    This class is meant to be subclassed, with the subclass adding visitor
+    methods.
+
+    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 `visit` method.  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 visit(self, node):
+        """Visit a node."""
+        method = 'visit_' + node.__class__.__name__
+        visitor = getattr(self, method, self.generic_visit)
+        return visitor(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, _ast.AST)):
+                        self.visit(item)
+            elif isinstance(value, (AST, _ast.AST)):
+                self.visit(value)
+
+
+class AST(object):
+    _fields = ()
+    _attributes = 'lineno', 'col_offset'
+
+    def __init__(self, *args, **kwargs):
+        self.__dict__.update(kwargs)
+        self._fields = self._fields or ()
+        for name, value in zip(self._fields, args):
+            setattr(self, name, value)
+
+
+for name, cls in _ast.__dict__.items():
+    if isinstance(cls, type) and issubclass(cls, _ast.AST):
+        try:
+            cls.__bases__ = (AST, ) + cls.__bases__
+        except TypeError:
+            pass
+
+
+class ExceptHandler(AST):
+    _fields = "type", "name", "body"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/astutil.py b/lib/Chameleon-2.9.2/src/chameleon/astutil.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/astutil.py
@@ -0,0 +1,926 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+"""Support classes for generating code from abstract syntax trees."""
+
+try:
+    import ast
+except ImportError:
+    from chameleon import ast24 as ast
+
+import sys
+import logging
+import weakref
+
+node_annotations = weakref.WeakKeyDictionary()
+
+try:
+    node_annotations[ast.Name()] = None
+except TypeError:
+    logging.debug(
+        "Unable to create weak references to AST nodes. " \
+        "A lock will be used around compilation loop."
+        )
+
+    node_annotations = {}
+
+__docformat__ = 'restructuredtext en'
+
+
+def annotated(value):
+    node = load("annotation")
+    node_annotations[node] = value
+    return node
+
+
+def parse(source, mode='eval'):
+    return compile(source, '', mode, ast.PyCF_ONLY_AST)
+
+
+def load(name):
+    return ast.Name(id=name, ctx=ast.Load())
+
+
+def store(name):
+    return ast.Name(id=name, ctx=ast.Store())
+
+
+def param(name):
+    return ast.Name(id=name, ctx=ast.Param())
+
+
+def delete(name):
+    return ast.Name(id=name, ctx=ast.Del())
+
+
+def subscript(name, value, ctx):
+    return ast.Subscript(
+        value=value,
+        slice=ast.Index(value=ast.Str(s=name)),
+        ctx=ctx,
+        )
+
+
+def walk_names(target, mode):
+    for node in ast.walk(target):
+        if isinstance(node, ast.Name) and \
+               isinstance(node.ctx, mode):
+            yield node.id
+
+
+def copy(source, target):
+    target.__class__ = source.__class__
+    target.__dict__ = source.__dict__
+
+
+def swap(root, replacement, name):
+    for node in ast.walk(root):
+        if (isinstance(node, ast.Name) and
+            isinstance(node.ctx, ast.Load) and
+            node.id == name):
+            assert hasattr(replacement, '_fields')
+            node_annotations.setdefault(node, replacement)
+
+
+def marker(name):
+    return ast.Str(s="__%s" % name)
+
+
+class Node(object):
+    """AST baseclass that gives us a convenient initialization
+    method. We explicitly declare and use the ``_fields`` attribute."""
+
+    _fields = ()
+
+    def __init__(self, *args, **kwargs):
+        assert isinstance(self._fields, tuple)
+        self.__dict__.update(kwargs)
+        for name, value in zip(self._fields, args):
+            setattr(self, name, value)
+
+    def __repr__(self):
+        """Poor man's single-line pretty printer."""
+
+        name = type(self).__name__
+        return '<%s%s at %x>' % (
+            name,
+            "".join(" %s=%r" % (name, getattr(self, name, "\"?\""))
+                        for name in self._fields),
+            id(self)
+            )
+
+
+class Builtin(Node):
+    """Represents a Python builtin.
+
+    Used when a builtin is used internally by the compiler, to avoid
+    clashing with a user assignment (e.g. ``help`` is a builtin, but
+    also commonly assigned in templates).
+    """
+
+    _fields = "id", "ctx"
+
+    ctx = ast.Load()
+
+
+class Symbol(Node):
+    """Represents an importable symbol."""
+
+    _fields = "value",
+
+
+class Static(Node):
+    """Represents a static value."""
+
+    _fields = "value", "name"
+
+    name = None
+
+
+class Comment(Node):
+    _fields = "text", "space", "stmt"
+
+    stmt = None
+    space = ""
+
+
+class ASTCodeGenerator(object):
+    """General purpose base class for AST transformations.
+
+    Every visitor method can be overridden to return an AST node that has been
+    altered or replaced in some way.
+    """
+
+    def __init__(self, tree):
+        self.lines_info = []
+        self.line_info = []
+        self.lines = []
+        self.line = ""
+        self.last = None
+        self.indent = 0
+        self.blame_stack = []
+        self.visit(tree)
+
+        if self.line.strip():
+            self._new_line()
+
+        self.line = None
+        self.line_info = None
+
+        # strip trivial lines
+        self.code = "\n".join(
+            line.strip() and line or ""
+            for line in self.lines
+            )
+
+    def _change_indent(self, delta):
+        self.indent += delta
+
+    def _new_line(self):
+        if self.line is not None:
+            self.lines.append(self.line)
+            self.lines_info.append(self.line_info)
+        self.line = ' ' * 4 * self.indent
+        if len(self.blame_stack) == 0:
+            self.line_info = []
+            self.last = None
+        else:
+            self.line_info = [(0, self.blame_stack[-1],)]
+            self.last = self.blame_stack[-1]
+
+    def _write(self, s):
+        if len(s) == 0:
+            return
+        if len(self.blame_stack) == 0:
+            if self.last is not None:
+                self.last = None
+                self.line_info.append((len(self.line), self.last))
+        else:
+            if self.last != self.blame_stack[-1]:
+                self.last = self.blame_stack[-1]
+                self.line_info.append((len(self.line), self.last))
+        self.line += s
+
+    def flush(self):
+        if self.line:
+            self._new_line()
+
+    def visit(self, node):
+        if node is None:
+            return None
+        if type(node) is tuple:
+            return tuple([self.visit(n) for n in node])
+        try:
+            self.blame_stack.append((node.lineno, node.col_offset,))
+            info = True
+        except AttributeError:
+            info = False
+        visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None)
+        if visitor is None:
+            raise Exception('No handler for ``%s`` (%s).' % (
+                node.__class__.__name__, repr(node)))
+        ret = visitor(node)
+        if info:
+            self.blame_stack.pop()
+        return ret
+
+    def visit_Module(self, node):
+        for n in node.body:
+            self.visit(n)
+    visit_Interactive = visit_Module
+    visit_Suite = visit_Module
+
+    def visit_Expression(self, node):
+        return self.visit(node.body)
+
+    # arguments = (expr* args, identifier? vararg,
+    #              identifier? kwarg, expr* defaults)
+    def visit_arguments(self, node):
+        first = True
+        no_default_count = len(node.args) - len(node.defaults)
+        for i, arg in enumerate(node.args):
+            if not first:
+                self._write(', ')
+            else:
+                first = False
+            self.visit(arg)
+            if i >= no_default_count:
+                self._write('=')
+                self.visit(node.defaults[i - no_default_count])
+        if getattr(node, 'vararg', None):
+            if not first:
+                self._write(', ')
+            else:
+                first = False
+            self._write('*' + node.vararg)
+        if getattr(node, 'kwarg', None):
+            if not first:
+                self._write(', ')
+            else:
+                first = False
+            self._write('**' + node.kwarg)
+
+    def visit_arg(self, node):
+        self._write(node.arg)
+
+    # FunctionDef(identifier name, arguments args,
+    #                           stmt* body, expr* decorators)
+    def visit_FunctionDef(self, node):
+        self._new_line()
+        for decorator in getattr(node, 'decorator_list', ()):
+            self._new_line()
+            self._write('@')
+            self.visit(decorator)
+        self._new_line()
+        self._write('def ' + node.name + '(')
+        self.visit(node.args)
+        self._write('):')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+
+    # ClassDef(identifier name, expr* bases, stmt* body)
+    def visit_ClassDef(self, node):
+        self._new_line()
+        self._write('class ' + node.name)
+        if node.bases:
+            self._write('(')
+            self.visit(node.bases[0])
+            for base in node.bases[1:]:
+                self._write(', ')
+                self.visit(base)
+            self._write(')')
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+
+    # Return(expr? value)
+    def visit_Return(self, node):
+        self._new_line()
+        self._write('return')
+        if getattr(node, 'value', None):
+            self._write(' ')
+            self.visit(node.value)
+
+    # Delete(expr* targets)
+    def visit_Delete(self, node):
+        self._new_line()
+        self._write('del ')
+        self.visit(node.targets[0])
+        for target in node.targets[1:]:
+            self._write(', ')
+            self.visit(target)
+
+    # Assign(expr* targets, expr value)
+    def visit_Assign(self, node):
+        self._new_line()
+        for target in node.targets:
+            self.visit(target)
+            self._write(' = ')
+        self.visit(node.value)
+
+    # AugAssign(expr target, operator op, expr value)
+    def visit_AugAssign(self, node):
+        self._new_line()
+        self.visit(node.target)
+        self._write(' ' + self.binary_operators[node.op.__class__] + '= ')
+        self.visit(node.value)
+
+    # Print(expr? dest, expr* values, bool nl)
+    def visit_Print(self, node):
+        self._new_line()
+        self._write('print')
+        if getattr(node, 'dest', None):
+            self._write(' >> ')
+            self.visit(node.dest)
+            if getattr(node, 'values', None):
+                self._write(', ')
+        else:
+            self._write(' ')
+        if getattr(node, 'values', None):
+            self.visit(node.values[0])
+            for value in node.values[1:]:
+                self._write(', ')
+                self.visit(value)
+        if not node.nl:
+            self._write(',')
+
+    # For(expr target, expr iter, stmt* body, stmt* orelse)
+    def visit_For(self, node):
+        self._new_line()
+        self._write('for ')
+        self.visit(node.target)
+        self._write(' in ')
+        self.visit(node.iter)
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+        if getattr(node, 'orelse', None):
+            self._new_line()
+            self._write('else:')
+            self._change_indent(1)
+            for statement in node.orelse:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # While(expr test, stmt* body, stmt* orelse)
+    def visit_While(self, node):
+        self._new_line()
+        self._write('while ')
+        self.visit(node.test)
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+        if getattr(node, 'orelse', None):
+            self._new_line()
+            self._write('else:')
+            self._change_indent(1)
+            for statement in node.orelse:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # If(expr test, stmt* body, stmt* orelse)
+    def visit_If(self, node):
+        self._new_line()
+        self._write('if ')
+        self.visit(node.test)
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+        if getattr(node, 'orelse', None):
+            self._new_line()
+            self._write('else:')
+            self._change_indent(1)
+            for statement in node.orelse:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # With(expr context_expr, expr? optional_vars, stmt* body)
+    def visit_With(self, node):
+        self._new_line()
+        self._write('with ')
+        self.visit(node.context_expr)
+        if getattr(node, 'optional_vars', None):
+            self._write(' as ')
+            self.visit(node.optional_vars)
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+
+    # Raise(expr? type, expr? inst, expr? tback)
+    def visit_Raise(self, node):
+        self._new_line()
+        self._write('raise')
+        if not getattr(node, "type", None):
+            exc = getattr(node, "exc", None)
+            if exc is None:
+                return
+            self._write(' ')
+            return self.visit(exc)
+        self._write(' ')
+        self.visit(node.type)
+        if not node.inst:
+            return
+        self._write(', ')
+        self.visit(node.inst)
+        if not node.tback:
+            return
+        self._write(', ')
+        self.visit(node.tback)
+
+    # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
+    def visit_Try(self, node):
+        self._new_line()
+        self._write('try:')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+        if getattr(node, 'handlers', None):
+            for handler in node.handlers:
+                self.visit(handler)
+        self._new_line()
+
+        if getattr(node, 'orelse', None):
+            self._write('else:')
+            self._change_indent(1)
+            for statement in node.orelse:
+                self.visit(statement)
+            self._change_indent(-1)
+
+        if getattr(node, 'finalbody', None):
+            self._new_line()
+            self._write('finally:')
+            self._change_indent(1)
+            for statement in node.finalbody:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
+    def visit_TryExcept(self, node):
+        self._new_line()
+        self._write('try:')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+        if getattr(node, 'handlers', None):
+            for handler in node.handlers:
+                self.visit(handler)
+        self._new_line()
+        if getattr(node, 'orelse', None):
+            self._write('else:')
+            self._change_indent(1)
+            for statement in node.orelse:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # excepthandler = (expr? type, expr? name, stmt* body)
+    def visit_ExceptHandler(self, node):
+        self._new_line()
+        self._write('except')
+        if getattr(node, 'type', None):
+            self._write(' ')
+            self.visit(node.type)
+        if getattr(node, 'name', None):
+            if sys.version_info[0] == 2:
+                assert getattr(node, 'type', None)
+                self._write(', ')
+            else:
+                self._write(' as ')
+            self.visit(node.name)
+        self._write(':')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+    visit_excepthandler = visit_ExceptHandler
+
+    # TryFinally(stmt* body, stmt* finalbody)
+    def visit_TryFinally(self, node):
+        self._new_line()
+        self._write('try:')
+        self._change_indent(1)
+        for statement in node.body:
+            self.visit(statement)
+        self._change_indent(-1)
+
+        if getattr(node, 'finalbody', None):
+            self._new_line()
+            self._write('finally:')
+            self._change_indent(1)
+            for statement in node.finalbody:
+                self.visit(statement)
+            self._change_indent(-1)
+
+    # Assert(expr test, expr? msg)
+    def visit_Assert(self, node):
+        self._new_line()
+        self._write('assert ')
+        self.visit(node.test)
+        if getattr(node, 'msg', None):
+            self._write(', ')
+            self.visit(node.msg)
+
+    def visit_alias(self, node):
+        self._write(node.name)
+        if getattr(node, 'asname', None):
+            self._write(' as ')
+            self._write(node.asname)
+
+    # Import(alias* names)
+    def visit_Import(self, node):
+        self._new_line()
+        self._write('import ')
+        self.visit(node.names[0])
+        for name in node.names[1:]:
+            self._write(', ')
+            self.visit(name)
+
+    # ImportFrom(identifier module, alias* names, int? level)
+    def visit_ImportFrom(self, node):
+        self._new_line()
+        self._write('from ')
+        if node.level:
+            self._write('.' * node.level)
+        self._write(node.module)
+        self._write(' import ')
+        self.visit(node.names[0])
+        for name in node.names[1:]:
+            self._write(', ')
+            self.visit(name)
+
+    # Exec(expr body, expr? globals, expr? locals)
+    def visit_Exec(self, node):
+        self._new_line()
+        self._write('exec ')
+        self.visit(node.body)
+        if not node.globals:
+            return
+        self._write(', ')
+        self.visit(node.globals)
+        if not node.locals:
+            return
+        self._write(', ')
+        self.visit(node.locals)
+
+    # Global(identifier* names)
+    def visit_Global(self, node):
+        self._new_line()
+        self._write('global ')
+        self.visit(node.names[0])
+        for name in node.names[1:]:
+            self._write(', ')
+            self.visit(name)
+
+    # Expr(expr value)
+    def visit_Expr(self, node):
+        self._new_line()
+        self.visit(node.value)
+
+    # Pass
+    def visit_Pass(self, node):
+        self._new_line()
+        self._write('pass')
+
+    # Break
+    def visit_Break(self, node):
+        self._new_line()
+        self._write('break')
+
+    # Continue
+    def visit_Continue(self, node):
+        self._new_line()
+        self._write('continue')
+
+    ### EXPRESSIONS
+    def with_parens(f):
+        def _f(self, node):
+            self._write('(')
+            f(self, node)
+            self._write(')')
+        return _f
+
+    bool_operators = {ast.And: 'and', ast.Or: 'or'}
+
+    # BoolOp(boolop op, expr* values)
+    @with_parens
+    def visit_BoolOp(self, node):
+        joiner = ' ' + self.bool_operators[node.op.__class__] + ' '
+        self.visit(node.values[0])
+        for value in node.values[1:]:
+            self._write(joiner)
+            self.visit(value)
+
+    binary_operators = {
+        ast.Add: '+',
+        ast.Sub: '-',
+        ast.Mult: '*',
+        ast.Div: '/',
+        ast.Mod: '%',
+        ast.Pow: '**',
+        ast.LShift: '<<',
+        ast.RShift: '>>',
+        ast.BitOr: '|',
+        ast.BitXor: '^',
+        ast.BitAnd: '&',
+        ast.FloorDiv: '//'
+    }
+
+    # BinOp(expr left, operator op, expr right)
+    @with_parens
+    def visit_BinOp(self, node):
+        self.visit(node.left)
+        self._write(' ' + self.binary_operators[node.op.__class__] + ' ')
+        self.visit(node.right)
+
+    unary_operators = {
+        ast.Invert: '~',
+        ast.Not: 'not',
+        ast.UAdd: '+',
+        ast.USub: '-',
+    }
+
+    # UnaryOp(unaryop op, expr operand)
+    def visit_UnaryOp(self, node):
+        self._write(self.unary_operators[node.op.__class__] + ' ')
+        self.visit(node.operand)
+
+    # Lambda(arguments args, expr body)
+    @with_parens
+    def visit_Lambda(self, node):
+        self._write('lambda ')
+        self.visit(node.args)
+        self._write(': ')
+        self.visit(node.body)
+
+    # IfExp(expr test, expr body, expr orelse)
+    @with_parens
+    def visit_IfExp(self, node):
+        self.visit(node.body)
+        self._write(' if ')
+        self.visit(node.test)
+        self._write(' else ')
+        self.visit(node.orelse)
+
+    # Dict(expr* keys, expr* values)
+    def visit_Dict(self, node):
+        self._write('{')
+        for key, value in zip(node.keys, node.values):
+            self.visit(key)
+            self._write(': ')
+            self.visit(value)
+            self._write(', ')
+        self._write('}')
+
+    def visit_Set(self, node):
+        self._write('{')
+        elts = list(node.elts)
+        last = elts.pop()
+        for elt in elts:
+            self.visit(elt)
+            self._write(', ')
+        self.visit(last)
+        self._write('}')
+
+    # ListComp(expr elt, comprehension* generators)
+    def visit_ListComp(self, node):
+        self._write('[')
+        self.visit(node.elt)
+        for generator in node.generators:
+            # comprehension = (expr target, expr iter, expr* ifs)
+            self._write(' for ')
+            self.visit(generator.target)
+            self._write(' in ')
+            self.visit(generator.iter)
+            for ifexpr in generator.ifs:
+                self._write(' if ')
+                self.visit(ifexpr)
+        self._write(']')
+
+    # GeneratorExp(expr elt, comprehension* generators)
+    def visit_GeneratorExp(self, node):
+        self._write('(')
+        self.visit(node.elt)
+        for generator in node.generators:
+            # comprehension = (expr target, expr iter, expr* ifs)
+            self._write(' for ')
+            self.visit(generator.target)
+            self._write(' in ')
+            self.visit(generator.iter)
+            for ifexpr in generator.ifs:
+                self._write(' if ')
+                self.visit(ifexpr)
+        self._write(')')
+
+    # Yield(expr? value)
+    def visit_Yield(self, node):
+        self._write('yield')
+        if getattr(node, 'value', None):
+            self._write(' ')
+            self.visit(node.value)
+
+    comparison_operators = {
+        ast.Eq: '==',
+        ast.NotEq: '!=',
+        ast.Lt: '<',
+        ast.LtE: '<=',
+        ast.Gt: '>',
+        ast.GtE: '>=',
+        ast.Is: 'is',
+        ast.IsNot: 'is not',
+        ast.In: 'in',
+        ast.NotIn: 'not in',
+    }
+
+    # Compare(expr left, cmpop* ops, expr* comparators)
+    @with_parens
+    def visit_Compare(self, node):
+        self.visit(node.left)
+        for op, comparator in zip(node.ops, node.comparators):
+            self._write(' ' + self.comparison_operators[op.__class__] + ' ')
+            self.visit(comparator)
+
+    # Call(expr func, expr* args, keyword* keywords,
+    #                         expr? starargs, expr? kwargs)
+    def visit_Call(self, node):
+        self.visit(node.func)
+        self._write('(')
+        first = True
+        for arg in node.args:
+            if not first:
+                self._write(', ')
+            first = False
+            self.visit(arg)
+
+        for keyword in node.keywords:
+            if not first:
+                self._write(', ')
+            first = False
+            # keyword = (identifier arg, expr value)
+            self._write(keyword.arg)
+            self._write('=')
+            self.visit(keyword.value)
+        if getattr(node, 'starargs', None):
+            if not first:
+                self._write(', ')
+            first = False
+            self._write('*')
+            self.visit(node.starargs)
+
+        if getattr(node, 'kwargs', None):
+            if not first:
+                self._write(', ')
+            first = False
+            self._write('**')
+            self.visit(node.kwargs)
+        self._write(')')
+
+    # Repr(expr value)
+    def visit_Repr(self, node):
+        self._write('`')
+        self.visit(node.value)
+        self._write('`')
+
+    # Num(object n)
+    def visit_Num(self, node):
+        self._write(repr(node.n))
+
+    # Str(string s)
+    def visit_Str(self, node):
+        self._write(repr(node.s))
+
+    # Attribute(expr value, identifier attr, expr_context ctx)
+    def visit_Attribute(self, node):
+        self.visit(node.value)
+        self._write('.')
+        self._write(node.attr)
+
+    # Subscript(expr value, slice slice, expr_context ctx)
+    def visit_Subscript(self, node):
+        self.visit(node.value)
+        self._write('[')
+
+        def _process_slice(node):
+            if isinstance(node, ast.Ellipsis):
+                self._write('...')
+            elif isinstance(node, ast.Slice):
+                if getattr(node, 'lower', 'None'):
+                    self.visit(node.lower)
+                self._write(':')
+                if getattr(node, 'upper', None):
+                    self.visit(node.upper)
+                if getattr(node, 'step', None):
+                    self._write(':')
+                    self.visit(node.step)
+            elif isinstance(node, ast.Index):
+                self.visit(node.value)
+            elif isinstance(node, ast.ExtSlice):
+                self.visit(node.dims[0])
+                for dim in node.dims[1:]:
+                    self._write(', ')
+                    self.visit(dim)
+            else:
+                raise NotImplemented('Slice type not implemented')
+        _process_slice(node.slice)
+        self._write(']')
+
+    # Name(identifier id, expr_context ctx)
+    def visit_Name(self, node):
+        self._write(node.id)
+
+    # List(expr* elts, expr_context ctx)
+    def visit_List(self, node):
+        self._write('[')
+        for elt in node.elts:
+            self.visit(elt)
+            self._write(', ')
+        self._write(']')
+
+    # Tuple(expr *elts, expr_context ctx)
+    def visit_Tuple(self, node):
+        self._write('(')
+        for elt in node.elts:
+            self.visit(elt)
+            self._write(', ')
+        self._write(')')
+
+
+class AnnotationAwareVisitor(ast.NodeVisitor):
+    def visit(self, node):
+        annotation = node_annotations.get(node)
+        if annotation is not None:
+            assert hasattr(annotation, '_fields')
+            node = annotation
+
+        super(AnnotationAwareVisitor, self).visit(node)
+
+    def apply_transform(self, node):
+        if node not in node_annotations:
+            result = self.transform(node)
+            if result is not None and result is not node:
+                node_annotations[node] = result
+
+
+class NameLookupRewriteVisitor(AnnotationAwareVisitor):
+    def __init__(self, transform):
+        self.transform = transform
+        self.transformed = set()
+        self.scopes = [set()]
+
+    def __call__(self, node):
+        self.visit(node)
+        return self.transformed
+
+    def visit_Name(self, node):
+        scope = self.scopes[-1]
+        if isinstance(node.ctx, ast.Param):
+            scope.add(node.id)
+        elif node.id not in scope:
+            self.transformed.add(node.id)
+            self.apply_transform(node)
+
+    def visit_FunctionDef(self, node):
+        self.scopes[-1].add(node.name)
+
+    def visit_alias(self, node):
+        name = node.asname if node.asname is not None else node.name
+        self.scopes[-1].add(name)
+
+    def visit_Lambda(self, node):
+        self.scopes.append(set())
+        try:
+            self.visit(node.args)
+            self.visit(node.body)
+        finally:
+            self.scopes.pop()
+
+
+class ItemLookupOnAttributeErrorVisitor(AnnotationAwareVisitor):
+    def __init__(self, transform):
+        self.transform = transform
+
+    def visit_Attribute(self, node):
+        self.generic_visit(node)
+        self.apply_transform(node)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/benchmark.py b/lib/Chameleon-2.9.2/src/chameleon/benchmark.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/benchmark.py
@@ -0,0 +1,478 @@
+import unittest
+import time
+import os
+import re
+from .utils import text_
+
+re_amp = re.compile(r'&(?!([A-Za-z]+|#[0-9]+);)')
+
+BIGTABLE_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="row python: options['table']">
+<td tal:repeat="c python: row.values()">
+<span tal:define="d python: c + 1"
+tal:attributes="class python: 'column-' + str(d)"
+tal:content="python: d" />
+</td>
+</tr>
+</table>"""
+
+MANY_STRINGS_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="i python: xrange(1000)">
+<td tal:content="string: number ${i}" />
+</tr>
+</table>
+"""
+
+HELLO_WORLD_ZPT = """\
+<html xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<body>
+<h1>Hello, world!</h1>
+</body>
+</html>
+"""
+
+I18N_ZPT = """\
+<html xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal"
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+  <body>
+    <div tal:repeat="i python: xrange(10)">
+      <div i18n:translate="">
+        Hello world!
+      </div>
+      <div i18n:translate="hello_world">
+        Hello world!
+      </div>
+      <div i18n:translate="">
+        <sup>Hello world!</sup>
+      </div>
+    </div>
+  </body>
+</html>
+"""
+
+
+def benchmark(title):
+    def decorator(f):
+        def wrapper(*args):
+            print(
+                "==========================\n " \
+                "%s\n==========================" % \
+                title)
+            return f(*args)
+        return wrapper
+    return decorator
+
+
+def timing(func, *args, **kwargs):
+    t1 = t2 = time.time()
+    i = 0
+    while t2 - t1 < 3:
+        func(**kwargs)
+        func(**kwargs)
+        func(**kwargs)
+        func(**kwargs)
+        i += 4
+        t2 = time.time()
+    return float(10 * (t2 - t1)) / i
+
+
+START = 0
+END = 1
+TAG = 2
+
+
+def yield_tokens(table=None):
+    index = []
+    tag = index.append
+    _re_amp = re_amp
+    tag(START)
+    yield "<", "html", "", ">\n"
+    for r in table:
+        tag(START)
+        yield "<", "tr", "", ">\n"
+
+        for c in r.values():
+            d = c + 1
+            tag(START)
+            yield "<", "td", "", ">\n"
+
+            _tmp5 = d
+            if not isinstance(_tmp5, unicode):
+                _tmp5 = str(_tmp5)
+            if ('&' in _tmp5):
+                if (';' in _tmp5):
+                    _tmp5 = _re_amp.sub('&', _tmp5)
+                else:
+                    _tmp5 = _tmp5.replace('&', '&')
+            if ('<' in _tmp5):
+                _tmp5 = _tmp5.replace('<', '<')
+            if ('>' in _tmp5):
+                _tmp5 = _tmp5.replace('>', '>')
+            if ('"' in _tmp5):
+                _tmp5 = _tmp5.replace('"', '"')
+            _tmp5 = "column-%s" % _tmp5
+
+            _tmp = d
+            if (_tmp.__class__ not in (str, unicode, int, float, )):
+                raise
+            if (_tmp is not None):
+                if not isinstance(_tmp, unicode):
+                    _tmp = str(_tmp)
+                if ('&' in _tmp):
+                    if (';' in _tmp):
+                        _tmp = _re_amp.sub('&', _tmp)
+                    else:
+                        _tmp = _tmp.replace('&', '&')
+                if ('<' in _tmp):
+                    _tmp = _tmp.replace('<', '<')
+                if ('>' in _tmp):
+                    _tmp = _tmp.replace('>', '>')
+            tag(START)
+
+            t = ["classicism"]
+
+            yield "<", "span", " ", t[0], '="', _tmp5, '"', ">\n"
+            tag(END)
+            yield "</", "span", ">\n"
+            tag(END)
+            yield "</", "td", ">\n"
+        tag(END)
+        yield "</", "tr", ">\n"
+    tag(END)
+    yield "</", "html", ">\n"
+
+
+def yield_tokens_dict_version(**kwargs):
+    index = []
+    tag = index.append
+    _re_amp = re_amp
+    tag(START)
+    yield "<", "html", "", ">\n"
+
+    for r in kwargs['table']:
+        kwargs['r'] = r
+        tag(START)
+        yield "<", "tr", "", ">\n"
+
+        for c in kwargs['r'].values():
+            kwargs['d'] = c + 1
+            tag(START)
+            yield "<", "td", "", ">\n"
+
+            _tmp5 = kwargs['d']
+            if not isinstance(_tmp5, unicode):
+                _tmp5 = str(_tmp5)
+            if ('&' in _tmp5):
+                if (';' in _tmp5):
+                    _tmp5 = _re_amp.sub('&', _tmp5)
+                else:
+                    _tmp5 = _tmp5.replace('&', '&')
+            if ('<' in _tmp5):
+                _tmp5 = _tmp5.replace('<', '<')
+            if ('>' in _tmp5):
+                _tmp5 = _tmp5.replace('>', '>')
+            if ('"' in _tmp5):
+                _tmp5 = _tmp5.replace('"', '"')
+            _tmp5 = "column-%s" % _tmp5
+
+            _tmp = kwargs['d']
+            if (_tmp.__class__ not in (str, unicode, int, float, )):
+                raise
+            if (_tmp is not None):
+                if not isinstance(_tmp, unicode):
+                    _tmp = str(_tmp)
+                if ('&' in _tmp):
+                    if (';' in _tmp):
+                        _tmp = _re_amp.sub('&', _tmp)
+                    else:
+                        _tmp = _tmp.replace('&', '&')
+                if ('<' in _tmp):
+                    _tmp = _tmp.replace('<', '<')
+                if ('>' in _tmp):
+                    _tmp = _tmp.replace('>', '>')
+            tag(START)
+
+            t = ["classicism"]
+
+            yield "<", "span", " ", t[0], '="', _tmp5, '"', ">\n"
+            tag(END)
+            yield "</", "span", ">\n"
+            tag(END)
+            yield "</", "td", ">\n"
+        tag(END)
+        yield "</", "tr", ">\n"
+    tag(END)
+    yield "</", "html", ">\n"
+
+
+def yield_stream(table=None):
+    _re_amp = re_amp
+    yield START, ("html", "", "\n"), None
+    for r in table:
+        yield START, ("tr", "", "\n"), None
+
+        for c in r.values():
+            d = c + 1
+            yield START, ("td", "", "\n"), None
+
+            _tmp5 = d
+            if not isinstance(_tmp5, unicode):
+                _tmp5 = str(_tmp5)
+            if ('&' in _tmp5):
+                if (';' in _tmp5):
+                    _tmp5 = _re_amp.sub('&', _tmp5)
+                else:
+                    _tmp5 = _tmp5.replace('&', '&')
+            if ('<' in _tmp5):
+                _tmp5 = _tmp5.replace('<', '<')
+            if ('>' in _tmp5):
+                _tmp5 = _tmp5.replace('>', '>')
+            if ('"' in _tmp5):
+                _tmp5 = _tmp5.replace('"', '"')
+            _tmp5 = "column-%s" % _tmp5
+
+            _tmp = d
+            if (_tmp.__class__ not in (str, unicode, int, float, )):
+                raise
+            if (_tmp is not None):
+                if not isinstance(_tmp, unicode):
+                    _tmp = str(_tmp)
+                if ('&' in _tmp):
+                    if (';' in _tmp):
+                        _tmp = _re_amp.sub('&', _tmp)
+                    else:
+                        _tmp = _tmp.replace('&', '&')
+                if ('<' in _tmp):
+                    _tmp = _tmp.replace('<', '<')
+                if ('>' in _tmp):
+                    _tmp = _tmp.replace('>', '>')
+            yield START, ("span", "", _tmp, " ", "class", _tmp5), None
+
+            yield END, ("span", "", "\n"), None
+            yield END, ("td", "", "\n"), None
+        yield END, ("tr", "", "\n"), None
+    yield END, ("html", "", "\n"), None
+
+from itertools import chain
+
+
+def bigtable_python_tokens(table=None, renderer=None):
+    iterable = renderer(table=table)
+    stream = chain(*iterable)
+    return "".join(stream)
+
+
+def bigtable_python_stream(table=None, renderer=None):
+    stream = renderer(table=table)
+    return "".join(stream_output(stream))
+
+
+def bigtable_python_stream_with_filter(table=None, renderer=None):
+    stream = renderer(table=table)
+    return "".join(stream_output(uppercase_filter(stream)))
+
+
+def uppercase_filter(stream):
+    for kind, data, pos in stream:
+        if kind is START:
+            data = (data[0], data[1], data[2].upper(),) + data[3:]
+        elif kind is END:
+            data = (data[0], data[1], data[2].upper())
+        elif kind is TAG:
+            raise NotImplemented
+        yield kind, data, pos
+
+
+def stream_output(stream):
+    for kind, data, pos in stream:
+        if kind is START:
+            tag = data[0]
+            yield "<%s" % tag
+            l = len(data)
+
+            # optimize for common cases
+            if l == 3:
+                pass
+            elif l == 6:
+                yield '%s%s="%s"' % (data[3], data[4], data[5])
+            else:
+                i = 3
+                while i < l:
+                    yield '%s%s="%s"' % (data[i], data[i + 1], data[i + 2])
+                    i += 3
+            yield "%s>%s" % (data[1], data[2])
+        elif kind is END:
+            yield "</%s%s>%s" % data
+        elif kind is TAG:
+            raise NotImplemented
+
+
+class Benchmarks(unittest.TestCase):
+    table = [dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10) \
+             for x in range(1000)]
+
+    def setUp(self):
+        # set up i18n component
+        from zope.i18n import translate
+        from zope.i18n.interfaces import INegotiator
+        from zope.i18n.interfaces import ITranslationDomain
+        from zope.i18n.negotiator import Negotiator
+        from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+        from zope.i18n.tests.test_negotiator import Env
+        from zope.tales.tales import Context
+
+        self.env = Env(('klingon', 'da', 'en', 'fr', 'no'))
+
+        class ZopeI18NContext(Context):
+
+            def translate(self, msgid, domain=None, context=None,
+                          mapping=None, default=None):
+                context = self.vars['options']['env']
+                return translate(msgid, domain, mapping,
+                                 context=context, default=default)
+
+        def _getContext(self, contexts=None, **kwcontexts):
+            if contexts is not None:
+                if kwcontexts:
+                    kwcontexts.update(contexts)
+                else:
+                    kwcontexts = contexts
+            return ZopeI18NContext(self, kwcontexts)
+
+        def _pt_getEngineContext(namespace):
+            self = namespace['template']
+            engine = self.pt_getEngine()
+            return _getContext(engine, namespace)
+
+        import zope.component
+        zope.component.provideUtility(Negotiator(), INegotiator)
+        catalog = SimpleTranslationDomain('domain')
+        zope.component.provideUtility(catalog, ITranslationDomain, 'domain')
+        self.files = os.path.abspath(os.path.join(__file__, '..', 'input'))
+
+    @staticmethod
+    def _chameleon(body, **kwargs):
+        from .zpt.template import PageTemplate
+        return PageTemplate(body, **kwargs)
+
+    @staticmethod
+    def _zope(body):
+        from zope.pagetemplate.pagetemplatefile import PageTemplate
+        template = PageTemplate()
+        template.pt_edit(body, 'text/xhtml')
+        return template
+
+    @benchmark(text_("BIGTABLE [python]"))
+    def test_bigtable(self):
+        options = {'table': self.table}
+
+        t_chameleon = timing(self._chameleon(BIGTABLE_ZPT), options=options)
+        print("chameleon:         %7.2f" % t_chameleon)
+
+        t_chameleon_utf8 = timing(
+            self._chameleon(BIGTABLE_ZPT, encoding='utf-8'), options=options)
+        print("chameleon (utf-8): %7.2f" % t_chameleon_utf8)
+
+        t_tokens = timing(
+            bigtable_python_tokens, table=self.table, renderer=yield_tokens)
+        print("token:             %7.2f" % t_tokens)
+
+        t_tokens_dict_version = timing(
+            bigtable_python_tokens, table=self.table,
+            renderer=yield_tokens_dict_version)
+        print("token (dict):      %7.2f" % t_tokens_dict_version)
+
+        t_stream = timing(
+            bigtable_python_stream, table=self.table, renderer=yield_stream)
+        print("stream:            %7.2f" % t_stream)
+
+        t_zope = timing(self._zope(BIGTABLE_ZPT), table=self.table)
+        print("zope.pagetemplate: %7.2f" % t_zope)
+        print("                  %7.1fX" % (t_zope / t_chameleon))
+
+        print("--------------------------")
+        print("check: %d vs %d" % (
+            len(self._chameleon(BIGTABLE_ZPT)(options=options)),
+            len(self._zope(BIGTABLE_ZPT)(table=self.table))))
+        print("--------------------------")
+
+    @benchmark(text_("MANY STRINGS [python]"))
+    def test_many_strings(self):
+        t_chameleon = timing(self._chameleon(MANY_STRINGS_ZPT))
+        print("chameleon:         %7.2f" % t_chameleon)
+        t_zope = timing(self._zope(MANY_STRINGS_ZPT))
+        print("zope.pagetemplate: %7.2f" % t_zope)
+        print("                  %7.1fX" % (t_zope / t_chameleon))
+
+        print("--------------------------")
+        print("check: %d vs %d" % (
+            len(self._chameleon(MANY_STRINGS_ZPT)()),
+            len(self._zope(MANY_STRINGS_ZPT)())))
+        print("--------------------------")
+
+    @benchmark(text_("HELLO WORLD"))
+    def test_hello_world(self):
+        t_chameleon = timing(self._chameleon(HELLO_WORLD_ZPT)) * 1000
+        print("chameleon:         %7.2f" % t_chameleon)
+        t_zope = timing(self._zope(HELLO_WORLD_ZPT)) * 1000
+        print("zope.pagetemplate: %7.2f" % t_zope)
+        print("                  %7.1fX" % (t_zope / t_chameleon))
+
+        print("--------------------------")
+        print("check: %d vs %d" % (
+            len(self._chameleon(HELLO_WORLD_ZPT)()),
+            len(self._zope(HELLO_WORLD_ZPT)())))
+        print("--------------------------")
+
+    @benchmark(text_("I18N"))
+    def test_i18n(self):
+        from zope.i18n import translate
+        t_chameleon = timing(
+            self._chameleon(I18N_ZPT),
+            translate=translate,
+            language="klingon") * 1000
+        print("chameleon:         %7.2f" % t_chameleon)
+        t_zope = timing(self._zope(I18N_ZPT), env=self.env) * 1000
+        print("zope.pagetemplate: %7.2f" % t_zope)
+        print("                  %7.1fX" % (t_zope / t_chameleon))
+
+    @benchmark(text_("COMPILATION"))
+    def test_compilation(self):
+        template = self._chameleon(HELLO_WORLD_ZPT)
+
+        def chameleon_cook_and_render(template=template):
+            template.cook(HELLO_WORLD_ZPT)
+            template()
+
+        t_chameleon = timing(chameleon_cook_and_render) * 1000
+        print("chameleon:         %7.2f" % t_chameleon)
+
+        template = self._zope(HELLO_WORLD_ZPT)
+
+        def zope_cook_and_render(templte=template):
+            template._cook()
+            template()
+
+        t_zope = timing(zope_cook_and_render) * 1000
+        print("zope.pagetemplate: %7.2f" % t_zope)
+        print("                    %0.3fX" % (t_zope / t_chameleon))
+
+
+def start():
+    result = unittest.TestResult()
+    test = unittest.makeSuite(Benchmarks)
+    test.run(result)
+
+    for error in result.errors:
+        print("Error in %s...\n" % error[0])
+        print(error[1])
+
+    for failure in result.failures:
+        print("Failure in %s...\n" % failure[0])
+        print(failure[1])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/codegen.py b/lib/Chameleon-2.9.2/src/chameleon/codegen.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/codegen.py
@@ -0,0 +1,221 @@
+try:
+    import ast
+except ImportError:
+    from chameleon import ast24 as ast
+
+import inspect
+import textwrap
+import types
+import copy
+
+try:
+    import __builtin__ as builtins
+except ImportError:
+    import builtins
+
+reverse_builtin_map = {}
+for name, value in builtins.__dict__.items():
+    try:
+        hash(value)
+    except TypeError:
+        continue
+
+    reverse_builtin_map[value] = name
+
+try:
+    basestring
+except NameError:
+    basestring = str
+
+from .astutil import ASTCodeGenerator
+from .astutil import load
+from .astutil import store
+from .astutil import parse
+from .astutil import Builtin
+from .astutil import Symbol
+from .astutil import node_annotations
+
+from .exc import CompilationError
+
+
+try:
+    NATIVE_NUMBERS = int, float, long, bool
+except NameError:
+    NATIVE_NUMBERS = int, float, bool
+
+
+def template(function, mode='exec', **kw):
+    def wrapper(*vargs, **kwargs):
+        symbols = dict(zip(args, vargs + defaults))
+        symbols.update(kwargs)
+
+        class Visitor(ast.NodeVisitor):
+            def visit_Name(self, node):
+                value = symbols.get(node.id, self)
+                if value is not self:
+                    if isinstance(value, basestring):
+                        value = load(value)
+                    if isinstance(value, type) or value in reverse_builtin_map:
+                        name = reverse_builtin_map.get(value)
+                        if name is not None:
+                            value = Builtin(name)
+                        else:
+                            value = Symbol(value)
+
+                    assert node not in node_annotations
+                    assert hasattr(value, '_fields')
+                    node_annotations[node] = value
+
+        expr = parse(source, mode=mode)
+        if not isinstance(function, basestring):
+            expr = expr.body[0]
+
+        Visitor().visit(expr)
+        return expr.body
+
+    if isinstance(function, basestring):
+        source = function
+        defaults = args = ()
+        return wrapper(**kw)
+
+    source = textwrap.dedent(inspect.getsource(function))
+    argspec = inspect.getargspec(function)
+    args = argspec[0]
+    defaults = argspec[3] or ()
+    return wrapper
+
+
+class TemplateCodeGenerator(ASTCodeGenerator):
+    """Extends the standard Python code generator class with handlers
+    for the helper node classes:
+
+    - Symbol (an importable value)
+    - Static (value that can be made global)
+    - Builtin (from the builtins module)
+    - Marker (short-hand for a unique static object)
+
+    """
+
+    names = ()
+
+    def __init__(self, tree):
+        self.imports = {}
+        self.defines = {}
+        self.markers = {}
+
+        # Generate code
+        super(TemplateCodeGenerator, self).__init__(tree)
+
+    def visit_Module(self, node):
+        super(TemplateCodeGenerator, self).visit_Module(node)
+
+        # Make sure we terminate the line printer
+        self.flush()
+
+        # Clear lines array for import visits
+        body = self.lines
+        self.lines = []
+
+        while self.defines:
+            name, node = self.defines.popitem()
+            assignment = ast.Assign(targets=[store(name)], value=node)
+            self.visit(assignment)
+
+        # Make sure we terminate the line printer
+        self.flush()
+
+        # Clear lines array for import visits
+        defines = self.lines
+        self.lines = []
+
+        while self.imports:
+            value, node = self.imports.popitem()
+
+            if isinstance(value, types.ModuleType):
+                stmt = ast.Import(
+                    names=[ast.alias(name=value.__name__, asname=node.id)])
+            elif hasattr(value, '__name__'):
+                path = reverse_builtin_map.get(value)
+                if path is None:
+                    path = value.__module__
+                    name = value.__name__
+                stmt = ast.ImportFrom(
+                    module=path,
+                    names=[ast.alias(name=name, asname=node.id)],
+                    level=0,
+                )
+            else:
+                raise TypeError(value)
+
+            self.visit(stmt)
+
+        # Clear last import
+        self.flush()
+
+        # Stich together lines
+        self.lines += defines + body
+
+    def define(self, name, node):
+        assert node is not None
+        value = self.defines.get(name)
+
+        if value is node:
+            pass
+        elif value is None:
+            self.defines[name] = node
+        else:
+            raise CompilationError(
+                "Duplicate symbol name for define.", name)
+
+        return load(name)
+
+    def require(self, value):
+        if value is None:
+            return load("None")
+
+        if isinstance(value, NATIVE_NUMBERS):
+            return ast.Num(value)
+
+        node = self.imports.get(value)
+        if node is None:
+            # we come up with a unique symbol based on the class name
+            name = "_%s" % getattr(value, '__name__', str(value)).\
+                   rsplit('.', 1)[-1]
+            node = load(name)
+            self.imports[value] = store(node.id)
+
+        return node
+
+    def visit(self, node):
+        annotation = node_annotations.get(node)
+        if annotation is None:
+            super(TemplateCodeGenerator, self).visit(node)
+        else:
+            self.visit(annotation)
+
+    def visit_Comment(self, node):
+        if node.stmt is None:
+            self._new_line()
+        else:
+            self.visit(node.stmt)
+
+        for line in node.text.replace('\r', '\n').split('\n'):
+            self._new_line()
+            self._write("%s#%s" % (node.space, line))
+
+    def visit_Builtin(self, node):
+        name = load(node.id)
+        self.visit(name)
+
+    def visit_Symbol(self, node):
+        node = self.require(node.value)
+        self.visit(node)
+
+    def visit_Static(self, node):
+        if node.name is None:
+            name = "_static_%d" % id(node.value)
+        else:
+            name = node.name
+
+        node = self.define(name, node.value)
+        self.visit(node)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/compiler.py b/lib/Chameleon-2.9.2/src/chameleon/compiler.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/compiler.py
@@ -0,0 +1,1553 @@
+import re
+import sys
+import itertools
+import logging
+import threading
+import functools
+import collections
+import pickle
+import textwrap
+
+from .astutil import load
+from .astutil import store
+from .astutil import param
+from .astutil import swap
+from .astutil import subscript
+from .astutil import node_annotations
+from .astutil import annotated
+from .astutil import NameLookupRewriteVisitor
+from .astutil import Comment
+from .astutil import Symbol
+from .astutil import Builtin
+
+from .codegen import TemplateCodeGenerator
+from .codegen import template
+
+from .tal import ErrorInfo
+from .tal import NAME
+from .i18n import fast_translate
+
+from .nodes import Text
+from .nodes import Value
+from .nodes import Substitution
+from .nodes import Assignment
+from .nodes import Module
+from .nodes import Context
+
+from .tokenize import Token
+from .config import DEBUG_MODE
+from .exc import TranslationError
+from .exc import ExpressionError
+from .parser import groupdict
+
+from .utils import DebuggingOutputStream
+from .utils import char2entity
+from .utils import ListDictProxy
+from .utils import native_string
+from .utils import byte_string
+from .utils import string_type
+from .utils import unicode_string
+from .utils import version
+from .utils import ast
+from .utils import safe_native
+from .utils import builtins
+from .utils import decode_htmlentities
+
+
+if version >= (3, 0, 0):
+    long = int
+
+log = logging.getLogger('chameleon.compiler')
+
+COMPILER_INTERNALS_OR_DISALLOWED = set([
+    "econtext",
+    "rcontext",
+    "str",
+    "int",
+    "float",
+    "long",
+    "len",
+    "None",
+    "True",
+    "False",
+    "RuntimeError",
+    ])
+
+
+RE_MANGLE = re.compile('[^\w_]')
+RE_NAME = re.compile('^%s$' % NAME)
+
+if DEBUG_MODE:
+    LIST = template("cls()", cls=DebuggingOutputStream, mode="eval")
+else:
+    LIST = template("[]", mode="eval")
+
+
+def identifier(prefix, suffix=None):
+    return "__%s_%s" % (prefix, mangle(suffix or id(prefix)))
+
+
+def mangle(string):
+    return RE_MANGLE.sub('_', str(string)).replace('\n', '')
+
+
+def load_econtext(name):
+    return template("getitem(KEY)", KEY=ast.Str(s=name), mode="eval")
+
+
+def store_econtext(name):
+    name = native_string(name)
+    return subscript(name, load("econtext"), ast.Store())
+
+
+def store_rcontext(name):
+    name = native_string(name)
+    return subscript(name, load("rcontext"), ast.Store())
+
+
+def set_error(token, exception):
+    try:
+        line, column = token.location
+        filename = token.filename
+    except AttributeError:
+        line, column = 0, 0
+        filename = "<string>"
+
+    string = safe_native(token)
+
+    return template(
+        "rcontext.setdefault('__error__', [])."
+        "append((string, line, col, src, exc))",
+        string=ast.Str(s=string),
+        line=ast.Num(n=line),
+        col=ast.Num(n=column),
+        src=ast.Str(s=filename),
+        sys=Symbol(sys),
+        exc=exception,
+        )
+
+
+def try_except_wrap(stmts, token):
+    exception = template(
+        "exc_info()[1]", exc_info=Symbol(sys.exc_info), mode="eval"
+        )
+
+    body = set_error(token, exception) + template("raise")
+
+    return ast.TryExcept(
+        body=stmts,
+        handlers=[ast.ExceptHandler(body=body)],
+        )
+
+
+ at template
+def emit_node(node):  # pragma: no cover
+    __append(node)
+
+
+ at template
+def emit_node_if_non_trivial(node):  # pragma: no cover
+    if node is not None:
+        __append(node)
+
+
+ at template
+def emit_bool(target, s, default_marker=None,
+                 default=None):  # pragma: no cover
+    if target is default_marker:
+        target = default
+    elif target:
+        target = s
+    else:
+        target = None
+
+
+ at template
+def emit_convert(
+    target, encoded=byte_string, str=unicode_string,
+    long=long, type=type,
+    default_marker=None, default=None):  # pragma: no cover
+    if target is None:
+        pass
+    elif target is default_marker:
+        target = default
+    else:
+        __tt = type(target)
+
+        if __tt is int or __tt is float or __tt is long:
+            target = str(target)
+        elif __tt is encoded:
+            target = decode(target)
+        elif __tt is not str:
+            try:
+                target = target.__html__
+            except AttributeError:
+                __converted = convert(target)
+                target = str(target) if target is __converted else __converted
+            else:
+                target = target()
+
+
+ at template
+def emit_translate(target, msgid, default=None):  # pragma: no cover
+    target = translate(msgid, default=default, domain=__i18n_domain)
+
+
+ at template
+def emit_convert_and_escape(
+    target, quote=None, quote_entity=None, str=unicode_string, long=long,
+    type=type, encoded=byte_string,
+    default_marker=None, default=None):  # pragma: no cover
+    if target is None:
+        pass
+    elif target is default_marker:
+        target = default
+    else:
+        __tt = type(target)
+
+        if __tt is int or __tt is float or __tt is long:
+            target = str(target)
+        else:
+            try:
+                if __tt is encoded:
+                    target = decode(target)
+                elif __tt is not str:
+                    try:
+                        target = target.__html__
+                    except:
+                        __converted = convert(target)
+                        target = str(target) if target is __converted \
+                                 else __converted
+                    else:
+                        raise RuntimeError
+            except RuntimeError:
+                target = target()
+            else:
+                if target is not None:
+                    try:
+                        escape = __re_needs_escape(target) is not None
+                    except TypeError:
+                        pass
+                    else:
+                        if escape:
+                            # Character escape
+                            if '&' in target:
+                                target = target.replace('&', '&')
+                            if '<' in target:
+                                target = target.replace('<', '<')
+                            if '>' in target:
+                                target = target.replace('>', '>')
+                            if quote is not None and quote in target:
+                                target = target.replace(quote, quote_entity)
+
+
+class Interpolator(object):
+    braces_required_regex = re.compile(
+        r'(?<!\\)\$({(?P<expression>.*)})',
+        re.DOTALL)
+
+    braces_optional_regex = re.compile(
+        r'(?<!\\)\$({(?P<expression>.*)}|(?P<variable>[A-Za-z][A-Za-z0-9_]*))',
+        re.DOTALL)
+
+    def __init__(self, expression, braces_required, translate=False):
+        self.expression = expression
+        self.regex = self.braces_required_regex if braces_required else \
+                     self.braces_optional_regex
+        self.translate = translate
+
+    def __call__(self, name, engine):
+        """The strategy is to find possible expression strings and
+        call the ``validate`` function of the parser to validate.
+
+        For every possible starting point, the longest possible
+        expression is tried first, then the second longest and so
+        forth.
+
+        Example 1:
+
+          ${'expressions use the ${<expression>} format'}
+
+        The entire expression is attempted first and it is also the
+        only one that validates.
+
+        Example 2:
+
+          ${'Hello'} ${'world!'}
+
+        Validation of the longest possible expression (the entire
+        string) will fail, while the second round of attempts,
+        ``${'Hello'}`` and ``${'world!'}`` respectively, validate.
+
+        """
+
+        body = []
+        nodes = []
+        text = self.expression
+
+        expr_map = {}
+        translate = self.translate
+
+        while text:
+            matched = text
+            m = self.regex.search(matched)
+            if m is None:
+                nodes.append(ast.Str(s=text))
+                break
+
+            part = text[:m.start()]
+            text = text[m.start():]
+
+            if part:
+                node = ast.Str(s=part)
+                nodes.append(node)
+
+            if not body:
+                target = name
+            else:
+                target = store("%s_%d" % (name.id, text.pos))
+
+            while True:
+                d = groupdict(m, matched)
+                string = d["expression"] or d["variable"] or ""
+
+                string = decode_htmlentities(string)
+
+                try:
+                    compiler = engine.parse(string)
+                    body += compiler.assign_text(target)
+                except ExpressionError:
+                    matched = matched[m.start():m.end() - 1]
+                    m = self.regex.search(matched)
+                    if m is None:
+                        raise
+                else:
+                    break
+
+            # If one or more expressions are not simple names, we
+            # disable translation.
+            if RE_NAME.match(string) is None:
+                translate = False
+
+            # if this is the first expression, use the provided
+            # assignment name; otherwise, generate one (here based
+            # on the string position)
+            node = load(target.id)
+            nodes.append(node)
+
+            expr_map[node] = safe_native(string)
+
+            text = text[len(m.group()):]
+
+        if len(nodes) == 1:
+            target = nodes[0]
+
+            if translate and isinstance(target, ast.Str):
+                target = template(
+                    "translate(msgid, domain=__i18n_domain, context=econtext)",
+                    msgid=target, mode="eval",
+                    )
+        else:
+            if translate:
+                formatting_string = ""
+                keys = []
+                values = []
+
+                for node in nodes:
+                    if isinstance(node, ast.Str):
+                        formatting_string += node.s
+                    else:
+                        string = expr_map[node]
+                        formatting_string += "${%s}" % string
+                        keys.append(ast.Str(s=string))
+                        values.append(node)
+
+                target = template(
+                    "translate(msgid, mapping=mapping, domain=__i18n_domain, context=econtext)",
+                    msgid=ast.Str(s=formatting_string),
+                    mapping=ast.Dict(keys=keys, values=values),
+                    mode="eval"
+                    )
+            else:
+                nodes = [
+                    template(
+                        "NODE if NODE is not None else ''",
+                        NODE=node, mode="eval"
+                        )
+                    for node in nodes
+                    ]
+
+                target = ast.BinOp(
+                    left=ast.Str(s="%s" * len(nodes)),
+                    op=ast.Mod(),
+                    right=ast.Tuple(elts=nodes, ctx=ast.Load()))
+
+        body += [ast.Assign(targets=[name], value=target)]
+        return body
+
+
+class ExpressionEngine(object):
+    """Expression engine.
+
+    This test demonstrates how to configure and invoke the engine.
+
+    >>> from chameleon import tales
+    >>> parser = tales.ExpressionParser({
+    ...     'python': tales.PythonExpr,
+    ...     'not': tales.NotExpr,
+    ...     'exists': tales.ExistsExpr,
+    ...     'string': tales.StringExpr,
+    ...     }, 'python')
+
+    >>> engine = ExpressionEngine(parser)
+
+    An expression evaluation function:
+
+    >>> eval = lambda expression: tales.test(
+    ...     tales.IdentityExpr(expression), engine)
+
+    We have provided 'python' as the default expression type. This
+    means that when no prefix is given, the expression is evaluated as
+    a Python expression:
+
+    >>> eval('not False')
+    True
+
+    Note that the ``type`` prefixes bind left. If ``not`` and
+    ``exits`` are two expression type prefixes, consider the
+    following::
+
+    >>> eval('not: exists: int(None)')
+    True
+
+    The pipe operator binds right. In the following example, but
+    arguments are evaluated against ``not: exists: ``.
+
+    >>> eval('not: exists: help')
+    False
+
+    >>> eval('string:test ${1}${2}')
+    'test 12'
+
+    """
+
+    supported_char_escape_set = set(('&', '<', '>'))
+
+    def __init__(self, parser, char_escape=(),
+                 default=None, default_marker=None):
+        self._parser = parser
+        self._char_escape = char_escape
+        self._default = default
+        self._default_marker = default_marker
+
+    def __call__(self, string, target):
+        # BBB: This method is deprecated. Instead, a call should first
+        # be made to ``parse`` and then one of the assignment methods
+        # ("value" or "text").
+
+        compiler = self.parse(string)
+        return compiler(string, target)
+
+    def parse(self, string):
+        expression = self._parser(string)
+        compiler = self.get_compiler(expression, string)
+        return ExpressionCompiler(compiler, self)
+
+    def get_compiler(self, expression, string):
+        def compiler(target, engine, result_type=None, *args):
+            stmts = expression(target, engine)
+
+            if result_type is not None:
+                method = getattr(self, '_convert_%s' % result_type)
+                steps = method(target, *args)
+                stmts.extend(steps)
+
+            return [try_except_wrap(stmts, string)]
+
+        return compiler
+
+    def _convert_bool(self, target, s):
+        """Converts value given by ``target`` to a string ``s`` if the
+        target is a true value, otherwise ``None``.
+        """
+
+        return emit_bool(
+            target, ast.Str(s=s),
+            default=self._default,
+            default_marker=self._default_marker
+            )
+
+    def _convert_text(self, target):
+        """Converts value given by ``target`` to text."""
+
+        if self._char_escape:
+            # This is a cop-out - we really only support a very select
+            # set of escape characters
+            other = set(self._char_escape) - self.supported_char_escape_set
+
+            if other:
+                for supported in '"', '\'', '':
+                    if supported in self._char_escape:
+                        quote = supported
+                        break
+                else:
+                    raise RuntimeError(
+                        "Unsupported escape set: %s." % repr(self._char_escape)
+                        )
+            else:
+                quote = '\0'
+
+            entity = char2entity(quote or '\0')
+
+            return emit_convert_and_escape(
+                target,
+                quote=ast.Str(s=quote),
+                quote_entity=ast.Str(s=entity),
+                default=self._default,
+                default_marker=self._default_marker,
+                )
+
+        return emit_convert(
+            target,
+            default=self._default,
+            default_marker=self._default_marker,
+            )
+
+
+class ExpressionCompiler(object):
+    def __init__(self, compiler, engine):
+        self.compiler = compiler
+        self.engine = engine
+
+    def assign_bool(self, target, s):
+        return self.compiler(target, self.engine, "bool", s)
+
+    def assign_text(self, target):
+        return self.compiler(target, self.engine, "text")
+
+    def assign_value(self, target):
+        return self.compiler(target, self.engine)
+
+
+class ExpressionEvaluator(object):
+    """Evaluates dynamic expression.
+
+    This is not particularly efficient, but supported for legacy
+    applications.
+
+    >>> from chameleon import tales
+    >>> parser = tales.ExpressionParser({'python': tales.PythonExpr}, 'python')
+    >>> engine = functools.partial(ExpressionEngine, parser)
+
+    >>> evaluate = ExpressionEvaluator(engine, {
+    ...     'foo': 'bar',
+    ...     })
+
+    The evaluation function is passed the local and remote context,
+    the expression type and finally the expression.
+
+    >>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
+    'barbaz'
+
+    The cache is now primed:
+
+    >>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
+    'barbaz'
+
+    Note that the call method supports currying of the expression
+    argument:
+
+    >>> python = evaluate({'boo': 'baz'}, {}, 'python')
+    >>> python('foo + boo')
+    'barbaz'
+
+    """
+
+    __slots__ = "_engine", "_cache", "_names", "_builtins"
+
+    def __init__(self, engine, builtins):
+        self._engine = engine
+        self._names, self._builtins = zip(*builtins.items())
+        self._cache = {}
+
+    def __call__(self, econtext, rcontext, expression_type, string=None):
+        if string is None:
+            return functools.partial(
+                self.__call__, econtext, rcontext, expression_type
+                )
+
+        expression = "%s:%s" % (expression_type, string)
+
+        try:
+            evaluate = self._cache[expression]
+        except KeyError:
+            assignment = Assignment(["_result"], expression, True)
+            module = Module("evaluate", Context(assignment))
+
+            compiler = Compiler(
+                self._engine, module, ('econtext', 'rcontext') + self._names
+                )
+
+            env = {}
+            exec(compiler.code, env)
+            evaluate = self._cache[expression] = env["evaluate"]
+
+        evaluate(econtext, rcontext, *self._builtins)
+        return econtext['_result']
+
+
+class NameTransform(object):
+    """
+    >>> nt = NameTransform(
+    ...     set(('foo', 'bar', )), {'boo': 'boz'},
+    ...     ('econtext', ),
+    ... )
+
+    >>> def test(node):
+    ...     rewritten = nt(node)
+    ...     module = ast.Module([ast.fix_missing_locations(rewritten)])
+    ...     codegen = TemplateCodeGenerator(module)
+    ...     return codegen.code
+
+    Any odd name:
+
+    >>> test(load('frobnitz'))
+    "getitem('frobnitz')"
+
+    A 'builtin' name will first be looked up via ``get`` allowing fall
+    back to the global builtin value:
+
+    >>> test(load('foo'))
+    "get('foo', foo)"
+
+    Internal names (with two leading underscores) are left alone:
+
+    >>> test(load('__internal'))
+    '__internal'
+
+    Compiler internals or disallowed names:
+
+    >>> test(load('econtext'))
+    'econtext'
+
+    Aliased names:
+
+    >>> test(load('boo'))
+    'boz'
+
+    """
+
+    def __init__(self, builtins, aliases, internals):
+        self.builtins = builtins
+        self.aliases = aliases
+        self.internals = internals
+
+    def __call__(self, node):
+        name = node.id
+
+        # Don't rewrite names that begin with an underscore; they are
+        # internal and can be assumed to be locally defined. This
+        # policy really should be part of the template program, not
+        # defined here in the compiler.
+        if name.startswith('__') or name in self.internals:
+            return node
+
+        if isinstance(node.ctx, ast.Store):
+            return store_econtext(name)
+
+        aliased = self.aliases.get(name)
+        if aliased is not None:
+            return load(aliased)
+
+        # If the name is a Python global, first try acquiring it from
+        # the dynamic context, then fall back to the global.
+        if name in self.builtins:
+            return template(
+                "get(key, name)",
+                mode="eval",
+                key=ast.Str(s=name),
+                name=load(name),
+                )
+
+        # Otherwise, simply acquire it from the dynamic context.
+        return load_econtext(name)
+
+
+class ExpressionTransform(object):
+    """Internal wrapper to transform expression nodes into assignment
+    statements.
+
+    The node input may use the provided expression engine, but other
+    expression node types are supported such as ``Builtin`` which
+    simply resolves a built-in name.
+
+    Used internally be the compiler.
+    """
+
+    loads_symbol = Symbol(pickle.loads)
+
+    def __init__(self, engine_factory, cache, visitor, strict=True):
+        self.engine_factory = engine_factory
+        self.cache = cache
+        self.strict = strict
+        self.visitor = visitor
+
+    def __call__(self, expression, target):
+        if isinstance(target, string_type):
+            target = store(target)
+
+        try:
+            stmts = self.translate(expression, target)
+        except ExpressionError:
+            if self.strict:
+                raise
+
+            exc = sys.exc_info()[1]
+            p = pickle.dumps(exc)
+
+            stmts = template(
+                "__exc = loads(p)", loads=self.loads_symbol, p=ast.Str(s=p)
+                )
+
+            token = Token(exc.token, exc.offset, filename=exc.filename)
+
+            stmts += set_error(token, load("__exc"))
+            stmts += [ast.Raise(exc=load("__exc"))]
+
+        # Apply visitor to each statement
+        for stmt in stmts:
+            self.visitor(stmt)
+
+        return stmts
+
+    def translate(self, expression, target):
+        if isinstance(target, string_type):
+            target = store(target)
+
+        cached = self.cache.get(expression)
+
+        if cached is not None:
+            stmts = [ast.Assign(targets=[target], value=cached)]
+        elif isinstance(expression, ast.expr):
+            stmts = [ast.Assign(targets=[target], value=expression)]
+        else:
+            # The engine interface supports simple strings, which
+            # default to expression nodes
+            if isinstance(expression, string_type):
+                expression = Value(expression, True)
+
+            kind = type(expression).__name__
+            visitor = getattr(self, "visit_%s" % kind)
+            stmts = visitor(expression, target)
+
+            # Add comment
+            target_id = getattr(target, "id", target)
+            comment = Comment(" %r -> %s" % (expression, target_id))
+            stmts.insert(0, comment)
+
+        return stmts
+
+    def visit_Value(self, node, target):
+        engine = self.engine_factory()
+        compiler = engine.parse(node.value)
+        return compiler.assign_value(target)
+
+    def visit_Default(self, node, target):
+        value = annotated(node.marker)
+        return [ast.Assign(targets=[target], value=value)]
+
+    def visit_Substitution(self, node, target):
+        engine = self.engine_factory(
+            char_escape=node.char_escape,
+            default=node.default,
+            )
+        compiler = engine.parse(node.value)
+        return compiler.assign_text(target)
+
+    def visit_Negate(self, node, target):
+        return self.translate(node.value, target) + \
+               template("TARGET = not TARGET", TARGET=target)
+
+    def visit_Identity(self, node, target):
+        expression = self.translate(node.expression, "__expression")
+        value = self.translate(node.value, "__value")
+
+        return expression + value + \
+               template("TARGET = __expression is __value", TARGET=target)
+
+    def visit_Equality(self, node, target):
+        expression = self.translate(node.expression, "__expression")
+        value = self.translate(node.value, "__value")
+
+        return expression + value + \
+               template("TARGET = __expression == __value", TARGET=target)
+
+    def visit_Boolean(self, node, target):
+        engine = self.engine_factory()
+        compiler = engine.parse(node.value)
+        return compiler.assign_bool(target, node.s)
+
+    def visit_Interpolation(self, node, target):
+        expr = node.value
+        if isinstance(expr, Substitution):
+            engine = self.engine_factory(
+                char_escape=expr.char_escape,
+                default=expr.default,
+                )
+        elif isinstance(expr, Value):
+            engine = self.engine_factory()
+        else:
+            raise RuntimeError("Bad value: %r." % node.value)
+
+        interpolator = Interpolator(
+            expr.value, node.braces_required, node.translation
+            )
+
+        compiler = engine.get_compiler(interpolator, expr.value)
+        return compiler(target, engine)
+
+    def visit_Translate(self, node, target):
+        if node.msgid is not None:
+            msgid = ast.Str(s=node.msgid)
+        else:
+            msgid = target
+        return self.translate(node.node, target) + \
+               emit_translate(target, msgid, default=target)
+
+    def visit_Static(self, node, target):
+        value = annotated(node)
+        return [ast.Assign(targets=[target], value=value)]
+
+    def visit_Builtin(self, node, target):
+        value = annotated(node)
+        return [ast.Assign(targets=[target], value=value)]
+
+
+class Compiler(object):
+    """Generic compiler class.
+
+    Iterates through nodes and yields Python statements which form a
+    template program.
+    """
+
+    exceptions = NameError, \
+                 ValueError, \
+                 AttributeError, \
+                 LookupError, \
+                 TypeError
+
+    defaults = {
+        'translate': Symbol(fast_translate),
+        'decode': Builtin("str"),
+        'convert': Builtin("str"),
+        }
+
+    lock = threading.Lock()
+
+    global_builtins = set(builtins.__dict__)
+
+    def __init__(self, engine_factory, node, builtins={}, strict=True):
+        self._scopes = [set()]
+        self._expression_cache = {}
+        self._translations = []
+        self._builtins = builtins
+        self._aliases = [{}]
+        self._macros = []
+        self._current_slot = []
+
+        internals = COMPILER_INTERNALS_OR_DISALLOWED | \
+                    set(self.defaults)
+
+        transform = NameTransform(
+            self.global_builtins | set(builtins),
+            ListDictProxy(self._aliases),
+            internals,
+            )
+
+        self._visitor = visitor = NameLookupRewriteVisitor(transform)
+
+        self._engine = ExpressionTransform(
+            engine_factory,
+            self._expression_cache,
+            visitor,
+            strict=strict,
+            )
+
+        if isinstance(node_annotations, dict):
+            self.lock.acquire()
+            backup = node_annotations.copy()
+        else:
+            backup = None
+
+        try:
+            module = ast.Module([])
+            module.body += self.visit(node)
+            ast.fix_missing_locations(module)
+            generator = TemplateCodeGenerator(module)
+        finally:
+            if backup is not None:
+                node_annotations.clear()
+                node_annotations.update(backup)
+                self.lock.release()
+
+        self.code = generator.code
+
+    def visit(self, node):
+        if node is None:
+            return ()
+        kind = type(node).__name__
+        visitor = getattr(self, "visit_%s" % kind)
+        iterator = visitor(node)
+        return list(iterator)
+
+    def visit_Sequence(self, node):
+        for item in node.items:
+            for stmt in self.visit(item):
+                yield stmt
+
+    def visit_Element(self, node):
+        self._aliases.append(self._aliases[-1].copy())
+
+        for stmt in self.visit(node.start):
+            yield stmt
+
+        for stmt in self.visit(node.content):
+            yield stmt
+
+        if node.end is not None:
+            for stmt in self.visit(node.end):
+                yield stmt
+
+        self._aliases.pop()
+
+    def visit_Module(self, node):
+        body = []
+
+        body += template("import re")
+        body += template("import functools")
+        body += template("__marker = object()")
+        body += template(
+            r"g_re_amp = re.compile(r'&(?!([A-Za-z]+|#[0-9]+);)')"
+        )
+        body += template(
+            r"g_re_needs_escape = re.compile(r'[&<>\"\']').search")
+
+        body += template(
+            r"__re_whitespace = "
+            r"functools.partial(re.compile('\s+').sub, ' ')",
+        )
+
+        # Visit module content
+        program = self.visit(node.program)
+
+        body += [ast.FunctionDef(
+            name=node.name, args=ast.arguments(
+                args=[param(b) for b in self._builtins],
+                defaults=(),
+                ),
+            body=program
+            )]
+
+        return body
+
+    def visit_MacroProgram(self, node):
+        functions = []
+
+        # Visit defined macros
+        macros = getattr(node, "macros", ())
+        names = []
+        for macro in macros:
+            stmts = self.visit(macro)
+            function = stmts[-1]
+            names.append(function.name)
+            functions += stmts
+
+        # Return function dictionary
+        functions += [ast.Return(value=ast.Dict(
+            keys=[ast.Str(s=name) for name in names],
+            values=[load(name) for name in names],
+            ))]
+
+        return functions
+
+    def visit_Context(self, node):
+        return template("getitem = econtext.__getitem__") + \
+               template("get = econtext.get") + \
+               self.visit(node.node)
+
+    def visit_Macro(self, node):
+        body = []
+
+        # Initialization
+        body += template("__append = __stream.append")
+        body += template("__re_amp = g_re_amp")
+        body += template("__re_needs_escape = g_re_needs_escape")
+
+        # Resolve defaults
+        for name in self.defaults:
+            body += template(
+                "NAME = econtext[KEY]",
+                NAME=name, KEY=ast.Str(s="__" + name)
+            )
+
+        # Internal set of defined slots
+        self._slots = set()
+
+        # Visit macro body
+        nodes = itertools.chain(*tuple(map(self.visit, node.body)))
+
+        # Slot resolution
+        for name in self._slots:
+            body += template(
+                "try: NAME = econtext[KEY].pop()\n"
+                "except: NAME = None",
+                KEY=ast.Str(s=name), NAME=store(name))
+
+        # Append visited nodes
+        body += nodes
+
+        function_name = "render" if node.name is None else \
+                        "render_%s" % mangle(node.name)
+
+        function = ast.FunctionDef(
+            name=function_name, args=ast.arguments(
+                args=[
+                    param("__stream"),
+                    param("econtext"),
+                    param("rcontext"),
+                    param("__i18n_domain"),
+                    ],
+                defaults=[load("None")],
+            ),
+            body=body
+            )
+
+        yield function
+
+    def visit_Text(self, node):
+        return emit_node(ast.Str(s=node.value))
+
+    def visit_Domain(self, node):
+        backup = "__previous_i18n_domain_%d" % id(node)
+        return template("BACKUP = __i18n_domain", BACKUP=backup) + \
+               template("__i18n_domain = NAME", NAME=ast.Str(s=node.name)) + \
+               self.visit(node.node) + \
+               template("__i18n_domain = BACKUP", BACKUP=backup)
+
+    def visit_OnError(self, node):
+        body = []
+
+        fallback = identifier("__fallback")
+        body += template("fallback = len(__stream)", fallback=fallback)
+
+        self._enter_assignment((node.name, ))
+        fallback_body = self.visit(node.fallback)
+        self._leave_assignment((node.name, ))
+
+        error_assignment = template(
+            "econtext[key] = cls(__exc, rcontext['__error__'][-1][1:3])",
+            cls=ErrorInfo,
+            key=ast.Str(s=node.name),
+            )
+
+        body += [ast.TryExcept(
+            body=self.visit(node.node),
+            handlers=[ast.ExceptHandler(
+                type=ast.Tuple(elts=[Builtin("Exception")], ctx=ast.Load()),
+                name=store("__exc"),
+                body=(error_assignment + \
+                      template("del __stream[fallback:]", fallback=fallback) + \
+                      fallback_body
+                      ),
+                )]
+            )]
+
+        return body
+
+    def visit_Content(self, node):
+        name = "__content"
+        body = self._engine(node.expression, store(name))
+
+        if node.translate:
+            body += emit_translate(name, name)
+
+        if node.char_escape:
+            body += emit_convert_and_escape(name)
+        else:
+            body += emit_convert(name)
+
+        body += template("if NAME is not None: __append(NAME)", NAME=name)
+
+        return body
+
+    def visit_Interpolation(self, node):
+        name = identifier("content")
+        return self._engine(node, name) + \
+               emit_node_if_non_trivial(name)
+
+    def visit_Alias(self, node):
+        assert len(node.names) == 1
+        name = node.names[0]
+        target = self._aliases[-1][name] = identifier(name, id(node))
+        return self._engine(node.expression, target)
+
+    def visit_Assignment(self, node):
+        for name in node.names:
+            if name in COMPILER_INTERNALS_OR_DISALLOWED:
+                raise TranslationError(
+                    "Name disallowed by compiler.", name
+                    )
+
+            if name.startswith('__'):
+                raise TranslationError(
+                    "Name disallowed by compiler (double underscore).",
+                    name
+                    )
+
+        assignment = self._engine(node.expression, store("__value"))
+
+        if len(node.names) != 1:
+            target = ast.Tuple(
+                elts=[store_econtext(name) for name in node.names],
+                ctx=ast.Store(),
+            )
+        else:
+            target = store_econtext(node.names[0])
+
+        assignment.append(ast.Assign(targets=[target], value=load("__value")))
+
+        for name in node.names:
+            if not node.local:
+                assignment += template(
+                    "rcontext[KEY] = __value", KEY=ast.Str(s=native_string(name))
+                    )
+
+        return assignment
+
+    def visit_Define(self, node):
+        scope = set(self._scopes[-1])
+        self._scopes.append(scope)
+
+        for assignment in node.assignments:
+            if assignment.local:
+                for stmt in self._enter_assignment(assignment.names):
+                    yield stmt
+
+            for stmt in self.visit(assignment):
+                yield stmt
+
+        for stmt in self.visit(node.node):
+            yield stmt
+
+        for assignment in node.assignments:
+            if assignment.local:
+                for stmt in self._leave_assignment(assignment.names):
+                    yield stmt
+
+        self._scopes.pop()
+
+    def visit_Omit(self, node):
+        return self.visit_Condition(node)
+
+    def visit_Condition(self, node):
+        target = "__condition"
+        assignment = self._engine(node.expression, target)
+
+        assert assignment
+
+        for stmt in assignment:
+            yield stmt
+
+        body = self.visit(node.node) or [ast.Pass()]
+
+        orelse = getattr(node, "orelse", None)
+        if orelse is not None:
+            orelse = self.visit(orelse)
+
+        test = load(target)
+
+        yield ast.If(test=test, body=body, orelse=orelse)
+
+    def visit_Translate(self, node):
+        """Translation.
+
+        Visit items and assign output to a default value.
+
+        Finally, compile a translation expression and use either
+        result or default.
+        """
+
+        body = []
+
+        # Track the blocks of this translation
+        self._translations.append(set())
+
+        # Prepare new stream
+        append = identifier("append", id(node))
+        stream = identifier("stream", id(node))
+        body += template("s = new_list", s=stream, new_list=LIST) + \
+                template("a = s.append", a=append, s=stream)
+
+        # Visit body to generate the message body
+        code = self.visit(node.node)
+        swap(ast.Suite(body=code), load(append), "__append")
+        body += code
+
+        # Reduce white space and assign as message id
+        msgid = identifier("msgid", id(node))
+        body += template(
+            "msgid = __re_whitespace(''.join(stream)).strip()",
+            msgid=msgid, stream=stream
+        )
+
+        default = msgid
+
+        # Compute translation block mapping if applicable
+        names = self._translations[-1]
+        if names:
+            keys = []
+            values = []
+
+            for name in names:
+                stream, append = self._get_translation_identifiers(name)
+                keys.append(ast.Str(s=name))
+                values.append(load(stream))
+
+                # Initialize value
+                body.insert(
+                    0, ast.Assign(
+                        targets=[store(stream)],
+                        value=ast.Str(s=native_string(""))))
+
+            mapping = ast.Dict(keys=keys, values=values)
+        else:
+            mapping = None
+
+        # if this translation node has a name, use it as the message id
+        if node.msgid:
+            msgid = ast.Str(s=node.msgid)
+
+        # emit the translation expression
+        body += template(
+            "__append(translate("
+            "msgid, mapping=mapping, default=default, domain=__i18n_domain, context=econtext))",
+            msgid=msgid, default=default, mapping=mapping
+            )
+
+        # pop away translation block reference
+        self._translations.pop()
+
+        return body
+
+    def visit_Start(self, node):
+        try:
+            line, column = node.prefix.location
+        except AttributeError:
+            line, column = 0, 0
+
+        yield Comment(
+            " %s%s ... (%d:%d)\n"
+            " --------------------------------------------------------" % (
+                node.prefix, node.name, line, column))
+
+        if node.attributes:
+            for stmt in emit_node(ast.Str(s=node.prefix + node.name)):
+                yield stmt
+
+            for attribute in node.attributes:
+                for stmt in self.visit(attribute):
+                    yield stmt
+
+            for stmt in emit_node(ast.Str(s=node.suffix)):
+                yield stmt
+        else:
+            for stmt in emit_node(
+                ast.Str(s=node.prefix + node.name + node.suffix)):
+                yield stmt
+
+    def visit_End(self, node):
+        for stmt in emit_node(ast.Str(
+            s=node.prefix + node.name + node.space + node.suffix)):
+            yield stmt
+
+    def visit_Attribute(self, node):
+        f = node.space + node.name + node.eq + node.quote + "%s" + node.quote
+
+        # Static attributes are just outputted directly
+        if isinstance(node.expression, ast.Str):
+            s = f % node.expression.s
+            return template("__append(S)", S=ast.Str(s=s))
+
+        target = identifier("attr", node.name)
+        body = self._engine(node.expression, store(target))
+        return body + template(
+            "if TARGET is not None: __append(FORMAT % TARGET)",
+            FORMAT=ast.Str(s=f),
+            TARGET=target,
+            )
+
+    def visit_Cache(self, node):
+        body = []
+
+        for expression in node.expressions:
+            name = identifier("cache", id(expression))
+            target = store(name)
+
+            # Skip re-evaluation
+            if self._expression_cache.get(expression):
+                continue
+
+            body += self._engine(expression, target)
+            self._expression_cache[expression] = target
+
+        body += self.visit(node.node)
+
+        return body
+
+    def visit_UseInternalMacro(self, node):
+        if node.name is None:
+            render = "render"
+        else:
+            render = "render_%s" % mangle(node.name)
+
+        return template(
+            "f(__stream, econtext.copy(), rcontext, __i18n_domain)",
+            f=render) + \
+            template("econtext.update(rcontext)")
+
+    def visit_DefineSlot(self, node):
+        name = "__slot_%s" % mangle(node.name)
+        body = self.visit(node.node)
+
+        self._slots.add(name)
+
+        orelse = template(
+            "SLOT(__stream, econtext.copy(), rcontext)",
+            SLOT=name)
+        test = ast.Compare(
+            left=load(name),
+            ops=[ast.Is()],
+            comparators=[load("None")]
+            )
+
+        return [
+            ast.If(test=test, body=body or [ast.Pass()], orelse=orelse)
+            ]
+
+    def visit_Name(self, node):
+        """Translation name."""
+
+        if not self._translations:
+            raise TranslationError(
+                "Not allowed outside of translation.", node.name)
+
+        if node.name in self._translations[-1]:
+            raise TranslationError(
+                "Duplicate translation name: %s." % node.name)
+
+        self._translations[-1].add(node.name)
+        body = []
+
+        # prepare new stream
+        stream, append = self._get_translation_identifiers(node.name)
+        body += template("s = new_list", s=stream, new_list=LIST) + \
+                template("a = s.append", a=append, s=stream)
+
+        # generate code
+        code = self.visit(node.node)
+        swap(ast.Suite(body=code), load(append), "__append")
+        body += code
+
+        # output msgid
+        text = Text('${%s}' % node.name)
+        body += self.visit(text)
+
+        # Concatenate stream
+        body += template("stream = ''.join(stream)", stream=stream)
+
+        return body
+
+    def visit_CodeBlock(self, node):
+        stmts = template(textwrap.dedent(node.source.strip('\n')))
+
+        for stmt in stmts:
+            self._visitor(stmt)
+
+        return stmts
+
+    def visit_UseExternalMacro(self, node):
+        self._macros.append(node.extend)
+
+        callbacks = []
+        for slot in node.slots:
+            key = "__slot_%s" % mangle(slot.name)
+            fun = "__fill_%s" % mangle(slot.name)
+
+            self._current_slot.append(slot.name)
+
+            body = template("getitem = econtext.__getitem__") + \
+                   template("get = econtext.get") + \
+                   self.visit(slot.node)
+
+            assert self._current_slot.pop() == slot.name
+
+            callbacks.append(
+                ast.FunctionDef(
+                    name=fun,
+                    args=ast.arguments(
+                        args=[
+                            param("__stream"),
+                            param("econtext"),
+                            param("rcontext"),
+                            param("__i18n_domain"),
+                            ],
+                        defaults=[load("__i18n_domain")],
+                        ),
+                    body=body or [ast.Pass()],
+                ))
+
+            key = ast.Str(s=key)
+
+            assignment = template(
+                "_slots = econtext[KEY] = DEQUE((NAME,))",
+                KEY=key, NAME=fun, DEQUE=Symbol(collections.deque),
+                )
+
+            if node.extend:
+                append = template("_slots.appendleft(NAME)", NAME=fun)
+
+                assignment = [ast.TryExcept(
+                    body=template("_slots = getitem(KEY)", KEY=key),
+                    handlers=[ast.ExceptHandler(body=assignment)],
+                    orelse=append,
+                    )]
+
+            callbacks.extend(assignment)
+
+        assert self._macros.pop() == node.extend
+
+        assignment = self._engine(node.expression, store("__macro"))
+
+        return (
+            callbacks + \
+            assignment + \
+            template(
+                "__macro.include(__stream, econtext.copy(), " \
+                "rcontext, __i18n_domain)") + \
+            template("econtext.update(rcontext)")
+            )
+
+    def visit_Repeat(self, node):
+        # Used for loop variable definition and restore
+        self._scopes.append(set())
+
+        # Variable assignment and repeat key for single- and
+        # multi-variable repeat clause
+        if node.local:
+            contexts = "econtext",
+        else:
+            contexts = "econtext", "rcontext"
+
+        for name in node.names:
+            if name in COMPILER_INTERNALS_OR_DISALLOWED:
+                raise TranslationError(
+                    "Name disallowed by compiler.", name
+                    )
+
+        if len(node.names) > 1:
+            targets = [
+                ast.Tuple(elts=[
+                    subscript(native_string(name), load(context), ast.Store())
+                    for name in node.names], ctx=ast.Store())
+                for context in contexts
+                ]
+
+            key = ast.Tuple(
+                elts=[ast.Str(s=name) for name in node.names],
+                ctx=ast.Load())
+        else:
+            name = node.names[0]
+            targets = [
+                subscript(native_string(name), load(context), ast.Store())
+                for context in contexts
+                ]
+
+            key = ast.Str(s=node.names[0])
+
+        index = identifier("__index", id(node))
+        assignment = [ast.Assign(targets=targets, value=load("__item"))]
+
+        # Make repeat assignment in outer loop
+        names = node.names
+        local = node.local
+
+        outer = self._engine(node.expression, store("__iterator"))
+
+        if local:
+            outer[:] = list(self._enter_assignment(names)) + outer
+
+        outer += template(
+            "__iterator, INDEX = getitem('repeat')(key, __iterator)",
+            key=key, INDEX=index
+            )
+
+        # Set a trivial default value for each name assigned to make
+        # sure we assign a value even if the iteration is empty
+        outer += [ast.Assign(
+            targets=[store_econtext(name)
+                     for name in node.names],
+            value=load("None"))
+              ]
+
+        # Compute inner body
+        inner = self.visit(node.node)
+
+        # After each iteration, decrease the index
+        inner += template("index -= 1", index=index)
+
+        # For items up to N - 1, emit repeat whitespace
+        inner += template(
+            "if INDEX > 0: __append(WHITESPACE)",
+            INDEX=index, WHITESPACE=ast.Str(s=node.whitespace)
+            )
+
+        # Main repeat loop
+        outer += [ast.For(
+            target=store("__item"),
+            iter=load("__iterator"),
+            body=assignment + inner,
+            )]
+
+        # Finally, clean up assignment if it's local
+        if outer:
+            outer += self._leave_assignment(names)
+
+        self._scopes.pop()
+
+        return outer
+
+    def _get_translation_identifiers(self, name):
+        assert self._translations
+        prefix = id(self._translations[-1])
+        stream = identifier("stream_%d" % prefix, name)
+        append = identifier("append_%d" % prefix, name)
+        return stream, append
+
+    def _enter_assignment(self, names):
+        for name in names:
+            for stmt in template(
+                "BACKUP = get(KEY, __marker)",
+                BACKUP=identifier("backup_%s" % name, id(names)),
+                KEY=ast.Str(s=native_string(name)),
+                ):
+                yield stmt
+
+    def _leave_assignment(self, names):
+        for name in names:
+            for stmt in template(
+                "if BACKUP is __marker: del econtext[KEY]\n"
+                "else:                 econtext[KEY] = BACKUP",
+                BACKUP=identifier("backup_%s" % name, id(names)),
+                KEY=ast.Str(s=native_string(name)),
+                ):
+                yield stmt
diff --git a/lib/Chameleon-2.9.2/src/chameleon/config.py b/lib/Chameleon-2.9.2/src/chameleon/config.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/config.py
@@ -0,0 +1,47 @@
+import os
+import logging
+
+log = logging.getLogger('chameleon.config')
+
+# Define which values are read as true
+TRUE = ('y', 'yes', 't', 'true', 'on', '1')
+
+# If eager parsing is enabled, templates are parsed upon
+# instantiation, rather than when first called upon; this mode is
+# useful for verifying validity of templates across a project
+EAGER_PARSING = os.environ.pop('CHAMELEON_EAGER', 'false')
+EAGER_PARSING = EAGER_PARSING.lower() in TRUE
+
+# Debug mode is mostly useful for debugging the template engine
+# itself. When enabled, generated source code is written to disk to
+# ease step-debugging and some log levels are lowered to increase
+# output. Also, the generated source code is available in the
+# ``source`` attribute of the template instance if compilation
+# succeeded.
+DEBUG_MODE = os.environ.pop('CHAMELEON_DEBUG', 'false')
+DEBUG_MODE = DEBUG_MODE.lower() in TRUE
+
+# If a cache directory is specified, template source code will be
+# persisted on disk and reloaded between sessions
+path = os.environ.pop('CHAMELEON_CACHE', None)
+if path is not None:
+    CACHE_DIRECTORY = os.path.abspath(path)
+    if not os.path.exists(CACHE_DIRECTORY):
+        raise ValueError(
+            "Cache directory does not exist: %s." % CACHE_DIRECTORY
+            )
+    log.info("directory cache: %s." % CACHE_DIRECTORY)
+else:
+    CACHE_DIRECTORY = None
+
+# When auto-reload is enabled, templates are reloaded on file change.
+AUTO_RELOAD = os.environ.pop('CHAMELEON_RELOAD', 'false')
+AUTO_RELOAD = AUTO_RELOAD.lower() in TRUE
+
+for key in os.environ:
+    if key.lower().startswith('chameleon'):
+        log.warn("unknown environment variable set: \"%s\"." % key)
+
+# This is the slice length of the expression displayed in the
+# formatted exception string
+SOURCE_EXPRESSION_MARKER_LENGTH = 60
diff --git a/lib/Chameleon-2.9.2/src/chameleon/exc.py b/lib/Chameleon-2.9.2/src/chameleon/exc.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/exc.py
@@ -0,0 +1,289 @@
+# -*- coding: utf-8 -*-
+
+import traceback
+
+from .utils import format_kwargs
+from .utils import safe_native
+from .tokenize import Token
+from .config import SOURCE_EXPRESSION_MARKER_LENGTH as LENGTH
+
+
+def compute_source_marker(line, column, expression, size):
+    """Computes source marker location string.
+
+    >>> def test(l, c, e, s):
+    ...     s, marker = compute_source_marker(l, c, e, s)
+    ...     out = s + '\\n' + marker
+    ...
+    ...     # Replace dot with middle-dot to work around doctest ellipsis
+    ...     print(out.replace('...', '···'))
+
+    >>> test('foo bar', 4, 'bar', 7)
+    foo bar
+        ^^^
+
+    >>> test('foo ${bar}', 4, 'bar', 10)
+    foo ${bar}
+          ^^^
+
+    >>> test('  foo bar', 6, 'bar', 6)
+    ··· oo bar
+           ^^^
+
+    >>> test('  foo bar baz  ', 6, 'bar', 6)
+    ··· o bar ···
+          ^^^
+
+    The entire expression is always shown, even if ``size`` does not
+    accomodate for it.
+
+    >>> test('  foo bar baz  ', 6, 'bar baz', 10)
+    ··· oo bar baz
+           ^^^^^^^
+
+    >>> test('      foo bar', 10, 'bar', 5)
+    ··· o bar
+          ^^^
+
+    >>> test('      foo bar', 10, 'boo', 5)
+    ··· o bar
+          ^
+
+    """
+
+    s = line.lstrip()
+    column -= len(line) - len(s)
+    s = s.rstrip()
+
+    try:
+        i  = s[column:].index(expression)
+    except ValueError:
+        # If we can't find the expression
+        # (this shouldn't happen), simply
+        # use a standard size marker
+        marker = "^"
+    else:
+        column += i
+        marker = "^" * len(expression)
+
+    if len(expression) > size:
+        offset = column
+        size = len(expression)
+    else:
+        window = (size - len(expression)) / 2.0
+        offset = column - window
+        offset -= min(3, max(0, column + window + len(expression) - len(s)))
+        offset = int(offset)
+
+    if offset > 0:
+        s = s[offset:]
+        r = s.lstrip()
+        d = len(s) - len(r)
+        s = "... " + r
+        column += 4 - d
+        column -= offset
+
+        # This also adds to the displayed length
+        size += 4
+
+    if len(s) > size:
+        s = s[:size].rstrip() + " ..."
+
+    return s, column * " " + marker
+
+
+def ellipsify(string, limit):
+    if len(string) > limit:
+        return "... " + string[-(limit - 4):]
+
+
+def reconstruct_exc(cls, state):
+    exc = Exception.__new__(cls)
+    exc.__dict__ = state
+    return exc
+
+
+class TemplateError(Exception):
+    """An error raised by Chameleon.
+
+    >>> from chameleon.tokenize import Token
+    >>> token = Token('token')
+    >>> message = 'message'
+
+    Make sure the exceptions can be copied:
+
+    >>> from copy import copy
+    >>> copy(TemplateError(message, token))
+    TemplateError('message', 'token')
+
+    And pickle/unpickled:
+
+    >>> from pickle import dumps, loads
+    >>> loads(dumps(TemplateError(message, token)))
+    TemplateError('message', 'token')
+
+    """
+
+    def __init__(self, msg, token):
+        if not isinstance(token, Token):
+            token = Token(token, 0)
+
+        self.msg = msg
+        self.token = safe_native(token)
+        self.offset = getattr(token, "pos", 0)
+        self.filename = token.filename
+
+    def __copy__(self):
+        inst = Exception.__new__(type(self))
+        inst.__dict__ = self.__dict__.copy()
+        return inst
+
+    def __reduce__(self):
+        return reconstruct_exc, (type(self), self.__dict__)
+
+    def __str__(self):
+        text = "%s\n\n" % self.msg
+        text += " - String:     \"%s\"" % self.token
+
+        if self.filename:
+            text += "\n"
+            text += " - Filename:   %s" % self.filename
+
+        try:
+            line, column = self.token.location
+        except AttributeError:
+            pass
+        else:
+            text += "\n"
+            text += " - Location:   (%d:%d)" % (line, column)
+
+        return text
+
+    def __repr__(self):
+        try:
+            return "%s('%s', '%s')" % (
+                self.__class__.__name__, self.msg, self.token
+                )
+        except AttributeError:
+            return object.__repr__(self)
+
+
+class ParseError(TemplateError):
+    """An error occurred during parsing.
+
+    Indicates an error on the structural level.
+    """
+
+
+class CompilationError(TemplateError):
+    """An error occurred during compilation.
+
+    Indicates a general compilation error.
+    """
+
+
+class TranslationError(TemplateError):
+    """An error occurred during translation.
+
+    Indicates a general translation error.
+    """
+
+
+class LanguageError(CompilationError):
+    """Language syntax error.
+
+    Indicates a syntactical error due to incorrect usage of the
+    template language.
+    """
+
+
+class ExpressionError(LanguageError):
+    """An error occurred compiling an expression.
+
+    Indicates a syntactical error in an expression.
+    """
+
+
+class ExceptionFormatter(object):
+    def __init__(self, errors, econtext, rcontext):
+        kwargs = rcontext.copy()
+        kwargs.update(econtext)
+
+        for name in tuple(kwargs):
+            if name.startswith('__'):
+                del kwargs[name]
+
+        self._errors = errors
+        self._kwargs = kwargs
+
+    def __call__(self):
+        # Format keyword arguments; consecutive arguments are indented
+        # for readability
+        try:
+            formatted = format_kwargs(self._kwargs)
+        except:
+            # the ``pprint.pformat`` method calls the representation
+            # method of the arguments; this may fail and since we're
+            # already in an exception handler, there's no point in
+            # pursuing this further
+            formatted = ()
+
+        for index, string in enumerate(formatted[1:]):
+            formatted[index + 1] = " " * 15 + string
+
+        out = []
+        seen = set()
+
+        for error in reversed(self._errors):
+            expression, line, column, filename, exc = error
+
+            if exc in seen:
+                continue
+
+            seen.add(exc)
+
+            if isinstance(exc, UnicodeDecodeError):
+                string = safe_native(exc.object)
+
+                s, marker = compute_source_marker(
+                    string, exc.start, string[exc.start:exc.end], LENGTH
+                    )
+
+                out.append(" - Stream:     %s" % s)
+                out.append("               %s" % marker)
+
+            _filename = ellipsify(filename, 60) if filename else "<string>"
+
+            out.append(" - Expression: \"%s\"" % expression)
+            out.append(" - Filename:   %s" % _filename)
+            out.append(" - Location:   (%d:%d)" % (line, column))
+
+            if filename and line and column:
+                try:
+                    f = open(filename, 'r')
+                except IOError:
+                    pass
+                else:
+                    try:
+                        # Pick out source line and format marker
+                        for i, l in enumerate(f):
+                            if i + 1 == line:
+                                s, marker = compute_source_marker(
+                                    l, column, expression, LENGTH
+                                    )
+
+                                out.append(" - Source:     %s" % s)
+                                out.append("               %s" % marker)
+                                break
+                    finally:
+                        f.close()
+
+        out.append(" - Arguments:  %s" % "\n".join(formatted))
+
+        formatted = traceback.format_exception_only(type(exc), exc)[-1]
+        formatted_class = "%s:" % type(exc).__name__
+
+        if formatted.startswith(formatted_class):
+            formatted = formatted[len(formatted_class):].lstrip()
+
+        return "\n".join(map(safe_native, [formatted] + out))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/i18n.py b/lib/Chameleon-2.9.2/src/chameleon/i18n.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/i18n.py
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import re
+
+from .exc import CompilationError
+from .utils import unicode_string
+
+NAME_RE = r"[a-zA-Z][-a-zA-Z0-9_]*"
+
+WHITELIST = frozenset([
+    "translate",
+    "domain",
+    "target",
+    "source",
+    "attributes",
+    "data",
+    "name",
+    "mode",
+    "xmlns",
+    "xml"
+    ])
+
+_interp_regex = re.compile(r'(?<!\$)(\$(?:(%(n)s)|{(%(n)s)}))'
+    % ({'n': NAME_RE}))
+
+
+try:  # pragma: no cover
+    str = unicode
+except NameError:
+    pass
+
+try:  # pragma: no cover
+    # optional: `zope.i18n`, `zope.i18nmessageid`
+    from zope.i18n import interpolate
+    from zope.i18n import translate
+    from zope.i18nmessageid import Message
+except ImportError:   # pragma: no cover
+
+    def fast_translate(msgid, domain=None, mapping=None, context=None,
+                       target_language=None, default=None):
+        if default is None:
+            return msgid
+
+        if mapping:
+            def replace(match):
+                whole, param1, param2 = match.groups()
+                return unicode_string(mapping.get(param1 or param2, whole))
+            return _interp_regex.sub(replace, default)
+
+        return default
+else:   # pragma: no cover
+    def fast_translate(msgid, domain=None, mapping=None, context=None,
+                       target_language=None, default=None):
+        if msgid is None:
+            return
+
+        if target_language is not None or context is not None:
+            result = translate(
+                msgid, domain=domain, mapping=mapping, context=context,
+                target_language=target_language, default=default)
+            if result != msgid:
+                return result
+
+        if isinstance(msgid, Message):
+            default = msgid.default
+            mapping = msgid.mapping
+
+        if default is None:
+            default = str(msgid)
+
+        if not isinstance(default, basestring):
+            return default
+
+        return interpolate(default, mapping)
+
+
+def parse_attributes(attrs, xml=True):
+    d = {}
+
+    # filter out empty items, eg:
+    # i18n:attributes="value msgid; name msgid2;"
+    # would result in 3 items where the last one is empty
+    attrs = [spec for spec in attrs.split(";") if spec]
+
+    for spec in attrs:
+        if ',' in spec:
+            raise CompilationError(
+                "Attribute must not contain comma. Use semicolon to "
+                "list multiple attributes", spec
+                )
+        parts = spec.split()
+        if len(parts) == 2:
+            attr, msgid = parts
+        elif len(parts) == 1:
+            attr = parts[0]
+            msgid = None
+        else:
+            raise CompilationError(
+                "Illegal i18n:attributes specification.", spec)
+        if not xml:
+            attr = attr.lower()
+        attr = attr.strip()
+        if attr in d:
+            raise CompilationError(
+                "Attribute may only be specified once in i18n:attributes", attr)
+        d[attr] = msgid
+
+    return d
diff --git a/lib/Chameleon-2.9.2/src/chameleon/interfaces.py b/lib/Chameleon-2.9.2/src/chameleon/interfaces.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/interfaces.py
@@ -0,0 +1,102 @@
+from zope.interface import Interface
+from zope.interface import Attribute
+
+
+class ITALExpressionErrorInfo(Interface):
+
+    type = Attribute("type",
+                     "The exception class.")
+
+    value = Attribute("value",
+                      "The exception instance.")
+
+    lineno = Attribute("lineno",
+                       "The line number the error occurred on in the source.")
+
+    offset = Attribute("offset",
+                       "The character offset at which the error occurred.")
+
+
+class ITALIterator(Interface):  # pragma: no cover
+    """A TAL iterator
+
+    Not to be confused with a Python iterator.
+    """
+
+    def next():
+        """Advance to the next value in the iteration, if possible
+
+        Return a true value if it was possible to advance and return
+        a false value otherwise.
+        """
+
+
+class ITALESIterator(ITALIterator):  # pragma: no cover
+    """TAL Iterator provided by TALES
+
+    Values of this iterator are assigned to items in the repeat namespace.
+
+    For example, with a TAL statement like: tal:repeat="item items",
+    an iterator will be assigned to "repeat/item".  The iterator
+    provides a number of handy methods useful in writing TAL loops.
+
+    The results are undefined of calling any of the methods except
+    'length' before the first iteration.
+    """
+
+    def index():
+        """Return the position (starting with "0") within the iteration
+        """
+
+    def number():
+        """Return the position (starting with "1") within the iteration
+        """
+
+    def even():
+        """Return whether the current position is even
+        """
+
+    def odd():
+        """Return whether the current position is odd
+        """
+
+    def parity():
+        """Return 'odd' or 'even' depending on the position's parity
+
+        Useful for assigning CSS class names to table rows.
+        """
+
+    def start():
+        """Return whether the current position is the first position
+        """
+
+    def end():
+        """Return whether the current position is the last position
+        """
+
+    def letter():
+        """Return the position (starting with "a") within the iteration
+        """
+
+    def Letter():
+        """Return the position (starting with "A") within the iteration
+        """
+
+    def roman():
+        """Return the position (starting with "i") within the iteration
+        """
+
+    def Roman():
+        """Return the position (starting with "I") within the iteration
+        """
+
+    def item():
+        """Return the item at the current position
+        """
+
+    def length():
+        """Return the length of the sequence
+
+        Note that this may fail if the TAL iterator was created on a Python
+        iterator.
+        """
diff --git a/lib/Chameleon-2.9.2/src/chameleon/loader.py b/lib/Chameleon-2.9.2/src/chameleon/loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/loader.py
@@ -0,0 +1,174 @@
+import functools
+import imp
+import logging
+import os
+import py_compile
+import shutil
+import sys
+import tempfile
+import warnings
+
+import pkg_resources
+
+log = logging.getLogger('chameleon.loader')
+
+try:
+    str = unicode
+except NameError:
+    basestring = str
+
+
+def cache(func):
+    def load(self, *args, **kwargs):
+        template = self.registry.get(args)
+        if template is None:
+            self.registry[args] = template = func(self, *args, **kwargs)
+        return template
+    return load
+
+
+def abspath_from_asset_spec(spec):
+    pname, filename = spec.split(':', 1)
+    return pkg_resources.resource_filename(pname, filename)
+
+if os.name == "nt":
+    def abspath_from_asset_spec(spec, f=abspath_from_asset_spec):
+        if spec[1] == ":":
+            return spec
+        return f(spec)
+
+
+class TemplateLoader(object):
+    """Template loader class.
+
+    To load templates using relative filenames, pass a sequence of
+    paths (or a single path) as ``search_path``.
+
+    To apply a default filename extension to inputs which do not have
+    an extension already (i.e. no dot), provide this as
+    ``default_extension`` (e.g. ``'.pt'``).
+
+    Additional keyword-arguments will be passed on to the template
+    constructor.
+    """
+
+    default_extension = None
+
+    def __init__(self, search_path=None, default_extension=None, **kwargs):
+        if search_path is None:
+            search_path = []
+        if isinstance(search_path, basestring):
+            search_path = [search_path]
+        if default_extension is not None:
+            self.default_extension = ".%s" % default_extension.lstrip('.')
+        self.search_path = search_path
+        self.registry = {}
+        self.kwargs = kwargs
+
+    @cache
+    def load(self, spec, cls=None):
+        if cls is None:
+            raise ValueError("Unbound template loader.")
+
+        spec = spec.strip()
+
+        if self.default_extension is not None and '.' not in spec:
+            spec += self.default_extension
+
+        if ':' in spec:
+            spec = abspath_from_asset_spec(spec)
+
+        if os.path.isabs(spec):
+            return cls(spec, **self.kwargs)
+
+        for path in self.search_path:
+            path = os.path.join(path, spec)
+            if os.path.exists(path):
+                return cls(path, **self.kwargs)
+
+        raise ValueError("Template not found: %s." % spec)
+
+    def bind(self, cls):
+        return functools.partial(self.load, cls=cls)
+
+
+class MemoryLoader(object):
+    def build(self, source, filename):
+        code = compile(source, filename, 'exec')
+        env = {}
+        exec(code, env)
+        return env
+
+    def get(self, name):
+        return None
+
+
+class ModuleLoader(object):
+    def __init__(self, path, remove=False):
+        self.path = path
+        self.remove = remove
+
+    def __del__(self, shutil=shutil):
+        if not self.remove:
+            return
+        try:
+            shutil.rmtree(self.path)
+        except:
+            warnings.warn("Could not clean up temporary file path: %s" % (self.path,))
+
+    def get(self, filename):
+        path = os.path.join(self.path, filename)
+        if os.path.exists(path):
+            log.debug("loading module from cache: %s." % filename)
+            base, ext = os.path.splitext(filename)
+            return self._load(base, path)
+        else:
+            log.debug('cache miss: %s' % filename)
+
+    def build(self, source, filename):
+        imp.acquire_lock()
+        try:
+            d = self.get(filename)
+            if d is not None:
+                return d
+
+            base, ext = os.path.splitext(filename)
+            name = os.path.join(self.path, base + ".py")
+
+            log.debug("writing source to disk (%d bytes)." % len(source))
+            fd, fn = tempfile.mkstemp(prefix=base, suffix='.tmp', dir=self.path)
+            temp = os.fdopen(fd, 'w')
+
+            try:
+                try:
+                    temp.write("%s\n" % '# -*- coding: utf-8 -*-')
+                    temp.write(source)
+                finally:
+                    temp.close()
+            except:
+                os.remove(fn)
+                raise
+
+            os.rename(fn, name)
+            log.debug("compiling %s into byte-code..." % filename)
+            py_compile.compile(name)
+
+            return self._load(base, name)
+        finally:
+            imp.release_lock()
+
+    def _load(self, base, filename):
+        imp.acquire_lock()
+        try:
+            module = sys.modules.get(base)
+            if module is None:
+                f = open(filename, 'rb')
+                try:
+                    assert base not in sys.modules
+                    module = imp.load_source(base, filename, f)
+                finally:
+                    f.close()
+        finally:
+            imp.release_lock()
+
+        return module.__dict__
diff --git a/lib/Chameleon-2.9.2/src/chameleon/metal.py b/lib/Chameleon-2.9.2/src/chameleon/metal.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/metal.py
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+WHITELIST = frozenset([
+    "define-macro",
+    "extend-macro",
+    "use-macro",
+    "define-slot",
+    "fill-slot",
+    "xmlns",
+    "xml"
+    ])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/namespaces.py b/lib/Chameleon-2.9.2/src/chameleon/namespaces.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/namespaces.py
@@ -0,0 +1,9 @@
+XML_NS = "http://www.w3.org/XML/1998/namespace"
+XMLNS_NS = "http://www.w3.org/2000/xmlns/"
+XHTML_NS = "http://www.w3.org/1999/xhtml"
+TAL_NS = "http://xml.zope.org/namespaces/tal"
+META_NS = "http://xml.zope.org/namespaces/meta"
+METAL_NS = "http://xml.zope.org/namespaces/metal"
+XI_NS = "http://www.w3.org/2001/XInclude"
+I18N_NS = "http://xml.zope.org/namespaces/i18n"
+PY_NS = "http://genshi.edgewall.org/"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/nodes.py b/lib/Chameleon-2.9.2/src/chameleon/nodes.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/nodes.py
@@ -0,0 +1,210 @@
+from .astutil import Node
+
+
+class UseExternalMacro(Node):
+    """Extend external macro."""
+
+    _fields = "expression", "slots", "extend"
+
+
+class Sequence(Node):
+    """Element sequence."""
+
+    _fields = "items",
+
+
+class Content(Node):
+    """Content substitution."""
+
+    _fields = "expression", "char_escape", "translate"
+
+
+class Default(Node):
+    """Represents a default value."""
+
+    _fields = "marker",
+
+
+class CodeBlock(Node):
+    _fields = "source",
+
+
+class Value(Node):
+    """Expression object value."""
+
+    _fields = "value",
+
+    def __repr__(self):
+        try:
+            line, column = self.value.location
+        except AttributeError:
+            line, column = 0, 0
+
+        return "<%s %r (%d:%d)>" % (
+            type(self).__name__, self.value, line, column
+            )
+
+
+class Substitution(Value):
+    """Expression value for text substitution."""
+
+    _fields = "value", "char_escape", "default"
+
+    default = None
+
+
+class Boolean(Value):
+    _fields = "value", "s"
+
+
+class Negate(Node):
+    """Wraps an expression with a negation."""
+
+    _fields = "value",
+
+
+class Element(Node):
+    """XML element."""
+
+    _fields = "start", "end", "content"
+
+
+class Attribute(Node):
+    """Element attribute."""
+
+    _fields = "name", "expression", "quote", "eq", "space"
+
+
+class Start(Node):
+    """Start-tag."""
+
+    _fields = "name", "prefix", "suffix", "attributes"
+
+
+class End(Node):
+    """End-tag."""
+
+    _fields = "name", "space", "prefix", "suffix"
+
+
+class Condition(Node):
+    """Node visited only if some condition holds."""
+
+    _fields = "expression", "node", "orelse"
+
+
+class Identity(Node):
+    """Condition expression that is true on identity."""
+
+    _fields = "expression", "value"
+
+
+class Equality(Node):
+    """Condition expression that is true on equality."""
+
+    _fields = "expression", "value"
+
+
+class Cache(Node):
+    """Cache (evaluate only once) the value of ``expression`` inside
+    ``node``.
+    """
+
+    _fields = "expressions", "node"
+
+
+class Assignment(Node):
+    """Variable assignment."""
+
+    _fields = "names", "expression", "local"
+
+
+class Alias(Assignment):
+    """Alias assignment.
+
+    Note that ``expression`` should be a cached or global value.
+    """
+
+    local = False
+
+
+class Define(Node):
+    """Variable definition in scope."""
+
+    _fields = "assignments", "node"
+
+
+class Repeat(Assignment):
+    """Iterate over provided assignment and repeat body."""
+
+    _fields = "names", "expression", "local", "whitespace", "node"
+
+
+class Macro(Node):
+    """Macro definition."""
+
+    _fields = "name", "body"
+
+
+class Program(Node):
+    _fields = "name", "body"
+
+
+class Module(Node):
+    _fields = "name", "program",
+
+
+class Context(Node):
+    _fields = "node",
+
+
+class Text(Node):
+    """Static text output."""
+
+    _fields = "value",
+
+
+class Interpolation(Text):
+    """String interpolation output."""
+
+    _fields = "value", "braces_required", "translation"
+
+
+class Translate(Node):
+    """Translate node."""
+
+    _fields = "msgid", "node"
+
+
+class Name(Node):
+    """Translation name."""
+
+    _fields = "name", "node"
+
+
+class Domain(Node):
+    """Update translation domain."""
+
+    _fields = "name", "node"
+
+
+class OnError(Node):
+    _fields = "fallback", "name", "node"
+
+
+class UseInternalMacro(Node):
+    """Use internal macro (defined inside same program)."""
+
+    _fields = "name",
+
+
+class FillSlot(Node):
+    """Fill a macro slot."""
+
+    _fields = "name", "node"
+
+
+class DefineSlot(Node):
+    """Define a macro slot."""
+
+    _fields = "name", "node"
diff --git a/lib/Chameleon-2.9.2/src/chameleon/parser.py b/lib/Chameleon-2.9.2/src/chameleon/parser.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/parser.py
@@ -0,0 +1,238 @@
+import re
+import logging
+
+try:
+    from collections import OrderedDict
+except ImportError:
+    from ordereddict import OrderedDict
+
+from .exc import ParseError
+from .namespaces import XML_NS
+from .tokenize import Token
+
+match_tag_prefix_and_name = re.compile(
+    r'^(?P<prefix></?)(?P<name>([^:\n ]+:)?[^ \n\t>/]+)'
+    '(?P<suffix>(?P<space>\s*)/?>)?',
+    re.UNICODE | re.DOTALL)
+match_single_attribute = re.compile(
+    r'(?P<space>\s+)(?!\d)'
+    r'(?P<name>[^ =/>\n\t]+)'
+    r'((?P<eq>\s*=\s*)'
+    r'((?P<quote>[\'"])(?P<value>.*?)(?P=quote)|'
+    r'(?P<alt_value>[^\s\'">/]+))|'
+    r'(?P<simple_value>(?![ \\n\\t\\r]*=)))',
+    re.UNICODE | re.DOTALL)
+match_comment = re.compile(
+    r'^<!--(?P<text>.*)-->$', re.DOTALL)
+match_cdata = re.compile(
+    r'^<!\[CDATA\[(?P<text>.*)\]>$', re.DOTALL)
+match_declaration = re.compile(
+    r'^<!(?P<text>[^>]+)>$', re.DOTALL)
+match_processing_instruction = re.compile(
+    r'^<\?(?P<name>\w+)(?P<text>.*?)\?>', re.DOTALL)
+match_xml_declaration = re.compile(r'^<\?xml(?=[ /])', re.DOTALL)
+
+log = logging.getLogger('chameleon.parser')
+
+
+def substitute(regex, repl, token):
+    if not isinstance(token, Token):
+        token = Token(token)
+
+    return Token(
+        regex.sub(repl, token),
+        token.pos,
+        token.source,
+        token.filename
+        )
+
+
+def groups(m, token):
+    result = []
+    for i, group in enumerate(m.groups()):
+        if group is not None:
+            j, k = m.span(i + 1)
+            group = token[j:k]
+
+        result.append(group)
+
+    return tuple(result)
+
+
+def groupdict(m, token):
+    d = m.groupdict()
+    for name, value in d.items():
+        if value is not None:
+            i, j = m.span(name)
+            d[name] = token[i:j]
+
+    return d
+
+
+def match_tag(token, regex=match_tag_prefix_and_name):
+    m = regex.match(token)
+    d = groupdict(m, token)
+
+    end = m.end()
+    token = token[end:]
+
+    attrs = d['attrs'] = []
+    for m in match_single_attribute.finditer(token):
+        attr = groupdict(m, token)
+        alt_value = attr.pop('alt_value', None)
+        if alt_value is not None:
+            attr['value'] = alt_value
+            attr['quote'] = ''
+        simple_value = attr.pop('simple_value', None)
+        if simple_value is not None:
+            attr['quote'] = ''
+            attr['value'] = ''
+            attr['eq'] = ''
+        attrs.append(attr)
+        d['suffix'] = token[m.end():]
+
+    return d
+
+
+def parse_tag(token, namespace):
+    node = match_tag(token)
+
+    update_namespace(node['attrs'], namespace)
+
+    if ':' in node['name']:
+        prefix = node['name'].split(':')[0]
+    else:
+        prefix = None
+
+    default = node['namespace'] = namespace.get(prefix, XML_NS)
+
+    node['ns_attrs'] = unpack_attributes(
+        node['attrs'], namespace, default)
+
+    return node
+
+
+def update_namespace(attributes, namespace):
+    # possibly update namespaces; we do this in a separate step
+    # because this assignment is irrespective of order
+    for attribute in attributes:
+        name = attribute['name']
+        value = attribute['value']
+        if name == 'xmlns':
+            namespace[None] = value
+        elif name.startswith('xmlns:'):
+            namespace[name[6:]] = value
+
+
+def unpack_attributes(attributes, namespace, default):
+    namespaced = OrderedDict()
+
+    for index, attribute in enumerate(attributes):
+        name = attribute['name']
+        value = attribute['value']
+
+        if ':' in name:
+            prefix = name.split(':')[0]
+            name = name[len(prefix) + 1:]
+            try:
+                ns = namespace[prefix]
+            except KeyError:
+                raise KeyError(
+                    "Undefined namespace prefix: %s." % prefix)
+        else:
+            ns = default
+        namespaced[ns, name] = value
+
+    return namespaced
+
+
+def identify(string):
+    if string.startswith("<"):
+        if string.startswith("<!--"):
+            return "comment"
+        if string.startswith("<![CDATA["):
+            return "cdata"
+        if string.startswith("<!"):
+            return "declaration"
+        if string.startswith("<?xml"):
+            return "xml_declaration"
+        if string.startswith("<?"):
+            return "processing_instruction"
+        if string.startswith("</"):
+            return "end_tag"
+        if string.endswith("/>"):
+            return "empty_tag"
+        if string.endswith(">"):
+            return "start_tag"
+        return "error"
+    return "text"
+
+
+class ElementParser(object):
+    """Parses tokens into elements."""
+
+    def __init__(self, stream, default_namespaces):
+        self.stream = stream
+        self.queue = []
+        self.index = []
+        self.namespaces = [default_namespaces.copy()]
+
+    def __iter__(self):
+        for token in self.stream:
+            item = self.parse(token)
+            self.queue.append(item)
+
+        return iter(self.queue)
+
+    def parse(self, token):
+        kind = identify(token)
+        visitor = getattr(self, "visit_%s" % kind, self.visit_default)
+        return visitor(kind, token)
+
+    def visit_comment(self, kind, token):
+        return "comment", (token, )
+
+    def visit_cdata(self, kind, token):
+        return "cdata", (token, )
+
+    def visit_default(self, kind, token):
+        return "default", (token, )
+
+    def visit_processing_instruction(self, kind, token):
+        m = match_processing_instruction.match(token)
+        return "processing_instruction", (groupdict(m, token), )
+
+    def visit_text(self, kind, token):
+        return kind, (token, )
+
+    def visit_start_tag(self, kind, token):
+        namespace = self.namespaces[-1].copy()
+        self.namespaces.append(namespace)
+        node = parse_tag(token, namespace)
+        self.index.append((node['name'], len(self.queue)))
+        return kind, (node, )
+
+    def visit_end_tag(self, kind, token):
+        try:
+            namespace = self.namespaces.pop()
+        except IndexError:
+            raise ParseError("Unexpected end tag.", token)
+
+        node = parse_tag(token, namespace)
+
+        while self.index:
+            name, pos = self.index.pop()
+            if name == node['name']:
+                start, = self.queue.pop(pos)[1]
+                children = self.queue[pos:]
+                del self.queue[pos:]
+                break
+        else:
+            raise ParseError("Unexpected end tag.", token)
+
+        return "element", (start, node, children)
+
+    def visit_empty_tag(self, kind, token):
+        namespace = self.namespaces[-1].copy()
+        node = parse_tag(token, namespace)
+        return "element", (node, None, [])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/program.py b/lib/Chameleon-2.9.2/src/chameleon/program.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/program.py
@@ -0,0 +1,38 @@
+try:
+    str = unicode
+except NameError:
+    long = int
+
+from .tokenize import iter_xml
+from .tokenize import iter_text
+from .parser import ElementParser
+from .namespaces import XML_NS
+from .namespaces import XMLNS_NS
+
+
+class ElementProgram(object):
+    DEFAULT_NAMESPACES = {
+        'xmlns': XMLNS_NS,
+        'xml': XML_NS,
+        }
+
+    tokenizers = {
+        'xml': iter_xml,
+        'text': iter_text,
+        }
+
+    def __init__(self, source, mode="xml", filename=None):
+        tokenizer = self.tokenizers[mode]
+        tokens = tokenizer(source, filename)
+        parser = ElementParser(tokens, self.DEFAULT_NAMESPACES)
+
+        self.body = []
+
+        for kind, args in parser:
+            node = self.visit(kind, args)
+            if node is not None:
+                self.body.append(node)
+
+    def visit(self, kind, args):
+        visitor = getattr(self, "visit_%s" % kind)
+        return visitor(*args)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/py25.py b/lib/Chameleon-2.9.2/src/chameleon/py25.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/py25.py
@@ -0,0 +1,36 @@
+import sys
+
+def lookup_attr(obj, key):
+    try:
+        return getattr(obj, key)
+    except AttributeError:
+        exc = sys.exc_info()[1]
+        try:
+            get = obj.__getitem__
+        except AttributeError:
+            raise exc
+        try:
+            return get(key)
+        except KeyError:
+            raise exc
+
+def exec_(code, globs=None, locs=None):
+    """Execute code in a namespace."""
+    if globs is None:
+        frame = sys._getframe(1)
+        globs = frame.f_globals
+        if locs is None:
+            locs = frame.f_locals
+        del frame
+    elif locs is None:
+        locs = globs
+    exec("""exec code in globs, locs""")
+
+
+exec_("""def raise_with_traceback(exc, tb):
+    raise type(exc), exc, tb
+""")
+
+
+def next(iter):
+    return iter.next()
diff --git a/lib/Chameleon-2.9.2/src/chameleon/py26.py b/lib/Chameleon-2.9.2/src/chameleon/py26.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/py26.py
@@ -0,0 +1,15 @@
+import sys
+
+def lookup_attr(obj, key):
+    try:
+        return getattr(obj, key)
+    except AttributeError:
+        exc = sys.exc_info()[1]
+        try:
+            get = obj.__getitem__
+        except AttributeError:
+            raise exc
+        try:
+            return get(key)
+        except KeyError:
+            raise exc
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tal.py b/lib/Chameleon-2.9.2/src/chameleon/tal.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tal.py
@@ -0,0 +1,479 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import re
+import copy
+
+from .exc import LanguageError
+from .utils import descriptorint
+from .utils import descriptorstr
+from .namespaces import XMLNS_NS
+from .parser import groups
+
+
+try:
+    next
+except NameError:
+    from chameleon.py25 import next
+
+try:
+    # optional library: `zope.interface`
+    import interfaces
+    import zope.interface
+except ImportError:
+    interfaces = None
+
+
+NAME = r"[a-zA-Z_][-a-zA-Z0-9_]*"
+DEFINE_RE = re.compile(r"(?s)\s*(?:(global|local)\s+)?" +
+                       r"(%s|\(%s(?:,\s*%s)*\))\s+(.*)\Z" % (NAME, NAME, NAME),
+                       re.UNICODE)
+SUBST_RE = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S | re.UNICODE)
+ATTR_RE = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S | re.UNICODE)
+
+ENTITY_RE = re.compile(r'(&(#?)(x?)(\d{1,5}|\w{1,8});)')
+
+WHITELIST = frozenset([
+    "define",
+    "comment",
+    "condition",
+    "content",
+    "replace",
+    "repeat",
+    "attributes",
+    "on-error",
+    "omit-tag",
+    "script",
+    "switch",
+    "case",
+    "xmlns",
+    "xml"
+    ])
+
+
+def split_parts(arg):
+    # Break in pieces at undoubled semicolons and
+    # change double semicolons to singles:
+    i = 0
+    while i < len(arg):
+        m = ENTITY_RE.search(arg[i:])
+        if m is None:
+            break
+        arg = arg[:i + m.end()] + ';' + arg[i + m.end():]
+        i += m.end()
+
+    arg = arg.replace(";;", "\0")
+    parts = arg.split(';')
+    parts = [p.replace("\0", ";") for p in parts]
+    if len(parts) > 1 and not parts[-1].strip():
+        del parts[-1]  # It ended in a semicolon
+
+    return parts
+
+
+def parse_attributes(clause):
+    attrs = {}
+    for part in split_parts(clause):
+        m = ATTR_RE.match(part)
+        if not m:
+            raise LanguageError(
+                "Bad syntax in attributes.", clause)
+        name, expr = groups(m, part)
+        if name in attrs:
+            raise LanguageError(
+                "Duplicate attribute name in attributes.", part)
+
+        attrs[name] = expr
+
+    return attrs
+
+
+def parse_substitution(clause):
+    m = SUBST_RE.match(clause)
+    if m is None:
+        raise LanguageError(
+            "Invalid content substitution syntax.", clause)
+
+    key, expression = groups(m, clause)
+    if not key:
+        key = "text"
+
+    return key, expression
+
+
+def parse_defines(clause):
+    """
+    Parses a tal:define value.
+
+    # Basic syntax, implicit local
+    >>> parse_defines('hello lovely')
+    [('local', ('hello',), 'lovely')]
+
+    # Explicit local
+    >>> parse_defines('local hello lovely')
+    [('local', ('hello',), 'lovely')]
+
+    # With global
+    >>> parse_defines('global hello lovely')
+    [('global', ('hello',), 'lovely')]
+
+    # Multiple expressions
+    >>> parse_defines('hello lovely; tea time')
+    [('local', ('hello',), 'lovely'), ('local', ('tea',), 'time')]
+
+    # With multiple names
+    >>> parse_defines('(hello, howdy) lovely')
+    [('local', ['hello', 'howdy'], 'lovely')]
+
+    # With unicode whitespace
+    >>> try:
+    ...     s = '\xc2\xa0hello lovely'.decode('utf-8')
+    ... except AttributeError:
+    ...     s = '\xa0hello lovely'
+    >>> from chameleon.utils import unicode_string
+    >>> parse_defines(s) == [
+    ...     ('local', ('hello',), 'lovely')
+    ... ]
+    True
+
+    """
+    defines = []
+    for part in split_parts(clause):
+        m = DEFINE_RE.match(part)
+        if m is None:
+            raise LanguageError("Invalid define syntax", part)
+        context, name, expr = groups(m, part)
+        context = context or "local"
+
+        if name.startswith('('):
+            names = [n.strip() for n in name.strip('()').split(',')]
+        else:
+            names = (name,)
+
+        defines.append((context, names, expr))
+
+    return defines
+
+
+def prepare_attributes(attrs, dyn_attributes, i18n_attributes,
+                       ns_attributes, drop_ns):
+    drop = set([attribute['name'] for attribute, (ns, value)
+                in zip(attrs, ns_attributes)
+                if ns in drop_ns or (
+                    ns == XMLNS_NS and
+                    attribute['value'] in drop_ns
+                    )
+                ])
+
+    attributes = []
+    normalized = {}
+
+    for attribute in attrs:
+        name = attribute['name']
+
+        if name in drop:
+            continue
+
+        attributes.append((
+            name,
+            attribute['value'],
+            attribute['quote'],
+            attribute['space'],
+            attribute['eq'],
+            None,
+            ))
+
+        normalized[name.lower()] = len(attributes) - 1
+
+    for name, expr in dyn_attributes.items():
+        index = normalized.get(name.lower())
+        if index is not None:
+            _, text, quote, space, eq, _ = attributes[index]
+            add = attributes.__setitem__
+        else:
+            text = None
+            quote = '"'
+            space = " "
+            eq = "="
+            index = len(attributes)
+            add = attributes.insert
+            normalized[name.lower()] = len(attributes) - 1
+
+        attribute = name, text, quote, space, eq, expr
+        add(index, attribute)
+
+    for name in i18n_attributes:
+        attr = name.lower()
+        if attr not in normalized:
+            attributes.append((name, name, '"', " ", "=", None))
+            normalized[attr] = len(attributes) - 1
+
+    return attributes
+
+
+class RepeatItem(object):
+    __slots__ = "length", "_iterator"
+
+    __allow_access_to_unprotected_subobjects__ = True
+
+    def __init__(self, iterator, length):
+        self.length = length
+        self._iterator = iterator
+
+    def __iter__(self):
+        return self._iterator
+
+    try:
+        iter(()).__len__
+    except AttributeError:
+        @descriptorint
+        def index(self):
+            try:
+                remaining = self._iterator.__length_hint__()
+            except AttributeError:
+                remaining = len(tuple(copy.copy(self._iterator)))
+            return self.length - remaining - 1
+    else:
+        @descriptorint
+        def index(self):
+            remaining = self._iterator.__len__()
+            return self.length - remaining - 1
+
+    @descriptorint
+    def start(self):
+        return self.index == 0
+
+    @descriptorint
+    def end(self):
+        return self.index == self.length - 1
+
+    @descriptorint
+    def number(self):
+        return self.index + 1
+
+    @descriptorstr
+    def odd(self):
+        """Returns a true value if the item index is odd.
+
+        >>> it = RepeatItem(iter(("apple", "pear")), 2)
+
+        >>> next(it._iterator)
+        'apple'
+        >>> it.odd()
+        ''
+
+        >>> next(it._iterator)
+        'pear'
+        >>> it.odd()
+        'odd'
+        """
+
+        return self.index % 2 == 1 and 'odd' or ''
+
+    @descriptorstr
+    def even(self):
+        """Returns a true value if the item index is even.
+
+        >>> it = RepeatItem(iter(("apple", "pear")), 2)
+
+        >>> next(it._iterator)
+        'apple'
+        >>> it.even()
+        'even'
+
+        >>> next(it._iterator)
+        'pear'
+        >>> it.even()
+        ''
+        """
+
+        return self.index % 2 == 0 and 'even' or ''
+
+    def next(self):
+        raise NotImplementedError(
+            "Method not implemented (can't update local variable).")
+
+    def _letter(self, base=ord('a'), radix=26):
+        """Get the iterator position as a lower-case letter
+
+        >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+        >>> next(it._iterator)
+        'apple'
+        >>> it.letter()
+        'a'
+        >>> next(it._iterator)
+        'pear'
+        >>> it.letter()
+        'b'
+        >>> next(it._iterator)
+        'orange'
+        >>> it.letter()
+        'c'
+        """
+
+        index = self.index
+        if index < 0:
+            raise TypeError("No iteration position")
+        s = ""
+        while 1:
+            index, off = divmod(index, radix)
+            s = chr(base + off) + s
+            if not index:
+                return s
+
+    letter = descriptorstr(_letter)
+
+    @descriptorstr
+    def Letter(self):
+        """Get the iterator position as an upper-case letter
+
+        >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+        >>> next(it._iterator)
+        'apple'
+        >>> it.Letter()
+        'A'
+        >>> next(it._iterator)
+        'pear'
+        >>> it.Letter()
+        'B'
+        >>> next(it._iterator)
+        'orange'
+        >>> it.Letter()
+        'C'
+        """
+
+        return self._letter(base=ord('A'))
+
+    @descriptorstr
+    def Roman(self, rnvalues=(
+                    (1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'),
+                    (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'),
+                    (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I'))):
+        """Get the iterator position as an upper-case roman numeral
+
+        >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+        >>> next(it._iterator)
+        'apple'
+        >>> it.Roman()
+        'I'
+        >>> next(it._iterator)
+        'pear'
+        >>> it.Roman()
+        'II'
+        >>> next(it._iterator)
+        'orange'
+        >>> it.Roman()
+        'III'
+        """
+
+        n = self.index + 1
+        s = ""
+        for v, r in rnvalues:
+            rct, n = divmod(n, v)
+            s = s + r * rct
+        return s
+
+    @descriptorstr
+    def roman(self):
+        """Get the iterator position as a lower-case roman numeral
+
+        >>> it = RepeatItem(iter(("apple", "pear", "orange")), 3)
+        >>> next(it._iterator)
+        'apple'
+        >>> it.roman()
+        'i'
+        >>> next(it._iterator)
+        'pear'
+        >>> it.roman()
+        'ii'
+        >>> next(it._iterator)
+        'orange'
+        >>> it.roman()
+        'iii'
+        """
+
+        return self.Roman().lower()
+
+
+if interfaces is not None:
+    zope.interface.classImplements(RepeatItem, interfaces.ITALESIterator)
+
+
+class RepeatDict(dict):
+    """Repeat dictionary implementation.
+
+    >>> repeat = RepeatDict({})
+    >>> iterator, length = repeat('numbers', range(5))
+    >>> length
+    5
+
+    >>> repeat['numbers']
+    <chameleon.tal.RepeatItem object at ...>
+
+    """
+
+    __slots__ = "__setitem__", "__getitem__", "__getattr__"
+
+    def __init__(self, d):
+        self.__setitem__ = d.__setitem__
+        self.__getitem__ = d.__getitem__
+        self.__getattr__ = d.__getitem__
+
+    def __call__(self, key, iterable):
+        """We coerce the iterable to a tuple and return an iterator
+        after registering it in the repeat dictionary."""
+
+        try:
+            iterable = tuple(iterable)
+        except TypeError:
+            if iterable is None:
+                iterable = ()
+            else:
+                # The message below to the TypeError is the Python
+                # 2.5-style exception message. Python 2.4.X also
+                # raises a TypeError, but with a different message.
+                # ("TypeError: iteration over non-sequence").  The
+                # Python 2.5 error message is more helpful.  We
+                # construct the 2.5-style message explicitly here so
+                # that both Python 2.4.X and Python 2.5+ will raise
+                # the same error.  This makes writing the tests eaiser
+                # and makes the output easier to understand.
+                raise TypeError("%r object is not iterable" %
+                                type(iterable).__name__)
+
+        length = len(iterable)
+        iterator = iter(iterable)
+
+        # Insert as repeat item
+        self[key] = RepeatItem(iterator, length)
+
+        return iterator, length
+
+
+class ErrorInfo(object):
+    """Information about an exception passed to an on-error handler."""
+
+    def __init__(self, err, position=(None, None)):
+        if isinstance(err, Exception):
+            self.type = err.__class__
+            self.value = err
+        else:
+            self.type = err
+            self.value = None
+        self.lineno = position[0]
+        self.offset = position[1]
+
+
+if interfaces is not None:
+    zope.interface.classImplements(ErrorInfo, interfaces.ITALExpressionErrorInfo)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tales.py b/lib/Chameleon-2.9.2/src/chameleon/tales.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tales.py
@@ -0,0 +1,541 @@
+import re
+import sys
+
+from .astutil import parse
+from .astutil import store
+from .astutil import load
+from .astutil import ItemLookupOnAttributeErrorVisitor
+from .codegen import TemplateCodeGenerator
+from .codegen import template
+from .codegen import reverse_builtin_map
+from .astutil import Builtin
+from .astutil import Symbol
+from .exc import ExpressionError
+from .utils import resolve_dotted
+from .utils import Markup
+from .utils import ast
+from .tokenize import Token
+from .parser import substitute
+from .compiler import Interpolator
+
+try:
+    from .py26 import lookup_attr
+except SyntaxError:
+    from .py25 import lookup_attr
+
+
+split_parts = re.compile(r'(?<!\\)\|')
+match_prefix = re.compile(r'^\s*([a-z\-_]+):').match
+re_continuation = re.compile(r'\\\s*$', re.MULTILINE)
+
+try:
+    from __builtin__ import basestring
+except ImportError:
+    basestring = str
+
+
+def resolve_global(value):
+    name = reverse_builtin_map.get(value)
+    if name is not None:
+        return Builtin(name)
+
+    return Symbol(value)
+
+
+def test(expression, engine=None, **env):
+    if engine is None:
+        engine = SimpleEngine()
+
+    body = expression(store("result"), engine)
+    module = ast.Module(body)
+    module = ast.fix_missing_locations(module)
+    env['rcontext'] = {}
+    source = TemplateCodeGenerator(module).code
+    code = compile(source, '<string>', 'exec')
+    exec(code, env)
+    result = env["result"]
+
+    if isinstance(result, basestring):
+        result = str(result)
+
+    return result
+
+
+def transform_attribute(node):
+    return template(
+        "lookup(object, name)",
+        lookup=Symbol(lookup_attr),
+        object=node.value,
+        name=ast.Str(s=node.attr),
+        mode="eval"
+        )
+
+
+class TalesExpr(object):
+    """Base class.
+
+    This class helps implementations for the Template Attribute
+    Language Expression Syntax (TALES).
+
+    The syntax evaluates one or more expressions, separated by '|'
+    (pipe). The first expression that succeeds, is returned.
+
+    Expression:
+
+      expression    := (type ':')? line ('|' expression)?
+      line          := .*
+
+    Expression lines may not contain the pipe character unless
+    escaped. It has a special meaning:
+
+    If the expression to the left of the pipe fails (raises one of the
+    exceptions listed in ``catch_exceptions``), evaluation proceeds to
+    the expression(s) on the right.
+
+    Subclasses must implement ``translate`` which assigns a value for
+    a given expression.
+
+    >>> class PythonPipeExpr(TalesExpr):
+    ...     def translate(self, expression, target):
+    ...         compiler = PythonExpr(expression)
+    ...         return compiler(target, None)
+
+    >>> test(PythonPipeExpr('foo | bar | 42'))
+    42
+
+    >>> test(PythonPipeExpr('foo|42'))
+    42
+    """
+
+    exceptions = NameError, \
+                 ValueError, \
+                 AttributeError, \
+                 LookupError, \
+                 TypeError
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        remaining = self.expression
+        assignments = []
+
+        while remaining:
+            if match_prefix(remaining) is not None:
+                compiler = engine.parse(remaining)
+                assignment = compiler.assign_value(target)
+                remaining = ""
+            else:
+                for m in split_parts.finditer(remaining):
+                    expression = remaining[:m.start()]
+                    remaining = remaining[m.end():]
+                    break
+                else:
+                    expression = remaining
+                    remaining = ""
+
+                expression = expression.replace('\\|', '|')
+                assignment = self.translate(expression, target)
+            assignments.append(assignment)
+
+        if not assignments:
+            assignments.append(
+                self.translate(remaining, target)
+                )
+
+        for i, assignment in enumerate(reversed(assignments)):
+            if i == 0:
+                body = assignment
+            else:
+                body = [ast.TryExcept(
+                    body=assignment,
+                    handlers=[ast.ExceptHandler(
+                        type=ast.Tuple(
+                            elts=map(resolve_global, self.exceptions),
+                            ctx=ast.Load()),
+                        name=None,
+                        body=body,
+                        )],
+                    )]
+
+        return body
+
+    def translate(self, expression, target):
+        """Return statements that assign a value to ``target``."""
+
+        raise NotImplementedError(
+            "Must be implemented by a subclass.")
+
+
+class PathExpr(TalesExpr):
+    """Path expression compiler.
+
+    Syntax::
+
+        PathExpr ::= Path [ '|' Path ]*
+        Path ::= variable [ '/' URL_Segment ]*
+        variable ::= Name
+
+    For example::
+
+        request/cookies/oatmeal
+        nothing
+        here/some-file 2001_02.html.tar.gz/foo
+        root/to/branch | default
+
+    When a path expression is evaluated, it attempts to traverse
+    each path, from left to right, until it succeeds or runs out of
+    paths. To traverse a path, it first fetches the object stored in
+    the variable. For each path segment, it traverses from the current
+    object to the subobject named by the path segment.
+
+    Once a path has been successfully traversed, the resulting object
+    is the value of the expression. If it is a callable object, such
+    as a method or class, it is called.
+
+    The semantics of traversal (and what it means to be callable) are
+    implementation-dependent (see the ``translate`` method).
+    """
+
+    def translate(self, expression, target):
+        raise NotImplementedError(
+            "Path expressions are not yet implemented. "
+            "It's unclear whether a general implementation "
+            "can be devised.")
+
+
+class PythonExpr(TalesExpr):
+    """Python expression compiler.
+
+    >>> test(PythonExpr('2 + 2'))
+    4
+
+    The Python expression is a TALES expression. That means we can use
+    the pipe operator:
+
+    >>> test(PythonExpr('foo | 2 + 2 | 5'))
+    4
+
+    To include a pipe character, use a backslash escape sequence:
+
+    >>> test(PythonExpr('\"\|\"'))
+    '|'
+    """
+
+    transform = ItemLookupOnAttributeErrorVisitor(transform_attribute)
+
+    def parse(self, string):
+        return parse(string, 'eval').body
+
+    def translate(self, expression, target):
+        # Strip spaces
+        string = expression.strip()
+
+        # Conver line continuations to newlines
+        string = substitute(re_continuation, '\n', string)
+
+        # Convert newlines to spaces
+        string = string.replace('\n', ' ')
+
+        try:
+            value = self.parse(string)
+        except SyntaxError:
+            exc = sys.exc_info()[1]
+            raise ExpressionError(exc.msg, string)
+
+        # Transform attribute lookups to allow fallback to item lookup
+        self.transform.visit(value)
+
+        return [ast.Assign(targets=[target], value=value)]
+
+
+class ImportExpr(object):
+    re_dotted = re.compile(r'^[A-Za-z.]+$')
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        string = self.expression.strip().replace('\n', ' ')
+        value = template(
+            "RESOLVE(NAME)",
+            RESOLVE=Symbol(resolve_dotted),
+            NAME=ast.Str(s=string),
+            mode="eval",
+            )
+        return [ast.Assign(targets=[target], value=value)]
+
+
+class NotExpr(object):
+    """Negates the expression.
+
+    >>> engine = SimpleEngine(PythonExpr)
+
+    >>> test(NotExpr('False'), engine)
+    True
+    >>> test(NotExpr('True'), engine)
+    False
+    """
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        compiler = engine.parse(self.expression)
+        body = compiler.assign_value(target)
+        return body + template("target = not target", target=target)
+
+
+class StructureExpr(object):
+    """Wraps the expression result as 'structure'.
+
+    >>> engine = SimpleEngine(PythonExpr)
+
+    >>> test(StructureExpr('\"<tt>foo</tt>\"'), engine)
+    '<tt>foo</tt>'
+    """
+
+    wrapper_class = Symbol(Markup)
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        compiler = engine.parse(self.expression)
+        body = compiler.assign_value(target)
+        return body + template(
+            "target = wrapper(target)",
+            target=target,
+            wrapper=self.wrapper_class
+            )
+
+
+class IdentityExpr(object):
+    """Identity expression.
+
+    Exists to demonstrate the interface.
+
+    >>> test(IdentityExpr('42'))
+    42
+    """
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        compiler = engine.parse(self.expression)
+        return compiler.assign_value(target)
+
+
+class StringExpr(object):
+    """Similar to the built-in ``string.Template``, but uses an
+    expression engine to support pluggable string substitution
+    expressions.
+
+    Expr string:
+
+      string       := (text | substitution) (string)?
+      substitution := ('$' variable | '${' expression '}')
+      text         := .*
+
+    In other words, an expression string can contain multiple
+    substitutions. The text- and substitution parts will be
+    concatenated back into a string.
+
+    >>> test(StringExpr('Hello ${name}!'), name='world')
+    'Hello world!'
+
+    In the default configuration, braces may be omitted if the
+    expression is an identifier.
+
+    >>> test(StringExpr('Hello $name!'), name='world')
+    'Hello world!'
+
+    The ``braces_required`` flag changes this setting:
+
+    >>> test(StringExpr('Hello $name!', True))
+    'Hello $name!'
+
+    We can escape interpolation using the standard escaping
+    syntax:
+
+    >>> test(StringExpr('\\${name}'))
+    '\\\${name}'
+
+    Multiple interpolations in one:
+
+    >>> test(StringExpr(\"Hello ${'a'}${'b'}${'c'}!\"))
+    'Hello abc!'
+
+    Here's a more involved example taken from a javascript source:
+
+    >>> result = test(StringExpr(\"\"\"
+    ... function(oid) {
+    ...     $('#' + oid).autocomplete({source: ${'source'}});
+    ... }
+    ... \"\"\"))
+
+    >>> 'source: source' in result
+    True
+
+    In the above examples, the expression is evaluated using the
+    dummy engine which just returns the input as a string.
+
+    As an example, we'll implement an expression engine which
+    instead counts the number of characters in the expresion and
+    returns an integer result.
+
+    >>> class engine:
+    ...     @staticmethod
+    ...     def parse(expression):
+    ...         class compiler:
+    ...             @staticmethod
+    ...             def assign_text(target):
+    ...                 return [
+    ...                     ast.Assign(
+    ...                         targets=[target],
+    ...                         value=ast.Num(n=len(expression))
+    ...                     )]
+    ...
+    ...         return compiler
+
+    This will demonstrate how the string expression coerces the
+    input to a string.
+
+    >>> expr = StringExpr(
+    ...    'There are ${hello world} characters in \"hello world\"')
+
+    We evaluate the expression using the new engine:
+
+    >>> test(expr, engine)
+    'There are 11 characters in \"hello world\"'
+    """
+
+    def __init__(self, expression, braces_required=False):
+        # The code relies on the expression being a token string
+        if not isinstance(expression, Token):
+            expression = Token(expression, 0)
+
+        self.translator = Interpolator(expression, braces_required)
+
+    def __call__(self, name, engine):
+        return self.translator(name, engine)
+
+
+class ProxyExpr(StringExpr):
+    def __init__(self, name, *args):
+        super(ProxyExpr, self).__init__(*args)
+        self.name = name
+
+    def __call__(self, target, engine):
+        assignment = super(ProxyExpr, self).__call__(target, engine)
+        return assignment + [
+            ast.Assign(targets=[target], value=ast.Call(
+                func=load(self.name),
+                args=[target],
+                keywords=[],
+                starargs=None,
+                kwargs=None
+                ))
+            ]
+
+
+class ExistsExpr(object):
+    """Boolean wrapper.
+
+    Return 0 if the expression results in an exception, otherwise 1.
+
+    As a means to generate exceptions, we set up an expression engine
+    which evaluates the provided expression using Python:
+
+    >>> engine = SimpleEngine(PythonExpr)
+
+    >>> test(ExistsExpr('int(0)'), engine)
+    1
+    >>> test(ExistsExpr('int(None)'), engine)
+    0
+
+    """
+
+    exceptions = AttributeError, LookupError, TypeError, NameError, KeyError
+
+    def __init__(self, expression):
+        self.expression = expression
+
+    def __call__(self, target, engine):
+        ignore = store("_ignore")
+        compiler = engine.parse(self.expression)
+        body = compiler.assign_value(ignore)
+
+        classes = map(resolve_global, self.exceptions)
+
+        return [
+            ast.TryExcept(
+                body=body,
+                handlers=[ast.ExceptHandler(
+                    type=ast.Tuple(elts=classes, ctx=ast.Load()),
+                    name=None,
+                    body=template("target = 0", target=target),
+                    )],
+                orelse=template("target = 1", target=target)
+                )
+            ]
+
+
+class ExpressionParser(object):
+    def __init__(self, factories, default):
+        self.factories = factories
+        self.default = default
+
+    def __call__(self, expression):
+        m = match_prefix(expression)
+        if m is not None:
+            prefix = m.group(1)
+            expression = expression[m.end():]
+        else:
+            prefix = self.default
+
+        try:
+            factory = self.factories[prefix]
+        except KeyError:
+            exc = sys.exc_info()[1]
+            raise LookupError(
+                "Unknown expression type: %s." % str(exc)
+                )
+
+        return factory(expression)
+
+
+class SimpleEngine(object):
+    expression = PythonExpr
+
+    def __init__(self, expression=None):
+        if expression is not None:
+            self.expression = expression
+
+    def parse(self, string):
+        compiler = self.expression(string)
+        return SimpleCompiler(compiler, self)
+
+
+class SimpleCompiler(object):
+    def __init__(self, compiler, engine):
+        self.compiler = compiler
+        self.engine = engine
+
+    def assign_text(self, target):
+        """Assign expression string as a text value."""
+
+        return self._assign_value_and_coerce(target, "str")
+
+    def assign_value(self, target):
+        """Assign expression string as object value."""
+
+        return self.compiler(target, self.engine)
+
+    def _assign_value_and_coerce(self, target, builtin):
+        return self.assign_value(target) + template(
+            "target = builtin(target)",
+            target=target,
+            builtin=builtin
+            )
diff --git a/lib/Chameleon-2.9.2/src/chameleon/template.py b/lib/Chameleon-2.9.2/src/chameleon/template.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/template.py
@@ -0,0 +1,332 @@
+from __future__ import with_statement
+
+import os
+import sys
+import copy
+import hashlib
+import shutil
+import logging
+import tempfile
+import inspect
+
+pkg_digest = hashlib.sha1(__name__.encode('utf-8'))
+
+try:
+    import pkg_resources
+except ImportError:
+    logging.info("Setuptools not installed. Unable to determine version.")
+else:
+    for path in sys.path:
+        for distribution in pkg_resources.find_distributions(path):
+            if distribution.has_version():
+                version = distribution.version.encode('utf-8')
+                pkg_digest.update(version)
+
+
+from .exc import TemplateError
+from .exc import ExceptionFormatter
+from .compiler import Compiler
+from .config import DEBUG_MODE
+from .config import AUTO_RELOAD
+from .config import EAGER_PARSING
+from .config import CACHE_DIRECTORY
+from .loader import ModuleLoader
+from .loader import MemoryLoader
+from .nodes import Module
+from .utils import DebuggingOutputStream
+from .utils import Scope
+from .utils import join
+from .utils import mangle
+from .utils import create_formatted_exception
+from .utils import read_bytes
+from .utils import raise_with_traceback
+from .utils import byte_string
+
+
+log = logging.getLogger('chameleon.template')
+
+
+def _make_module_loader():
+    remove = False
+    if CACHE_DIRECTORY:
+        path = CACHE_DIRECTORY
+    else:
+        path = tempfile.mkdtemp()
+        remove = True
+
+    return ModuleLoader(path)
+
+
+class BaseTemplate(object):
+    """Template base class.
+
+    Takes a string input which must be one of the following:
+
+    - a unicode string (or string on Python 3);
+    - a utf-8 encoded byte string;
+    - a byte string for an XML document that defines an encoding
+      in the document premamble;
+    - an HTML document that specifies the encoding via the META tag.
+
+    Note that the template input is decoded, parsed and compiled on
+    initialization.
+    """
+
+    default_encoding = "utf-8"
+
+    # This attribute is strictly informational in this template class
+    # and is used in exception formatting. It may be set on
+    # initialization using the optional ``filename`` keyword argument.
+    filename = '<string>'
+
+    _cooked = False
+
+    if DEBUG_MODE or CACHE_DIRECTORY:
+        loader = _make_module_loader()
+    else:
+        loader = MemoryLoader()
+
+    if DEBUG_MODE:
+        output_stream_factory = DebuggingOutputStream
+    else:
+        output_stream_factory = list
+
+    debug = DEBUG_MODE
+
+    # The ``builtins`` dictionary can be used by a template class to
+    # add symbols which may not be redefined and which are (cheaply)
+    # available in the template variable scope
+    builtins = {}
+
+    # The ``builtins`` dictionary is updated with this dictionary at
+    # cook time. Note that it can be provided at class initialization
+    # using the ``extra_builtins`` keyword argument.
+    extra_builtins = {}
+
+    # Expression engine must be provided by subclass
+    engine = None
+
+    # When ``strict`` is set, expressions must be valid at compile
+    # time. When not set, this is only required at evaluation time.
+    strict = True
+
+    def __init__(self, body=None, **config):
+        self.__dict__.update(config)
+
+        if body is not None:
+            self.write(body)
+
+        # This is only necessary if the ``debug`` flag was passed as a
+        # keyword argument
+        if self.__dict__.get('debug') is True:
+            self.loader = _make_module_loader()
+
+    def __call__(self, **kwargs):
+        return self.render(**kwargs)
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__, self.filename)
+
+    @property
+    def keep_body(self):
+        # By default, we only save the template body if we're
+        # in debugging mode (to save memory).
+        return self.__dict__.get('keep_body', DEBUG_MODE)
+
+    @property
+    def keep_source(self):
+        # By default, we only save the generated source code if we're
+        # in debugging mode (to save memory).
+        return self.__dict__.get('keep_source', DEBUG_MODE)
+
+    def cook(self, body):
+        digest = self._digest(body)
+        builtins_dict = self.builtins.copy()
+        builtins_dict.update(self.extra_builtins)
+        names, builtins = zip(*builtins_dict.items())
+        program = self._cook(body, digest, names)
+
+        initialize = program['initialize']
+        functions = initialize(*builtins)
+
+        for name, function in functions.items():
+            setattr(self, "_" + name, function)
+
+        self._cooked = True
+
+        if self.keep_body:
+            self.body = body
+
+    def cook_check(self):
+        assert self._cooked
+
+    def parse(self, body):
+        raise NotImplementedError("Must be implemented by subclass.")
+
+    def render(self, **__kw):
+        econtext = Scope(__kw)
+        rcontext = {}
+        self.cook_check()
+        stream = self.output_stream_factory()
+        try:
+            self._render(stream, econtext, rcontext)
+        except:
+            cls, exc, tb = sys.exc_info()
+            errors = rcontext.get('__error__')
+            if errors:
+                formatter = exc.__str__
+                if isinstance(formatter, ExceptionFormatter):
+                    if errors is not formatter._errors:
+                        formatter._errors.extend(errors)
+                    raise
+
+                formatter = ExceptionFormatter(errors, econtext, rcontext)
+
+                try:
+                    exc = create_formatted_exception(exc, cls, formatter)
+                except TypeError:
+                    pass
+
+                raise_with_traceback(exc, tb)
+
+            raise
+
+        return join(stream)
+
+    def write(self, body):
+        if isinstance(body, byte_string):
+            body, encoding, content_type = read_bytes(
+                body, self.default_encoding
+                )
+        else:
+            content_type = body.startswith('<?xml')
+            encoding = None
+
+        self.content_type = content_type
+        self.content_encoding = encoding
+
+        self.cook(body)
+
+    def _get_module_name(self, digest):
+        return "%s.py" % digest
+
+    def _cook(self, body, digest, builtins):
+        name = self._get_module_name(digest)
+        cooked = self.loader.get(name)
+        if cooked is None:
+            try:
+                source = self._make(body, builtins)
+                if self.debug:
+                    source = "# template: %s\n#\n%s" % (self.filename, source)
+                if self.keep_source:
+                    self.source = source
+                cooked = self.loader.build(source, name)
+            except TemplateError:
+                exc = sys.exc_info()[1]
+                exc.filename = self.filename
+                raise
+        elif self.keep_source:
+            module = sys.modules.get(cooked.get('__name__'))
+            if module is not None:
+                self.source = inspect.getsource(module)
+            else:
+                self.source = None
+
+        return cooked
+
+    def _digest(self, body):
+        class_name = type(self).__name__.encode('utf-8')
+        sha = pkg_digest.copy()
+        sha.update(body.encode('utf-8', 'ignore'))
+        sha.update(class_name)
+        return sha.hexdigest()
+
+    def _compile(self, program, builtins):
+        compiler = Compiler(self.engine, program, builtins, strict=self.strict)
+        return compiler.code
+
+    def _make(self, body, builtins):
+        program = self.parse(body)
+        module = Module("initialize", program)
+        return self._compile(module, builtins)
+
+
+class BaseTemplateFile(BaseTemplate):
+    """File-based template base class.
+
+    Relative path names are supported only when a template loader is
+    provided as the ``loader`` parameter.
+    """
+
+    # Auto reload is not enabled by default because it's a significant
+    # performance hit
+    auto_reload = AUTO_RELOAD
+
+    def __init__(self, filename, auto_reload=None, **config):
+        # Normalize filename
+        filename = os.path.abspath(
+            os.path.normpath(os.path.expanduser(filename))
+            )
+
+        self.filename = filename
+
+        # Override reload setting only if value is provided explicitly
+        if auto_reload is not None:
+            self.auto_reload = auto_reload
+
+        super(BaseTemplateFile, self).__init__(**config)
+
+        if EAGER_PARSING:
+            self.cook_check()
+
+    def cook_check(self):
+        if self.auto_reload:
+            mtime = self.mtime()
+
+            if mtime != self._v_last_read:
+                self._v_last_read = mtime
+                self._cooked = False
+
+        if self._cooked is False:
+            body = self.read()
+            log.debug("cooking %r (%d bytes)..." % (self.filename, len(body)))
+            self.cook(body)
+
+    def mtime(self):
+        try:
+            return os.path.getmtime(self.filename)
+        except (IOError, OSError):
+            return 0
+
+    def read(self):
+        with open(self.filename, "rb") as f:
+            data = f.read()
+
+        body, encoding, content_type = read_bytes(
+            data, self.default_encoding
+            )
+
+        # In non-XML mode, we support various platform-specific line
+        # endings and convert them to the UNIX newline character
+        if content_type != "text/xml" and '\r' in body:
+            body = body.replace('\r\n', '\n').replace('\r', '\n')
+
+        self.content_type = content_type
+        self.content_encoding = encoding
+
+        return body
+
+    def _get_module_name(self, digest):
+        filename = os.path.basename(self.filename)
+        mangled = mangle(filename)
+        return "%s_%s.py" % (mangled, digest)
+
+    def _get_filename(self):
+        return self.__dict__.get('filename')
+
+    def _set_filename(self, filename):
+        self.__dict__['filename'] = filename
+        self._v_last_read = None
+        self._cooked = False
+
+    filename = property(_get_filename, _set_filename)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/__init__.py
@@ -0,0 +1,1 @@
+#
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-interpolation.txt
@@ -0,0 +1,1 @@
+${'<Hello world>'}<&>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.html
@@ -0,0 +1,7 @@
+<html>
+  <body py:with="text 'Hello world!'">
+    ${text}
+    $text
+  </body>
+  ${text | 'Goodbye world!'}
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001-variable-scope.pt
@@ -0,0 +1,11 @@
+<html>
+  <body tal:define="text 'Hello world!'">
+    ${text}
+  </body>
+  <tal:check condition="exists: text">
+    bad
+  </tal:check>
+  <tal:check condition="not: exists: text">
+    ok
+  </tal:check>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/001.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002-repeat-scope.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <div tal:repeat="text ('Hello', 'Goodbye')">
+      <span tal:repeat="char ('!', '.')">${text}${char}</span>
+    </div>
+    <tal:check condition="not: exists: text">ok</tal:check>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/002.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc ></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003-content.pt
@@ -0,0 +1,17 @@
+<html>
+  <body>
+    <div tal:content="'Hello world!'" />
+    <div tal:content="'Hello world!'" />1
+   2<div tal:content="'Hello world!'" />
+    <div tal:content="'Hello world!'" />3
+    <div tal:content="'Hello world!'">4</div>5
+   6<div tal:content="'Hello world!'"></div>
+    <div tal:content="1" />
+    <div tal:content="1.0" />
+    <div tal:content="True" />
+    <div tal:content="False" />
+    <div tal:content="0" />
+    <div tal:content="None" />
+    <div tal:replace="content" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/003.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc >
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004-attributes.pt
@@ -0,0 +1,18 @@
+<html>
+  <body>
+    <span tal:attributes="class 'hello'" />
+    <span class="goodbye" tal:attributes="class 'hello'" />
+    <span CLASS="goodbye" tal:attributes="class 'hello'" />
+    <span tal:attributes="class None" />
+    <span a="1" b="2" c="3" tal:attributes="a None" />
+    <span a="1" b="2" c="3" tal:attributes="b None" />
+    <span a="1" b="2" c="3" tal:attributes="c None" />
+    <span a="1" b="2" c="3" tal:attributes="b None; c None" />
+    <span a="1" b="2" c="3" tal:attributes="b string:;;" />
+    <span a="1" b="2" c="3" tal:attributes="b string:&" />
+    <span class="hello" tal:attributes="class 'goodbye'" />
+    <span class="hello" tal:attributes="class '"goodbye"'" />
+    <span class="hello" tal:attributes="class '\'goodbye\''" />
+    <span class='hello' tal:attributes="class '\'goodbye\''" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/004.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005-default.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <img class="default" tal:attributes="class default" />
+    <img tal:attributes="class default" />
+    <span tal:content="default">Default</span>
+    <span tal:content="True">Default</span>
+    <span tal:content="False">Default</span>
+    <span tal:content="default">
+      <em>${'Computed default'}</em>
+    </span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/005.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1 = "v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006-attribute-interpolation.pt
@@ -0,0 +1,9 @@
+<html>
+  <body class="ltr" tal:define="hash string:#">
+    <img src="${'#'}" alt="copyright (c) ${2010}" />
+    <img src="" alt="copyright (c) ${2010}" tal:attributes="src string:$hash" />
+    <img src="" alt="copyright (c) ${2010}" tal:attributes="src string:${hash}" />
+    <img src="${None}" alt="$ignored" />
+    <img src="" alt="${'%stype \'str\'%s' % (chr(60), chr(62))}" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/006.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1='v1'></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007-content-interpolation.pt
@@ -0,0 +1,15 @@
+<html>
+  <body>
+    ${'Hello world!'}
+    ${literal}
+    ${structure: literal.s}
+    ${"%stype 'str'%s" % (chr(60), chr(62))}
+    &&
+    ${None}
+    ${None or
+      'Hello world'}
+    $leftalone
+    <div>${None}</div>
+    <div>${1 < 2 and 'Hello world' or None}</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/007.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc> </doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008-builtins.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    ${nothing}
+    <div tal:attributes="class string:dynamic" class="static">
+      ${attrs['class']}
+    </div>
+    <div tal:define="nothing string:nothing">
+      ${nothing}
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/008.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&<>"'</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009-literals.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    ${literal}
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/009.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&#x20;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010-structure.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div tal:content="text string:1 < 2" />
+    <div tal:content="structure string:2 < 3, 2&3, 2<3, 2>3" />
+    <div tal:content="structure string:3 ${'<'} 4" />
+    <div tal:content="structure '%d < %d' % (4, 5)" />
+    <div tal:replace="structure content" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/010.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="v1" ></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011-messages.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div tal:content="text message" />
+    <div tal:content="structure message" />
+    <div tal:content="text string:${message}" />
+    <div tal:content="structure string:${message}" />
+    ${message}
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/011.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED a2 CDATA #IMPLIED>
+]>
+<doc a1="v1" a2="v2"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012-translation.pt
@@ -0,0 +1,21 @@
+<html>
+  <body>
+    <div i18n:translate="">
+      Hello world!
+    </div>
+    <div i18n:translate="hello_world">
+      Hello world!
+    </div>
+    <div i18n:translate="">
+      <sup>Hello world!</sup>
+    </div>
+    <div i18n:translate="">
+      Hello <em i18n:name="first">${'world'}</em>!
+      Goodbye <em i18n:name="second">${'planet'}</em>!
+    </div>
+    <div i18n:translate="hello_goodbye">
+      Hello <em i18n:name="first">${'world'}</em>!
+      Goodbye <em i18n:name="second">${'planet'}</em>!
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/012.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc : CDATA #IMPLIED>
+]>
+<doc :="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013-repeat-nested.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <table>
+      <tr tal:repeat="i (1,2)">
+        <td tal:repeat="j (1,2)">
+          [${i},${j}]
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/013.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc _.-0123456789 CDATA #IMPLIED>
+]>
+<doc _.-0123456789="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014-repeat-nested-similar.pt
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    <span tal:repeat="i (3,4)">
+      <span tal:repeat="j (3,4)">[${i},${j}]</span>
+    </span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/014.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc abcdefghijklmnopqrstuvwxyz CDATA #IMPLIED>
+]>
+<doc abcdefghijklmnopqrstuvwxyz="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015-translation-nested.pt
@@ -0,0 +1,10 @@
+<html>
+  <body>
+    <div i18n:translate="">
+      Price:
+      <span i18n:name="price" i18n:translate="">
+        Per kilo <em i18n:name="amount">${12.5}</em>
+      </span>
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/015.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc ABCDEFGHIJKLMNOPQRSTUVWXYZ CDATA #IMPLIED>
+]>
+<doc ABCDEFGHIJKLMNOPQRSTUVWXYZ="v1"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016-explicit-translation.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <div i18n:translate="" tal:content="string:Hello world!">
+      Hello world!
+    </div>
+    <img alt="${'Hello world!'}" i18n:attributes="alt" />
+    <img alt="${'Hello world!'}" i18n:attributes="alt hello_world" />
+    <img tal:attributes="alt 'Hello world!'" i18n:attributes="alt" />
+    <img tal:attributes="alt 'Hello world!'" i18n:attributes="alt hello_world" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/016.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi?></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017-omit-tag.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <div tal:omit-tag="">Hello world!</div>
+    <div tal:omit-tag="">1
+      Hello world!
+   2</div>3
+   4<div tal:omit-tag="True">Hello world!</div>
+    <div tal:omit-tag="False">Hello world!</div>
+    <div class="omitted" tal:omit-tag="True">Hello world!</div>
+    <div class="${'omitted'}" tal:omit-tag="True">Hello world!</div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/017.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi some data ? > <??></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018-translation-nested-dynamic.pt
@@ -0,0 +1,13 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+  <div i18n:translate="" tal:omit-tag="">
+      <span i18n:name="monthname"
+            i18n:translate=""
+            tal:content="'october'"
+            tal:omit-tag="">monthname</span>
+      <span i18n:name="year"
+            i18n:translate=""
+            tal:content="1982"
+            tal:omit-tag="">year</span>
+  </div>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/018.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<foo>]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019-replace.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    <div tal:replace="'Hello world!'" />
+    <div tal:replace="'Hello world!'" />1
+   2<div tal:replace="'Hello world!'" />
+    <div tal:replace="'Hello world!'" />3
+    <div tal:replace="'Hello world!'">4</div>5
+   6<div tal:replace="'Hello world!'"></div>
+    <div tal:replace="1" />
+    <div tal:replace="1.0" />
+    <div tal:replace="True" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/019.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<&]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020-on-error.pt
@@ -0,0 +1,10 @@
+<html>
+  <body>
+    <div id="test" tal:attributes="class python: 'abc' + 2" tal:on-error="nothing" />
+    <div tal:on-error="string:${type(error.value).__name__} thrown at ${error.lineno}:${error.offset}.">
+      <div tal:content="undefined" />
+    </div>
+    <div tal:replace="undefined" tal:on-error="nothing" />
+    <div tal:content="undefined" tal:on-error="nothing" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/020.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[<&]>]]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021-translation-domain.pt
@@ -0,0 +1,16 @@
+<html>
+  <body i18n:domain="old">
+    <div i18n:domain="new" i18n:translate="">
+      Hello world!
+    </div>
+    <div i18n:translate="">
+      Hello world!
+    </div>
+    <div class="test" i18n:domain="new" i18n:attributes="class">
+      Hello world!
+    </div>
+    <div class="test" i18n:domain="new" i18n:attributes="class test_msgid">
+      Hello world!
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/021.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><!-- a comment --></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022-switch.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    <div tal:switch="True">
+      <span tal:case="False">bad</span>
+      <span tal:case="True">ok</span>
+      <span tal:case="not not True">ok</span>
+    </div>
+    <div tal:switch="True">
+      <span tal:case="False">bad</span>
+      <span tal:case="default">ok</span>
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/022.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><!-- a comment ->--></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023-condition.pt
@@ -0,0 +1,6 @@
+<html>
+  <body tal:condition="True">
+    <span tal:define="selector False" tal:condition="selector">bad</span>
+    <span tal:condition="True">ok</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/023.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024-namespace-elements.pt
@@ -0,0 +1,16 @@
+<html>
+  <body>
+    <tal:first>
+      <tal:second>
+        ${'first'}
+      </tal:second>
+      second
+    </tal:first>
+    <tal:block condition="True">
+      ok
+    </tal:block>
+    <tal:block condition="False">
+      bad
+    </tal:block>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/024.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo)>
+<!ELEMENT foo (#PCDATA)>
+<!ENTITY e "<foo></foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025-repeat-whitespace.pt
@@ -0,0 +1,14 @@
+<html>
+  <body>
+    <ul>
+      <tal:item repeat="i (1, 2, 3)"><li tal:content="i" /></tal:item>
+      <span tal:omit-tag="" tal:repeat="j (1, 2, 3)"><li tal:content="j" /></span>
+      <tal:count>
+        <tal:count-loop repeat="count (1, 2, 3)">
+          <span tal:replace="count"
+                /><tal:comma condition="not repeat['count'].end">,</tal:comma>
+       </tal:count-loop>
+      </tal:count>.
+    </ul>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/025.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo (#PCDATA)>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026-repeat-variable.pt
@@ -0,0 +1,13 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <ul>
+    <li tal:attributes="class repeat['i'].even()+repeat['i'].odd()" name="${i}-${repeat.i.index}" tal:repeat="i range(3)"><span tal:replace="i" /></li>
+  </ul>
+  <ul>
+    <li tal:attributes="class repeat['i'].even+repeat['i'].odd"
+        tal:repeat="i range(3)"><span tal:replace="i" /></li>
+  </ul>
+  <ul>
+    <li tal:repeat="i range(3)"><span tal:condition="repeat['i'].even" tal:replace="repeat['i'].even" /><span tal:condition="repeat['i'].odd" tal:replace="repeat['i'].odd" /></li>
+  </ul>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/026.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo EMPTY>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027-attribute-replacement.pt
@@ -0,0 +1,11 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <span id="test"
+        class="dummy"
+        onClick=""
+        tal:define="a 'abc'"
+        tal:attributes="class 'def' + a + default; style 'hij'; onClick 'alert();;'"
+        tal:content="a + 'ghi'" />
+  <span tal:replace="'Hello World!'">Hello <b>Universe</b>!</span>
+  <span tal:replace="'Hello World!'"><b>Hello Universe!</b></span>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/027.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (foo*)>
+<!ELEMENT foo ANY>
+]>
+<doc><foo/><foo></foo></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028-attribute-toggle.pt
@@ -0,0 +1,6 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <option tal:attributes="selected True"></option>
+  <option tal:attributes="selected False"></option>
+  <option tal:attributes="selected None"></option>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/028.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029-attribute-ordering.pt
@@ -0,0 +1,5 @@
+<div xmlns="http://www.w3.org/1999/xhtml"
+     xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <a rel="self" href="http://repoze.org" id="link-id"
+     tal:attributes="href 'http://python.org'" />
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/029.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030-repeat-tuples.pt
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    <div tal:repeat="(i, j) ((1, 2), (3, 4))">
+      ${repeat['i', 'j'].number}, ${i}, ${j}
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/030.xml
@@ -0,0 +1,5 @@
+<?xml version = "1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031-namespace-with-tal.pt
@@ -0,0 +1,7 @@
+<div>
+  <tal:example replace="'Hello World!'" />
+  <tal:example tal:replace="'Hello World!'" />
+  <tal:div content="'Hello World!'" />
+  <tal:multiple repeat="i range(3)" replace="i" />
+  <tal:div condition="True">True</tal:div>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/031.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032-master-template.pt
@@ -0,0 +1,20 @@
+<html i18n:domain="master" metal:define-macro="main" tal:define="content nothing">
+  <head>
+    <title metal:define-slot="title"
+           metal:define-macro="title"
+           tal:define="has_title exists: title"
+           tal:content="title if has_title else default">Master template</title>
+  </head>
+  <body>
+    <div id="content">
+      <metal:content define-slot="content">
+        <!-- content here -->
+      </metal:content>
+    </div>
+    <div id="footer">
+      <metal:footer define-slot="body-footer" tal:content="nothing">
+        <!-- footer here -->
+      </metal:footer>
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/032.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' standalone='yes'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033-use-macro-trivial.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/033.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding="UTF-8" standalone='yes'?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034-use-template-as-macro.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load('032-master-template.pt')" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/034.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc/>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035-use-macro-with-fill-slot.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+  <title metal:fill-slot="title" tal:define="kind 'New'">
+    ${kind} title
+  </title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/035.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036-use-macro-inherits-dynamic-scope.pt
@@ -0,0 +1,2 @@
+<html tal:define="title string:New title"
+      metal:use-macro="load('032-master-template.pt').macros['main']" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/036.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+<?pi data?>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037-use-macro-local-variable-scope.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']" >
+  <metal:content metal:fill-slot="content">
+    <span tal:condition="content is None">ok</span>
+  </metal:content>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/037.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+<!-- comment -->
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038-use-macro-globals.pt
@@ -0,0 +1,6 @@
+<metal:globals use-macro="load('039-globals.pt')"  />
+<html>
+  <body>
+    <span tal:condition="content is None">ok</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/038.xml
@@ -0,0 +1,6 @@
+<!-- comment -->
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039-globals.pt
@@ -0,0 +1,1 @@
+<tal:globals define="global content None" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/039.xml
@@ -0,0 +1,5 @@
+<?pi data?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040-macro-using-template-symbol.pt
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<!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:tal="http://xml.zope.org/namespaces/tal"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      metal:define-macro="master"
+      template-macros="${' '.join(template.macros.names)}"
+      macros="${' '.join(macros.names)}">
+    <metal:block tal:define="foo 'foo'">
+      ${foo}
+      <div metal:define-slot="content" tal:replace="None">
+         <!-- will be replaced -->
+      </div>
+      <span template-macros="${' '.join(template.macros.names)}"
+            macros="${' '.join(macros.names)}">
+         <!-- demonstrate difference between
+              `template` and `macros` symbol -->
+      </span>
+    </metal:block>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/040.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1=""<&>'"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041-translate-nested-names.pt
@@ -0,0 +1,22 @@
+<html>
+  <body>
+    <div i18n:translate="">
+      Hello
+      <tal:nested condition="True">
+        <span i18n:name="world">world!</span>
+      </tal:nested>
+    </div>
+    <div i18n:translate="hello">
+      Hello
+      <tal:nested condition="True">
+        <span i18n:name="world">world!</span>
+      </tal:nested>
+    </div>
+    <div i18n:translate="">
+      Goodbye
+      <tal:nested condition="False">
+        <span i18n:name="world">world!</span>
+      </tal:nested>
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/041.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+]>
+<doc a1="A"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042-use-macro-fill-footer.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+  <metal:footer fill-slot="body-footer">New footer</metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/042.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>A</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043-macro-nested-dynamic-vars.pt
@@ -0,0 +1,19 @@
+<html>
+  <body>
+    <tal:macros condition="0">
+
+      <metal:outer define-macro="outer">
+        <metal:inner use-macro="template.macros['inner']" />
+      </metal:outer>
+
+      <metal:inner define-macro="inner">
+        ${title}
+      </metal:inner>
+
+    </tal:macros>
+
+    <div tal:define="title string:My title"
+         metal:use-macro="template.macros['outer']"
+         />
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/043.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1="foo
+bar"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044-tuple-define.pt
@@ -0,0 +1,5 @@
+<html>
+  <body tal:define="(a, b) 'a', 'b'">
+    ${a}, ${b}
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/044.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (e*)>
+<!ELEMENT e EMPTY>
+<!ATTLIST e a1 CDATA "v1" a2 CDATA "v2" a3 CDATA #IMPLIED>
+]>
+<doc>
+<e a3="v3"/>
+<e a1="w1"/>
+<e a2="w2" a3="v3"/>
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045-namespaces.pt
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE application [
+  <!ENTITY nbsp "\ ">
+]>
+<application xmlns="http://research.sun.com/wadl/2006/10"
+             xsi:schemaLocation="http://research.sun.com/wadl/2006/10/wadl.xsd"
+             xmlns:wadl="http://research.sun.com/wadl/2006/10"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xmlns:tal="http://xml.zope.org/namespaces/tal">
+  <resources tal:define="path '/'">
+    <resource path="${path}">ZZZ YYY XXX</resource>
+  </resources>
+</application>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/045.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "v1">
+<!ATTLIST doc a1 CDATA "z1">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046-extend-macro.pt
@@ -0,0 +1,6 @@
+<html metal:define-macro="extended"
+      metal:extend-macro="load('032-master-template.pt').macros['main']">
+  <metal:footer fill-slot="body-footer">
+    <span metal:define-slot="kind">New</span> footer
+  </metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/046.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "v1">
+<!ATTLIST doc a2 CDATA "v2">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047-use-extended-macro.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('046-extend-macro.pt').macros['extended']">
+  <em metal:fill-slot="kind">Extended</em>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/047.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>X
+Y</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048-use-extended-macro-fill-original.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('046-extend-macro.pt').macros['extended']">
+  <metal:footer fill-slot="body-footer">
+    Extended footer
+  </metal:footer>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/048.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049-entities-in-attributes.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <pre tal:content="string:amp=&amp; lt=&lt;"  />
+    <pre tal:content="structure string:amp=&amp; lt=&lt;"  />
+    <script tal:replace="structure string:<script />" />
+    <script tal:replace="string:<script />" />
+    <script tal:replace="string:${'<'}script /${'>'}" />
+    <script tal:replace="structure string:${'<'}script /${'>'}" />
+    <img alt="1 < 2: ${1 < 2}" />
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/049.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c3cc797b5954881cc794f6720674a8bfa13aacbe
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050-define-macro-and-use-not-extend.pt
@@ -0,0 +1,6 @@
+<html metal:define-macro="main"
+      metal:use-macro="load('032-master-template.pt').macros['main']">
+  <metal:content fill-slot="content">
+     Default content
+  </metal:content>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/050.xml
new file mode 100644
index 0000000000000000000000000000000000000000..12303b1af2185eb29894629b99431fea831367b1
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051-use-non-extended-macro.pt
@@ -0,0 +1,5 @@
+<html metal:use-macro="load('050-define-macro-and-use-not-extend.pt').macros['main']">
+  <metal:content fill-slot="content">
+    <span>Filled content</span>
+  </metal:content>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/051.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7ae8f6c73a4b47ec18492ebefed16c63f5f5ef22
GIT binary patch
[stripped]
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052-i18n-domain-inside-filled-slot.pt
@@ -0,0 +1,8 @@
+<html metal:define-macro="main"
+      metal:use-macro="load('032-master-template.pt').macros['main']">
+  <metal:content fill-slot="content">
+    <span i18n:domain="mydomain" i18n:translate="">
+       Translated content
+    </span>
+  </metal:content>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/052.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>𐀀􏿽</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053-special-characters-in-attributes.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <a tal:attributes="href string:@@view">test</a>
+    <a href="${'@@'}view">test</a>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/053.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY e "<e/>">
+<!ELEMENT doc (e)>
+<!ELEMENT e EMPTY>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054-import-expression.pt
@@ -0,0 +1,3 @@
+<div tal:define="datetime import: datetime.datetime">
+  ${datetime(1984, 12, 31).isoformat()}
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/054.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+
+
+<doc
+></doc
+>
+
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055-attribute-fallback-to-dict-lookup.pt
@@ -0,0 +1,4 @@
+<div tal:define="obj {'foo': 'bar', 'boo': {'bar': 'baz'}}">
+  ${obj.foo}
+  ${obj.boo.bar}
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/055.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<?pi  data?>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056-comment-attribute.pt
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    <tal:first comment="ignored">
+      Namespace tag
+    </tal:first>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/056.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&#x0000000000000000000000000000000000000041;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057-order.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <div tal:condition="False" tal:repeat="item bad_input" />
+    <div tal:define="sequence 1, 2, 3"
+         tal:repeat="item sequence"
+         tal:replace="item" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/057.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a*)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058-script.pt
@@ -0,0 +1,16 @@
+<html>
+  <head>
+    <script tal:define="field {'oid': 1}; values 'values'; options 'options'">
+      deform.addCallback(
+        '${field.oid}',
+        function (oid) {
+            $('#' + oid).autocomplete({source: ${values}});
+            $('#' + oid).autocomplete("option", ${options});
+        }
+      );
+    </script>
+  </head>
+  <body>
+    <!-- Form -->
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/058.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1=" 1  	2 	"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059-embedded-javascript.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <span onclick="alert(true && false);">test</span>
+    <span onclick="alert(${str(True).lower()} && ${str(False).lower()});">test</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/059.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (e*)>
+<!ELEMENT e EMPTY>
+<!ATTLIST e a1 CDATA #IMPLIED a2 CDATA #IMPLIED a3 CDATA #IMPLIED>
+]>
+<doc>
+<e a1="v1" a2="v2" a3="v3"/>
+<e a1="w1" a2="v2"/>
+<e a1="v1" a2="w2" a3="v3"/>
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060-macro-with-multiple-same-slots.pt
@@ -0,0 +1,8 @@
+<html metal:define-macro="main">
+  <head>
+    <title><metal:title define-slot="title">Untitled</metal:title></title>
+  </head>
+  <body>
+    <h1><metal:title define-slot="title">Untitled</metal:title></h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/060.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>X
Y</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061-fill-one-slot-but-two-defined.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('060-macro-with-multiple-same-slots.pt').macros['main']">
+  <metal:title fill-slot="title">My document</metal:title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/061.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>£</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062-comments-and-expressions.pt
@@ -0,0 +1,27 @@
+<div>
+  <!--! ${dropped} -->
+</div>
+
+<div>
+  <!--? ${left alone} -->
+</div>
+
+<div>
+  <!-- ${'not left alone'} -->
+</div>
+
+<div meta:interpolation="true">
+  <!-- ${'not left alone'} -->
+</div>
+
+<div meta:interpolation="false">
+  <!-- ${left alone} -->
+</div>
+
+<!--[if IE ${6}]>
+  Special instructions for IE 6 here
+<![endif]-->
+
+<!--?[if IE 6]>
+  ${left alone}
+<![endif]-->
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/062.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&#xe40;&#xe08;&#xe21;ส์</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063-continuation.pt
@@ -0,0 +1,4 @@
+<div tal:define="foo 1 + \
+                     1">
+  ${foo}
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/063.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE เจมส์ [
+<!ELEMENT เจมส์ (#PCDATA)>
+]>
+<เจมส์></เจมส์>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064-tags-and-special-characters.pt
@@ -0,0 +1,4 @@
+<tal:block>
+  <div	id="test"	class="${'test'}">
+  </div>
+</tal:block>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/064.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&#x10000;&#x10FFFD;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065-use-macro-in-fill.pt
@@ -0,0 +1,6 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+  <title tal:define="title string:Title"
+         metal:fill-slot="title"
+         metal:use-macro="load('032-master-template.pt').macros['title']" />
+  <div metal:fill-slot="content">Content</div>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/065.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e "<">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066-load-expression.pt
@@ -0,0 +1,1 @@
+<html tal:define="hello_world load: hello_world.pt" metal:use-macro="hello_world" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/066.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!-- 34 is double quote -->
+<!ENTITY e1 """>
+]>
+<doc a1="&e1;"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067-attribute-decode.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <img src="#" tal:attributes="class 1 > 0 and 'up' or 0 < 1 and 'down';" />
+    <img src="#" tal:attributes="class 0 > 1 and 'up' or 0 < 1 and 'down';" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/067.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>
</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068-less-than-greater-than-in-attributes.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <span tal:content="string:0 < 1 or 0 > 1" />
+    <span tal:content="structure string:0 < 1 or 0 > 1" />
+    <span class="0 < 1 or 0 > 1" />
+    <span>0 < 1 or 0 > 1</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/068.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069-translation-domain-and-macro.pt
@@ -0,0 +1,3 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+  <title metal:fill-slot="title" i18n:domain="test" i18n:translate="title">Title</title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/069.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!NOTATION n PUBLIC "whatever">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070-translation-domain-and-use-macro.pt
@@ -0,0 +1,3 @@
+<html i18n:domain="test" metal:use-macro="load('032-master-template.pt').macros['main']">
+  <title metal:fill-slot="title" i18n:translate="title">Title</title>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/070.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e "<!ELEMENT doc (#PCDATA)>">
+%e;
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071-html-attribute-defaults.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <input type="input" tal:attributes="checked True" />
+    <input type="input" tal:attributes="checked False" />
+    <input type="input" tal:attributes="checked None" />
+    <input type="input" checked="checked" tal:attributes="checked default" />
+    <input type="input" checked tal:attributes="checked default" />
+    <input type="input" tal:attributes="checked default" />
+    <input type="input" class="field" tal:attributes="class True" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/071.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ID #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072-repeat-interpolation.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    <ul>
+      <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else default}">${i}</li>
+    </ul>
+    <ul>
+      <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else None}">${i}</li>
+    </ul>
+    <ul>
+      <li tal:repeat="i range(1, 4)" class="${'odd' if i % 2 != 0 else False}">${i}</li>
+    </ul>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/072.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a IDREF #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073-utf8-encoded.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>${'my title'} — ${'my site'}</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/073.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a IDREFS #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074-encoded-template.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="windows-1251" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>${'my title'} — ${'my site'}</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/074.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITY #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075-nested-macros.pt
@@ -0,0 +1,11 @@
+<metal:page define-macro="master">
+  <tal:block metal:use-macro="load('032-master-template.pt').macros['main']">
+
+    <metal:block fill-slot="content">
+      <metal:override define-slot="content">
+        foo
+      </metal:override>
+    </metal:block>
+
+  </tal:block>
+</metal:page>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/075.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITIES #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076-nested-macro-override.pt
@@ -0,0 +1,3 @@
+<metal:page use-macro="load('075-nested-macros.pt').macros['master']">
+  <metal:block fill-slot="content">bar</metal:block>
+</metal:page>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/076.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a NOTATION (n1|n2) #IMPLIED>
+<!NOTATION n1 SYSTEM "http://www.w3.org/">
+<!NOTATION n2 SYSTEM "http://www.w3.org/">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077-i18n-attributes.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" i18n:domain="test" i18n:attributes="value Title" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/077.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a (1|2) #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078-tags-and-newlines.pt
@@ -0,0 +1,23 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+      tal:omit-tag=""
+      tal:define="id 'foo'">
+  <body>
+      <span id="toDataContainer"
+            tal:attributes="id string:${id}-toDataContainer">
+        <script type="text/javascript" tal:content="string:
+          copyDataForSubmit('${id}');">
+          // initial copying of field "field.to" --> "field"
+          copyDataForSubmit("<i tal:replace="${id}"/>");
+        </script>
+      </span>
+      <tal:block
+    repeat="value python: (1, 2, 3)"
+    ><span class="selected-option"
+           tal:content="value"
+    /><tal:block condition="not:repeat.value.end">, </tal:block
+  ></tal:block
+>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/078.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #REQUIRED>
+]>
+<doc a="v"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079-implicit-i18n.pt
@@ -0,0 +1,16 @@
+<html tal:define="request dict(site_url='http://host')">
+  <head>
+    <title>Welcome</title>
+  </head>
+  <body>
+    <h1>Welcome</h1>
+    <span>An edge case: ${.</span>
+    <img tal:define="site_url request.site_url" alt="Site logo" href="${site_url}/logo.png" />
+    <img alt="Site logo" href="${request.site_url}/logo.png" />
+    <div id="content">
+      foo.
+      <br />
+      bar.
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/079.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #FIXED "v">
+]>
+<doc a="v"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080-xmlns-namespace-on-tal.pt
@@ -0,0 +1,6 @@
+<tal:component xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal">
+   Hello world
+</tal:component>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/080.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #FIXED "v">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081-load-spec.pt
@@ -0,0 +1,1 @@
+<html metal:use-macro="load: chameleon:tests/inputs/hello_world.pt" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/081.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a, b, c)>
+<!ELEMENT a (a?)>
+<!ELEMENT b (b*)>
+<!ELEMENT c (a | b)+>
+]>
+<doc><a/><b/><c><a/></c></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082-load-spec-computed.pt
@@ -0,0 +1,1 @@
+<html tal:define="name 'hello_world'" metal:use-macro="load: chameleon:tests/inputs/${name}.pt" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/082.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e SYSTEM "e.dtd">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083-template-dict-to-macro.pt
@@ -0,0 +1,2 @@
+<html tal:define="template load: 032-master-template.pt"
+      metal:use-macro="template['main']" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/083.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY % e PUBLIC 'whatever' "e.dtd">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084-interpolation-in-cdata.pt
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <script>
+      <![CDATA[
+      alert("${'Hello world!'}");
+      ]]>
+    </script>
+  </head>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/084.xml
@@ -0,0 +1,1 @@
+<!DOCTYPE doc [<!ELEMENT doc (#PCDATA)>]><doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085-nested-translation.pt
@@ -0,0 +1,11 @@
+<html tal:define="request dict(site_url='http://host')" i18n:domain="new">
+  <head>
+    <title>Welcome</title>
+  </head>
+  <body>
+    <h1>Welcome</h1>
+    <p i18n:translate="">
+      <a i18n:name="click_here" i18n:translate="" href="${request.site_url}">Click here</a> to continue.
+    </p>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/085.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY % e "<foo>">
+<!ENTITY e "">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086-self-closing.pt
@@ -0,0 +1,10 @@
+<html metal:use-macro="load('032-master-template.pt').macros['main']">
+  <body>
+    <div metal:fill-slot="content">
+      <div tal:condition="True">
+        <a href="#">Chart</a>
+        <div id="chart-info"/>
+      </div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/086.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "">
+<!ENTITY e "<foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087-code-blocks.pt
@@ -0,0 +1,28 @@
+<?python
+    foo = [1, 2, 3] ?>
+
+<ul>
+  <li tal:repeat="f foo" tal:content="f" />
+</ul>
+
+<?python
+    foo = [1, 2, 3]
+    boo = [4, 5, 6]
+?>
+
+<ul>
+  <li tal:repeat="(f, g) zip(foo, boo)" tal:content="f + g" />
+</ul>
+
+<div>
+  <?python numbers = map(str, range(1, 10)) ?>
+  Please input a number from the range ${", ".join(numbers)}.
+</div>
+
+<div>
+  <?python
+     def function(i):
+         return i + 1
+     ?>
+  41 + 1 = ${function(41)}.
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/087.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY e "<foo/>">
+<!ELEMENT doc (foo)>
+<!ELEMENT foo EMPTY>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088-python-newlines.pt
@@ -0,0 +1,2 @@
+<span tal:replace="python: ', '.join((
+    'a', 'b', 'c'))" />
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/088.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "<foo>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/089.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e "&#x10000;&#x10FFFD;&#x10FFFF;">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/090.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ATTLIST e a NOTATION (n) #IMPLIED>
+<!ELEMENT doc (e)*>
+<!ELEMENT e (#PCDATA)>
+<!NOTATION n PUBLIC "whatever">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/091.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!NOTATION n SYSTEM "http://www.w3.org/">
+<!ENTITY e SYSTEM "http://www.w3.org/" NDATA n>
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a ENTITY "e">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/092.xml
@@ -0,0 +1,10 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a)*>
+<!ELEMENT a EMPTY>
+]>
+<doc>
+<a/>
+    <a/>	<a/>
+
+
+</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/093.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc>
+

</doc>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/094.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ENTITY % e "foo">
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a1 CDATA "%e;">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/095.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 CDATA #IMPLIED>
+<!ATTLIST doc a1 NMTOKENS #IMPLIED>
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc a1="1  2"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/096.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS " 1  	2 	">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/097.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY % e SYSTEM "097.ent">
+<!ATTLIST doc a1 CDATA "v1">
+%e;
+<!ATTLIST doc a2 CDATA "v2">
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/098.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><?pi x
+y?></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/099.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/100.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ENTITY e PUBLIC ";!*#@$_%" "100.xml">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101-unclosed-tags.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <h1><br><br>Hello world</h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/101.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e """>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102-unquoted-attributes.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <h1 class=title align=center>Hello world</h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/102.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="""></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103-simple-attribute.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <select name="foo2" multiple style="visibility: hidden">
+      <option value="1">this should</option>
+      <option value="2">remain hidden right?</option>
+    </select>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/103.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/104.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x	y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/105.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x	y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/106.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x
y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/107.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x
y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/108.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
+">
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x&e;y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/109.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a=""></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/110.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "
">
+<!ATTLIST doc a CDATA #IMPLIED>
+]>
+<doc a="x&e;y"></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/111.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST doc a NMTOKENS #IMPLIED>
+]>
+<doc a=" x  y "></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/112.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (a | b)>
+<!ELEMENT a (#PCDATA)>
+]>
+<doc><a></a></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/113.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ATTLIST e a CDATA #IMPLIED>
+]>
+<doc></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/114.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e "<![CDATA[&foo;]]>">
+]>
+<doc>&e;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/115.xml
@@ -0,0 +1,6 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY e1 "&e2;">
+<!ENTITY e2 "v">
+]>
+<doc>&e1;</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/116.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc><![CDATA[
+]]></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/117.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY rsqb "]">
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/118.xml
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (#PCDATA)>
+<!ENTITY rsqb "]]">
+]>
+<doc>]</doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/119.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+<!ELEMENT doc ANY>
+]>
+<doc><!-- -á --></doc>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/greeting.pt
@@ -0,0 +1,1 @@
+<div>Hello, ${name | 'undefined'}.</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    ${'Hello world!'}
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/inputs/hello_world.txt
@@ -0,0 +1,1 @@
+${'Hello world!'}
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.html
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    Hello world!
+    Hello world!
+  </body>
+  Goodbye world!
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    Hello world!
+  </body>
+
+
+    ok
+
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/001.txt
@@ -0,0 +1,1 @@
+<Hello world><&>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/002.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    <div>
+      <span>Hello!</span>
+      <span>Hello.</span>
+    </div>
+    <div>
+      <span>Goodbye!</span>
+      <span>Goodbye.</span>
+    </div>
+    ok
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/003.pt
@@ -0,0 +1,17 @@
+<html>
+  <body>
+    <div>Hello world!</div>
+    <div>Hello world!</div>1
+   2<div>Hello world!</div>
+    <div>Hello world!</div>3
+    <div>Hello world!</div>5
+   6<div>Hello world!</div>
+    <div>1</div>
+    <div>1.0</div>
+    <div>True</div>
+    <div>False</div>
+    <div>0</div>
+    <div></div>
+    <div>Hello world!</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/004.pt
@@ -0,0 +1,18 @@
+<html>
+  <body>
+    <span class="hello" />
+    <span class="hello" />
+    <span class="hello" />
+    <span />
+    <span b="2" c="3" />
+    <span a="1" c="3" />
+    <span a="1" b="2" />
+    <span a="1" />
+    <span a="1" b=";" c="3" />
+    <span a="1" b="&" c="3" />
+    <span class="goodbye" />
+    <span class=""goodbye"" />
+    <span class="'goodbye'" />
+    <span class=''goodbye'' />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/005.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <img class="default" />
+    <img />
+    <span>Default</span>
+    <span>True</span>
+    <span>False</span>
+    <span>
+      <em>Computed default</em>
+    </span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/006.pt
@@ -0,0 +1,9 @@
+<html>
+  <body class="ltr">
+    <img src="#" alt="copyright (c) 2010" />
+    <img src="#" alt="copyright (c) 2010" />
+    <img src="#" alt="copyright (c) 2010" />
+    <img alt="$ignored" />
+    <img src="" alt="<type 'str'>" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/007.pt
@@ -0,0 +1,14 @@
+<html>
+  <body>
+    Hello world!
+    <div>Hello world!</div>
+    <div>Hello world!</div>
+    <type 'str'>
+    &&
+
+    Hello world
+    $leftalone
+    <div></div>
+    <div>Hello world</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/008.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+
+    <div class="dynamic">
+      static
+    </div>
+    <div>
+      nothing
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/009.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <div>Hello world!</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/010.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>1 < 2</div>
+    <div>2 < 3, 2&3, 2<3, 2>3</div>
+    <div>3 < 4</div>
+    <div>4 < 5</div>
+    <div>Hello world!</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011-en.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Message ('message' translation into 'en')</div>
+    <div>Message ('message' translation into 'en')</div>
+    <div>Message ('message' translation into 'en')</div>
+    <div>Message ('message' translation into 'en')</div>
+    Message ('message' translation into 'en')
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/011.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Message</div>
+    <div>Message</div>
+    <div>Message</div>
+    <div>Message</div>
+    Message
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012-en.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Hello world! ('Hello world!' translation into 'en')</div>
+    <div>Hello world! ('hello_world' translation into 'en')</div>
+    <div><sup>Hello world!</sup> ('<sup>Hello world!</sup>' translation into 'en')</div>
+    <div>Hello <em>world</em>! Goodbye <em>planet</em>! ('Hello ${first}! Goodbye ${second}!' translation into 'en')</div>
+    <div>Hello <em>world</em>! Goodbye <em>planet</em>! ('hello_goodbye' translation into 'en')</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/012.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Hello world!</div>
+    <div>Hello world!</div>
+    <div><sup>Hello world!</sup></div>
+    <div>Hello <em>world</em>! Goodbye <em>planet</em>!</div>
+    <div>Hello <em>world</em>! Goodbye <em>planet</em>!</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/013.pt
@@ -0,0 +1,22 @@
+<html>
+  <body>
+    <table>
+      <tr>
+        <td>
+          [1,1]
+        </td>
+        <td>
+          [1,2]
+        </td>
+      </tr>
+      <tr>
+        <td>
+          [2,1]
+        </td>
+        <td>
+          [2,2]
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/014.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <span>
+      <span>[3,3]</span>
+      <span>[3,4]</span>
+    </span>
+    <span>
+      <span>[4,3]</span>
+      <span>[4,4]</span>
+    </span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015-en.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <div>Price: <span>Per kilo <em>12.5</em> ('Per kilo ${amount}' translation into 'en')</span> ('Price: ${price}' translation into 'en')</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/015.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <div>Price: <span>Per kilo <em>12.5</em></span></div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016-en.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Hello world! ('Hello world!' translation into 'en')</div>
+    <img alt="Hello world! ('Hello world!' translation into 'en')" />
+    <img alt="Hello world! ('hello_world' translation into 'en')" />
+    <img alt="Hello world! ('Hello world!' translation into 'en')" />
+    <img alt="Hello world! ('hello_world' translation into 'en')" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/016.pt
@@ -0,0 +1,9 @@
+<html>
+  <body>
+    <div>Hello world!</div>
+    <img alt="Hello world!" />
+    <img alt="Hello world!" />
+    <img alt="Hello world!" />
+    <img alt="Hello world!" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/017.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    Hello world!
+    1
+      Hello world!
+   23
+   4Hello world!
+    <div>Hello world!</div>
+    Hello world!
+    Hello world!
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018-en.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  october ('october' translation into 'en') 1982 ('1982' translation into 'en') ('${monthname} ${year}' translation into 'en')
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/018.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  october 1982
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/019.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    Hello world!
+    Hello world!1
+   2Hello world!
+    Hello world!3
+    Hello world!5
+   6Hello world!
+    1
+    1.0
+    True
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/020.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <div id="test"></div>
+    <div>NameError thrown at 5:24.</div>
+    <div></div>
+    <div></div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021-en.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <div>Hello world! ('Hello world!' translation into 'en' with domain 'new')</div>
+    <div>Hello world! ('Hello world!' translation into 'en' with domain 'old')</div>
+    <div class="test ('test' translation into 'en' with domain 'new')">
+      Hello world!
+    </div>
+    <div class="test ('test_msgid' translation into 'en' with domain 'new')">
+      Hello world!
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/021.pt
@@ -0,0 +1,12 @@
+<html>
+  <body>
+    <div>Hello world!</div>
+    <div>Hello world!</div>
+    <div class="test">
+      Hello world!
+    </div>
+    <div class="test">
+      Hello world!
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/022.pt
@@ -0,0 +1,13 @@
+<html>
+  <body>
+    <div>
+
+      <span>ok</span>
+      <span>ok</span>
+    </div>
+    <div>
+
+      <span>ok</span>
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/023.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+
+    <span>ok</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/024.pt
@@ -0,0 +1,14 @@
+<html>
+  <body>
+
+
+        first
+
+      second
+
+
+      ok
+
+
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/025.pt
@@ -0,0 +1,23 @@
+<html>
+  <body>
+    <ul>
+      <li>1</li>
+      <li>2</li>
+      <li>3</li>
+      <li>1</li>
+      <li>2</li>
+      <li>3</li>
+
+
+          1,
+
+
+          2,
+
+
+          3
+
+      .
+    </ul>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/026.pt
@@ -0,0 +1,17 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  <ul>
+    <li name="0-0" class="even">0</li>
+    <li name="1-1" class="odd">1</li>
+    <li name="2-2" class="even">2</li>
+  </ul>
+  <ul>
+    <li class="even">0</li>
+    <li class="odd">1</li>
+    <li class="even">2</li>
+  </ul>
+  <ul>
+    <li>even</li>
+    <li>odd</li>
+    <li>even</li>
+  </ul>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/027.pt
@@ -0,0 +1,7 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  <span id="test"
+        class="defabcdummy"
+        onClick="alert();" style="hij">abcghi</span>
+  Hello World!
+  Hello World!
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/028.pt
@@ -0,0 +1,5 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  <option selected="True"></option>
+  <option></option>
+  <option></option>
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/029.pt
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+  <a rel="self" href="http://python.org" id="link-id" />
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/030.pt
@@ -0,0 +1,10 @@
+<html>
+  <body>
+    <div>
+      1, 1, 2
+    </div>
+    <div>
+      2, 3, 4
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/031.pt
@@ -0,0 +1,9 @@
+<div>
+  Hello World!
+  Hello World!
+  Hello World!
+  0
+  1
+  2
+  True
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/032.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/033.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/034.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/035.pt
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>
+    New title
+  </title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/036.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>New title</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/037.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+    <span>ok</span>
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/038.pt
@@ -0,0 +1,6 @@
+
+<html>
+  <body>
+    <span>ok</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/039.pt
new file mode 100644
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/040.pt
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<!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"
+      template-macros="master"
+      macros="master">
+
+      foo
+
+      <span template-macros="master"
+            macros="master">
+         <!-- demonstrate difference between
+              `template` and `macros` symbol -->
+      </span>
+
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/041.pt
@@ -0,0 +1,7 @@
+<html>
+  <body>
+    <div>Hello <span>world!</span></div>
+    <div>Hello <span>world!</span></div>
+    <div>Goodbye</div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/042.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+      New footer
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/043.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+
+
+
+
+        My title
+
+
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/044.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    a, b
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/045.pt
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE application [
+  <!ENTITY nbsp "\ ">
+]>
+<application xmlns="http://research.sun.com/wadl/2006/10"
+             xsi:schemaLocation="http://research.sun.com/wadl/2006/10/wadl.xsd"
+             xmlns:wadl="http://research.sun.com/wadl/2006/10"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <resources>
+    <resource path="/">ZZZ YYY XXX</resource>
+  </resources>
+</application>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/046.pt
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    <span>New</span> footer
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/047.pt
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    <em>Extended</em> footer
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/048.pt
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    Extended footer
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/049.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <pre>amp=&amp; lt=&lt;</pre>
+    <pre>amp=& lt=<</pre>
+    <script />
+    <script />
+    <script />
+    <script />
+    <img alt="1 < 2: True" />
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/050.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+     Default content
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/051.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+     Default content
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/052.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+    <span>Translated content</span>
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/053.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <a href="@@view">test</a>
+    <a href="@@view">test</a>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/054.pt
@@ -0,0 +1,3 @@
+<div>
+  1984-12-31T00:00:00
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/055.pt
@@ -0,0 +1,4 @@
+<div>
+  bar
+  baz
+</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/056.pt
@@ -0,0 +1,7 @@
+<html>
+  <body>
+
+      Namespace tag
+
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/057.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+
+    1
+    2
+    3
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/058.pt
@@ -0,0 +1,16 @@
+<html>
+  <head>
+    <script>
+      deform.addCallback(
+        '1',
+        function (oid) {
+            $('#' + oid).autocomplete({source: values});
+            $('#' + oid).autocomplete("option", options);
+        }
+      );
+    </script>
+  </head>
+  <body>
+    <!-- Form -->
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/059.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <span onclick="alert(true && false);">test</span>
+    <span onclick="alert(true && false);">test</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/060.pt
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>Untitled</title>
+  </head>
+  <body>
+    <h1>Untitled</h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/061.pt
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>My document</title>
+  </head>
+  <body>
+    <h1>My document</h1>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/062.pt
@@ -0,0 +1,27 @@
+<div>
+
+</div>
+
+<div>
+  <!-- ${left alone} -->
+</div>
+
+<div>
+  <!-- not left alone -->
+</div>
+
+<div>
+  <!-- not left alone -->
+</div>
+
+<div>
+  <!-- ${left alone} -->
+</div>
+
+<!--[if IE 6]>
+  Special instructions for IE 6 here
+<![endif]-->
+
+<!--[if IE 6]>
+  ${left alone}
+<![endif]-->
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/063.pt
@@ -0,0 +1,3 @@
+<div>
+  2
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/064.pt
@@ -0,0 +1,3 @@
+
+  <div	id="test"	class="test">
+  </div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/065.pt
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <title>Title</title>
+  </head>
+  <body>
+    <div id="content">
+      <div>Content</div>
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/066.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    Hello world!
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/067.pt
@@ -0,0 +1,6 @@
+<html>
+  <body>
+    <img src="#" class="up" />
+    <img src="#" class="down" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/068.pt
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <span>0 < 1 or 0 > 1</span>
+    <span>0 < 1 or 0 > 1</span>
+    <span class="0 < 1 or 0 > 1" />
+    <span>0 < 1 or 0 > 1</span>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069-en.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Title ('title' translation into 'en' with domain 'test')</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/069.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Title</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070-en.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Title ('title' translation into 'en' with domain 'test')</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/070.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Title</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/071.pt
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <input type="input" checked="True" />
+    <input type="input" />
+    <input type="input" />
+    <input type="input" checked="checked" />
+    <input type="input" checked />
+    <input type="input" />
+    <input type="input" class="True" />
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/072.pt
@@ -0,0 +1,19 @@
+<html>
+  <body>
+    <ul>
+      <li class="odd">1</li>
+      <li>2</li>
+      <li class="odd">3</li>
+    </ul>
+    <ul>
+      <li class="odd">1</li>
+      <li>2</li>
+      <li class="odd">3</li>
+    </ul>
+    <ul>
+      <li class="odd">1</li>
+      <li>2</li>
+      <li class="odd">3</li>
+    </ul>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/073.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>my title — my site</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/074.pt
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="windows-1251" ?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>my title — my site</title></head>
+<body></body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/075.pt
@@ -0,0 +1,19 @@
+
+  <html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+
+        foo
+
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/076.pt
@@ -0,0 +1,17 @@
+
+  <html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+<BLANKLINE>
+      bar
+<BLANKLINE>
+    </div>
+    <div id="footer">
+<BLANKLINE>
+    </div>
+  </body>
+</html>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077-en.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" value="value ('Title' translation into 'en' with domain 'test')" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/077.pt
@@ -0,0 +1,1 @@
+<input type="hidden" id="uploadify_label_file_title" value="value" />
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/078.pt
@@ -0,0 +1,11 @@
+
+  <body>
+      <span id="foo-toDataContainer">
+        <script type="text/javascript">
+          copyDataForSubmit('foo');</script>
+      </span>
+      <span class="selected-option">1</span>, 
+      <span class="selected-option">2</span>, 
+      <span class="selected-option">3</span>
+  </body>
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079-en.pt
@@ -0,0 +1,16 @@
+<html>
+  <head>
+    <title>Welcome ('Welcome' translation into 'en')</title>
+  </head>
+  <body>
+    <h1>Welcome ('Welcome' translation into 'en')</h1>
+    <span>An edge case: ${. ('An edge case: ${.' translation into 'en')</span>
+    <img alt="Site logo ('Site logo' translation into 'en')" href="http://host/logo.png" />
+    <img alt="Site logo ('Site logo' translation into 'en')" href="http://host/logo.png" />
+    <div id="content">
+      foo. ('foo.' translation into 'en')
+      <br />
+      bar. ('bar.' translation into 'en')
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/079.pt
@@ -0,0 +1,16 @@
+<html>
+  <head>
+    <title>Welcome</title>
+  </head>
+  <body>
+    <h1>Welcome</h1>
+    <span>An edge case: ${.</span>
+    <img alt="Site logo" href="http://host/logo.png" />
+    <img alt="Site logo" href="http://host/logo.png" />
+    <div id="content">
+      foo.
+      <br />
+      bar.
+    </div>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/080.pt
@@ -0,0 +1,3 @@
+
+   Hello world
+
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/081.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    Hello world!
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/082.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    Hello world!
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/083.pt
@@ -0,0 +1,15 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+
+        <!-- content here -->
+
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/084.pt
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <script>
+      <![CDATA[
+      alert("Hello world!");
+      ]]>
+    </script>
+  </head>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085-en.pt
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>Welcome</title>
+  </head>
+  <body>
+    <h1>Welcome</h1>
+    <p><a href="http://host">Click here ('Click here' translation into 'en' with domain 'new')</a> to continue. ('${click_here} to continue.' translation into 'en' with domain 'new')</p>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/085.pt
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>Welcome</title>
+  </head>
+  <body>
+    <h1>Welcome</h1>
+    <p><a href="http://host">Click here</a> to continue.</p>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/086.pt
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <title>Master template</title>
+  </head>
+  <body>
+    <div id="content">
+      <div>
+      <div>
+        <a href="#">Chart</a>
+        <div id="chart-info"/>
+      </div>
+    </div>
+    </div>
+    <div id="footer">
+
+    </div>
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/087.pt
@@ -0,0 +1,25 @@
+
+
+<ul>
+  <li>1</li>
+  <li>2</li>
+  <li>3</li>
+</ul>
+
+
+
+<ul>
+  <li>5</li>
+  <li>7</li>
+  <li>9</li>
+</ul>
+
+<div>
+
+  Please input a number from the range 1, 2, 3, 4, 5, 6, 7, 8, 9.
+</div>
+
+<div>
+
+  41 + 1 = 42.
+</div>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/088.pt
@@ -0,0 +1,1 @@
+a, b, c
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/101.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <h1><br><br>Hello world</h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/102.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <h1 class=title align=center>Hello world</h1>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/103.html
@@ -0,0 +1,8 @@
+<html>
+  <body>
+    <select name="foo2" multiple style="visibility: hidden">
+      <option value="1">this should</option>
+      <option value="2">remain hidden right?</option>
+    </select>
+  </body>
+</html>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/greeting.pt
@@ -0,0 +1,1 @@
+<div>Hello, undefined.</div>
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.pt
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    Hello world!
+  </body>
+</html>
\ No newline at end of file
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/outputs/hello_world.txt
@@ -0,0 +1,1 @@
+Hello world!
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_doctests.py
@@ -0,0 +1,40 @@
+import unittest
+import doctest
+
+OPTIONFLAGS = (doctest.ELLIPSIS |
+               doctest.REPORT_ONLY_FIRST_FAILURE)
+
+
+class DoctestCase(unittest.TestCase):
+    def __new__(self, test):
+        return getattr(self, test)()
+
+    @classmethod
+    def test_tal(cls):
+        from chameleon import tal
+        return doctest.DocTestSuite(
+            tal, optionflags=OPTIONFLAGS)
+
+    @classmethod
+    def test_tales(cls):
+        from chameleon import tales
+        return doctest.DocTestSuite(
+            tales, optionflags=OPTIONFLAGS)
+
+    @classmethod
+    def test_utils(cls):
+        from chameleon import utils
+        return doctest.DocTestSuite(
+            utils, optionflags=OPTIONFLAGS)
+
+    @classmethod
+    def test_exc(cls):
+        from chameleon import exc
+        return doctest.DocTestSuite(
+            exc, optionflags=OPTIONFLAGS)
+
+    @classmethod
+    def test_compiler(cls):
+        from chameleon import compiler
+        return doctest.DocTestSuite(
+            compiler, optionflags=OPTIONFLAGS)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_loader.py
@@ -0,0 +1,79 @@
+import unittest
+
+
+class LoadTests:
+    def _makeOne(self, search_path=None, **kwargs):
+        klass = self._getTargetClass()
+        return klass(search_path, **kwargs)
+
+    def _getTargetClass(self):
+        from chameleon.loader import TemplateLoader
+        return TemplateLoader
+
+    def test_load_relative(self):
+        import os
+        here = os.path.join(os.path.dirname(__file__), "inputs")
+        loader = self._makeOne(search_path=[here])
+        result = self._load(loader, 'hello_world.pt')
+        self.assertEqual(result.filename, os.path.join(here, 'hello_world.pt'))
+
+    def test_consecutive_loads(self):
+        import os
+        here = os.path.join(os.path.dirname(__file__), "inputs")
+        loader = self._makeOne(search_path=[here])
+
+        self.assertTrue(
+            self._load(loader, 'hello_world.pt') is \
+            self._load(loader, 'hello_world.pt'))
+
+    def test_load_relative_badpath_in_searchpath(self):
+        import os
+        here = os.path.join(os.path.dirname(__file__), "inputs")
+        loader = self._makeOne(search_path=[os.path.join(here, 'none'), here])
+        result = self._load(loader, 'hello_world.pt')
+        self.assertEqual(result.filename, os.path.join(here, 'hello_world.pt'))
+
+    def test_load_abs(self):
+        import os
+        here = os.path.join(os.path.dirname(__file__), "inputs")
+        loader = self._makeOne()
+        abs = os.path.join(here, 'hello_world.pt')
+        result = self._load(loader, abs)
+        self.assertEqual(result.filename, abs)
+
+
+class LoadPageTests(unittest.TestCase, LoadTests):
+    def _load(self, loader, filename):
+        from chameleon.zpt import template
+        return loader.load(filename, template.PageTemplateFile)
+
+
+class ZPTLoadTests(unittest.TestCase):
+    def _makeOne(self, *args, **kwargs):
+        import os
+        here = os.path.join(os.path.dirname(__file__), "inputs")
+        from chameleon.zpt import loader
+        return loader.TemplateLoader(here, **kwargs)
+
+    def test_load_xml(self):
+        loader = self._makeOne()
+        template = loader.load("hello_world.pt", "xml")
+        from chameleon.zpt.template import PageTemplateFile
+        self.assertTrue(isinstance(template, PageTemplateFile))
+
+    def test_load_text(self):
+        loader = self._makeOne()
+        template = loader.load("hello_world.txt", "text")
+        from chameleon.zpt.template import PageTextTemplateFile
+        self.assertTrue(isinstance(template, PageTextTemplateFile))
+
+    def test_load_getitem_gets_xml_file(self):
+        loader = self._makeOne()
+        template = loader["hello_world.pt"]
+        from chameleon.zpt.template import PageTemplateFile
+        self.assertTrue(isinstance(template, PageTemplateFile))
+
+
+def test_suite():
+    import sys
+    return unittest.findTestCases(sys.modules[__name__])
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_parser.py
@@ -0,0 +1,92 @@
+from __future__ import with_statement
+
+import sys
+
+from unittest import TestCase
+
+from ..namespaces import XML_NS
+from ..namespaces import XMLNS_NS
+from ..namespaces import PY_NS
+
+
+class ParserTest(TestCase):
+    def test_sample_files(self):
+        import os
+        import traceback
+        path = os.path.join(os.path.dirname(__file__), "inputs")
+        for filename in os.listdir(path):
+            if not filename.endswith('.html'):
+                continue
+
+            with open(os.path.join(path, filename), 'rb') as f:
+                source = f.read()
+
+            from ..utils import read_encoded
+            try:
+                want = read_encoded(source)
+            except UnicodeDecodeError:
+                exc = sys.exc_info()[1]
+                self.fail("%s - %s" % (exc, filename))
+
+            from ..tokenize import iter_xml
+            from ..parser import ElementParser
+            try:
+                tokens = iter_xml(want)
+                parser = ElementParser(tokens, {
+                    'xmlns': XMLNS_NS,
+                    'xml': XML_NS,
+                    'py': PY_NS,
+                    })
+                elements = tuple(parser)
+            except:
+                self.fail(traceback.format_exc())
+
+            output = []
+
+            def render(kind, args):
+                if kind == 'element':
+                    # start tag
+                    tag, end, children = args
+                    output.append("%(prefix)s%(name)s" % tag)
+
+                    for attr in tag['attrs']:
+                        output.append(
+                            "%(space)s%(name)s%(eq)s%(quote)s%(value)s%(quote)s" % \
+                            attr
+                            )
+
+                    output.append("%(suffix)s" % tag)
+
+                    # children
+                    for item in children:
+                        render(*item)
+
+                    # end tag
+                    output.append(
+                        "%(prefix)s%(name)s%(space)s%(suffix)s" % end
+                        )
+                elif kind == 'text':
+                    text = args[0]
+                    output.append(text)
+                elif kind == 'start_tag':
+                    node = args[0]
+                    output.append(
+                        "%(prefix)s%(name)s%(space)s%(suffix)s" % node
+                        )
+                else:
+                    raise RuntimeError("Not implemented: %s." % kind)
+
+            for kind, args in elements:
+                render(kind, args)
+
+            got = "".join(output)
+
+            from doctest import OutputChecker
+            checker = OutputChecker()
+
+            if checker.check_output(want, got, 0) is False:
+                from doctest import Example
+                example = Example(f.name, want)
+                diff = checker.output_difference(
+                    example, got, 0)
+                self.fail("(%s) - \n%s" % (f.name, diff))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_sniffing.py
@@ -0,0 +1,124 @@
+from __future__ import with_statement
+
+import os
+import unittest
+import tempfile
+import shutil
+
+from chameleon.utils import unicode_string
+from chameleon.utils import encode_string
+
+
+class TypeSniffingTestCase(unittest.TestCase):
+    def setUp(self):
+        self.tempdir = tempfile.mkdtemp(prefix='chameleon-tests')
+
+    def tearDown(self):
+        shutil.rmtree(self.tempdir)
+
+    def _get_temporary_file(self):
+        filename = os.path.join(self.tempdir, 'template.py')
+        assert not os.path.exists(filename)
+        f = open(filename, 'w')
+        f.flush()
+        f.close()
+        return filename
+
+    def get_template(self, text):
+        fn = self._get_temporary_file()
+
+        with open(fn, 'wb') as tmpfile:
+            tmpfile.write(text)
+
+        from chameleon.template import BaseTemplateFile
+
+        class DummyTemplateFile(BaseTemplateFile):
+            def cook(self, body):
+                self.body = body
+
+        template = DummyTemplateFile(fn)
+        template.cook_check()
+        return template
+
+    def check_content_type(self, text, expected_type):
+        from chameleon.utils import read_bytes
+        content_type = read_bytes(text, 'ascii')[2]
+        self.assertEqual(content_type, expected_type)
+
+    def test_xml_encoding(self):
+        from chameleon.utils import xml_prefixes
+
+        document1 = unicode_string(
+            "<?xml version='1.0' encoding='ascii'?><doc/>"
+            )
+        document2 = unicode_string(
+            "<?xml\tversion='1.0' encoding='ascii'?><doc/>"
+            )
+
+        for bom, encoding in xml_prefixes:
+            try:
+                "".encode(encoding)
+            except LookupError:
+                # System does not support this encoding
+                continue
+
+            self.check_content_type(document1.encode(encoding), "text/xml")
+            self.check_content_type(document2.encode(encoding), "text/xml")
+
+    HTML_PUBLIC_ID = "-//W3C//DTD HTML 4.01 Transitional//EN"
+    HTML_SYSTEM_ID = "http://www.w3.org/TR/html4/loose.dtd"
+
+    # Couldn't find the code that handles this... yet.
+    # def test_sniffer_html_ascii(self):
+    #     self.check_content_type(
+    #         "<!DOCTYPE html [ SYSTEM '%s' ]><html></html>"
+    #         % self.HTML_SYSTEM_ID,
+    #         "text/html")
+    #     self.check_content_type(
+    #         "<html><head><title>sample document</title></head></html>",
+    #         "text/html")
+
+    # TODO: This reflects a case that simply isn't handled by the
+    # sniffer; there are many, but it gets it right more often than
+    # before.
+    def donttest_sniffer_xml_simple(self):
+        self.check_content_type("<doc><element/></doc>", "text/xml")
+
+    def test_html_default_encoding(self):
+        body = encode_string(
+            '<html><head><title>' \
+            '\xc3\x90\xc2\xa2\xc3\x90\xc2\xb5' \
+            '\xc3\x91\xc2\x81\xc3\x91\xc2\x82' \
+            '</title></head></html>')
+
+        template = self.get_template(body)
+        self.assertEqual(template.body, body.decode('utf-8'))
+
+    def test_html_encoding_by_meta(self):
+        body = encode_string(
+            '<html><head><title>' \
+            '\xc3\x92\xc3\xa5\xc3\xb1\xc3\xb2' \
+            '</title><meta http-equiv="Content-Type"' \
+            ' content="text/html; charset=windows-1251"/>' \
+            "</head></html>")
+
+        template = self.get_template(body)
+        self.assertEqual(template.body, body.decode('windows-1251'))
+
+    def test_xhtml(self):
+        body = encode_string(
+            '<html><head><title>' \
+            '\xc3\x92\xc3\xa5\xc3\xb1\xc3\xb2' \
+            '</title><meta http-equiv="Content-Type"' \
+            ' content="text/html; charset=windows-1251"/>' \
+            "</head></html>")
+
+        template = self.get_template(body)
+        self.assertEqual(template.body, body.decode('windows-1251'))
+
+
+def test_suite():
+    return unittest.makeSuite(TypeSniffingTestCase)
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_templates.py
@@ -0,0 +1,679 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import with_statement
+
+import re
+import os
+import sys
+import shutil
+import tempfile
+
+from functools import wraps
+from functools import partial
+
+try:
+    from unittest2 import TestCase
+except ImportError:
+    from unittest import TestCase
+
+
+from chameleon.utils import byte_string
+
+
+class Message(object):
+    def __str__(self):
+        return "message"
+
+
+class ImportTestCase(TestCase):
+    def test_pagetemplates(self):
+        from chameleon import PageTemplate
+        from chameleon import PageTemplateFile
+        from chameleon import PageTemplateLoader
+
+    def test_pagetexttemplates(self):
+        from chameleon import PageTextTemplate
+        from chameleon import PageTextTemplateFile
+
+
+class TemplateFileTestCase(TestCase):
+    @property
+    def _class(self):
+        from chameleon.template import BaseTemplateFile
+
+        class TestTemplateFile(BaseTemplateFile):
+            cook_count = 0
+
+            def cook(self, body):
+                self.cook_count += 1
+                self._cooked = True
+
+        return TestTemplateFile
+
+    def setUp(self):
+        self.tempdir = tempfile.mkdtemp(prefix='chameleon-tests')
+
+    def tearDown(self):
+        shutil.rmtree(self.tempdir)
+
+    def _get_temporary_file(self):
+        filename = os.path.join(self.tempdir, 'template.py')
+        assert not os.path.exists(filename)
+        f = open(filename, 'w')
+        f.flush()
+        f.close()
+        return filename
+
+    def test_cook_check(self):
+        fn = self._get_temporary_file()
+        template = self._class(fn)
+        template.cook_check()
+        self.assertEqual(template.cook_count, 1)
+
+    def test_auto_reload(self):
+        fn = self._get_temporary_file()
+
+        # set time in past
+        os.utime(fn, (0, 0))
+
+        template = self._class(fn, auto_reload=True)
+        template.cook_check()
+
+        # a second cook check makes no difference
+        template.cook_check()
+        self.assertEqual(template.cook_count, 1)
+
+        # set current time on file
+        os.utime(fn, None)
+
+        # file is reloaded
+        template.cook_check()
+        self.assertEqual(template.cook_count, 2)
+
+    def test_relative_is_expanded_to_cwd(self):
+        template = self._class("___does_not_exist___")
+        try:
+            template.cook_check()
+        except IOError:
+            exc = sys.exc_info()[1]
+            self.assertEqual(
+                os.getcwd(),
+                os.path.dirname(exc.filename)
+                )
+        else:
+            self.fail("Expected OSError.")
+
+
+class RenderTestCase(TestCase):
+    root = os.path.dirname(__file__)
+
+    def find_files(self, ext):
+        inputs = os.path.join(self.root, "inputs")
+        outputs = os.path.join(self.root, "outputs")
+        for filename in sorted(os.listdir(inputs)):
+            name, extension = os.path.splitext(filename)
+            if extension != ext:
+                continue
+            path = os.path.join(inputs, filename)
+
+            # if there's no output file, treat document as static and
+            # expect intput equal to output
+            import glob
+            globbed = tuple(glob.iglob(os.path.join(
+                outputs, "%s*%s" % (name.split('-', 1)[0], ext))))
+
+            if not globbed:
+                self.fail("Missing output for: %s." % name)
+
+            for output in globbed:
+                name, ext = os.path.splitext(output)
+                basename = os.path.basename(name)
+                if '-' in basename:
+                    language = basename.split('-')[1]
+                else:
+                    language = None
+
+                yield path, output, language
+
+
+class ZopePageTemplatesTest(RenderTestCase):
+    @property
+    def from_string(body):
+        from ..zpt.template import PageTemplate
+        return partial(PageTemplate, keep_source=True)
+
+    @property
+    def from_file(body):
+        from ..zpt.template import PageTemplateFile
+        return partial(PageTemplateFile, keep_source=True)
+
+    def template(body):
+        def decorator(func):
+            @wraps(func)
+            def wrapper(self):
+                template = self.from_string(body)
+                return func(self, template)
+
+            return wrapper
+        return decorator
+
+    def error(body):
+        def decorator(func):
+            @wraps(func)
+            def wrapper(self):
+                from chameleon.exc import TemplateError
+                try:
+                    template = self.from_string(body)
+                except TemplateError:
+                    exc = sys.exc_info()[1]
+                    return func(self, body, exc)
+                else:
+                    self.fail("Expected exception.")
+
+            return wrapper
+        return decorator
+
+    def test_syntax_error_in_strict_mode(self):
+        from chameleon.exc import ExpressionError
+
+        self.assertRaises(
+            ExpressionError,
+            self.from_string,
+            """<tal:block replace='bad /// ' />""",
+            strict=True
+            )
+
+    def test_syntax_error_in_non_strict_mode(self):
+        from chameleon.exc import ExpressionError
+
+        body = """<tal:block replace='bad /// ' />"""
+        template = self.from_string(body, strict=False)
+
+        try:
+            template()
+        except ExpressionError:
+            exc = sys.exc_info()[1]
+            self.assertTrue(body[exc.offset:].startswith('bad ///'))
+        else:
+            self.fail("Expected exception")
+
+    @error("""<tal:dummy attributes=\"dummy 'dummy'\" />""")
+    def test_attributes_on_tal_tag_fails(self, body, exc):
+        self.assertTrue(body[exc.offset:].startswith('dummy'))
+
+    @error("""<tal:dummy i18n:attributes=\"foo, bar\" />""")
+    def test_i18n_attributes_with_non_identifiers(self, body, exc):
+        self.assertTrue(body[exc.offset:].startswith('foo,'))
+
+    @error("""<tal:dummy repeat=\"key,value mydict.items()\">""")
+    def test_repeat_syntax_error_message(self, body, exc):
+        self.assertTrue(body[exc.offset:].startswith('key,value'))
+
+    def test_encoded(self):
+        filename = '074-encoded-template.pt'
+        with open(os.path.join(self.root, 'inputs', filename), 'rb') as f:
+            body = f.read()
+
+        self.from_string(body)
+
+    def test_utf8_encoded(self):
+        filename = '073-utf8-encoded.pt'
+        with open(os.path.join(self.root, 'inputs', filename), 'rb') as f:
+            body = f.read()
+
+        self.from_string(body)
+
+    def test_unicode_decode_error(self):
+        template = self.from_file(
+            os.path.join(self.root, 'inputs', 'greeting.pt')
+            )
+
+        string = native = "the artist formerly known as ƤŗíƞĆě"
+        try:
+            string = string.decode('utf-8')
+        except AttributeError:
+            pass
+
+        class name:
+            @staticmethod
+            def __html__():
+                # This raises a decoding exception
+                string.encode('utf-8').decode('ascii')
+
+                self.fail("Expected exception raised.")
+
+        try:
+            template(name=name)
+        except UnicodeDecodeError:
+            exc = sys.exc_info()[1]
+            formatted = str(exc)
+
+            # There's a marker under the expression that has the
+            # unicode decode error
+            self.assertTrue('^^^^^' in formatted)
+            self.assertTrue(native in formatted)
+        else:
+            self.fail("expected error")
+
+    def test_custom_encoding_for_str_or_bytes_in_content(self):
+        string = '<div>Тест${text}</div>'
+        try:
+            string = string.decode('utf-8')
+        except AttributeError:
+            pass
+
+        template = self.from_string(string, encoding="windows-1251")
+
+        text = 'Тест'
+
+        try:
+            text = text.decode('utf-8')
+        except AttributeError:
+            pass
+
+        rendered = template(text=text.encode('windows-1251'))
+
+        self.assertEqual(
+            rendered,
+            string.replace('${text}', text)
+            )
+
+    def test_custom_encoding_for_str_or_bytes_in_attributes(self):
+        string = '<img tal="Тест${text}" />'
+        try:
+            string = string.decode('utf-8')
+        except AttributeError:
+            pass
+
+        template = self.from_string(string, encoding="windows-1251")
+
+        text = 'Тест'
+
+        try:
+            text = text.decode('utf-8')
+        except AttributeError:
+            pass
+
+        rendered = template(text=text.encode('windows-1251'))
+
+        self.assertEqual(
+            rendered,
+            string.replace('${text}', text)
+            )
+
+    def test_null_translate_function(self):
+        template = self.from_string('${test}', translate=None)
+        rendered = template(test=object())
+        self.assertTrue('object' in rendered)
+
+    def test_object_substitution_coerce_to_str(self):
+        template = self.from_string('${test}', translate=None)
+
+        class dummy(object):
+            def __repr__(inst):
+                self.fail("call not expected")
+
+            def __str__(inst):
+                return '<dummy>'
+
+        rendered = template(test=dummy())
+        self.assertEqual(rendered, '<dummy>')
+
+    def test_repr(self):
+        template = self.from_file(
+            os.path.join(self.root, 'inputs', 'hello_world.pt')
+            )
+        self.assertTrue(template.filename in repr(template))
+
+    def test_underscore_variable(self):
+        template = self.from_string(
+            "<div tal:define=\"_dummy 'foo'\">${_dummy}</div>"
+            )
+        self.assertTrue(template(), "<div>foo</div>")
+
+    def test_trim_attribute_space(self):
+        document = '''<div
+                  class="document"
+                  id="test"
+                  tal:attributes="class string:${default} test"
+            />'''
+
+        result1 = self.from_string(
+            document)()
+
+        result2 = self.from_string(
+            document, trim_attribute_space=True)()
+
+        self.assertEqual(result1.count(" "), 49)
+        self.assertEqual(result2.count(" "), 4)
+        self.assertTrue(" />" in result1)
+        self.assertTrue(" />" in result2)
+
+    def test_exception(self):
+        from traceback import format_exception_only
+
+        template = self.from_string(
+            "<div tal:define=\"dummy foo\">${dummy}</div>"
+            )
+        try:
+            template()
+        except:
+            exc = sys.exc_info()[1]
+            formatted = str(exc)
+            self.assertFalse('NameError:' in formatted)
+            self.assertTrue('foo' in formatted)
+            self.assertTrue('(1:23)' in formatted)
+
+            formatted_exc = "\n".join(format_exception_only(type(exc), exc))
+            self.assertTrue('NameError: foo' in formatted_exc)
+        else:
+            self.fail("expected error")
+
+    def test_create_formatted_exception(self):
+        from chameleon.utils import create_formatted_exception
+
+        exc = create_formatted_exception(NameError('foo'), NameError, str)
+        self.assertEqual(exc.args, ('foo', ))
+
+        class MyNameError(NameError):
+            def __init__(self, boo):
+                NameError.__init__(self, boo)
+                self.bar = boo
+
+        exc = create_formatted_exception(MyNameError('foo'), MyNameError, str)
+        self.assertEqual(exc.args, ('foo', ))
+        self.assertEqual(exc.bar, 'foo')
+
+    def test_create_formatted_exception_no_subclass(self):
+        from chameleon.utils import create_formatted_exception
+
+        class DifficultMetaClass(type):
+            def __init__(self, class_name, bases, namespace):
+                if not bases == (BaseException, ):
+                    raise TypeError(bases)
+
+        Difficult = DifficultMetaClass('Difficult', (BaseException, ), {'args': ()})
+
+        exc = create_formatted_exception(Difficult(), Difficult, str)
+        self.assertEqual(exc.args, ())
+
+    def test_error_handler_makes_safe_copy(self):
+        calls = []
+
+        class TestException(Exception):
+            def __init__(self, *args, **kwargs):
+                calls.append((args, kwargs))
+
+        def _render(stream, econtext, rcontext):
+            exc = TestException('foo', bar='baz')
+            rcontext['__error__'] = ('expression', 1, 42, 'test.pt', exc),
+            raise exc
+
+        template = self.from_string("")
+        template._render = _render
+        try:
+            template()
+        except TestException:
+            self.assertEqual(calls, [(('foo', ), {'bar': 'baz'})])
+            exc = sys.exc_info()[1]
+            formatted = str(exc)
+            self.assertTrue('TestException' in formatted)
+            self.assertTrue('"expression"' in formatted)
+            self.assertTrue('(1:42)' in formatted)
+        else:
+            self.fail("unexpected error")
+
+    def test_double_underscore_variable(self):
+        from chameleon.exc import TranslationError
+        self.assertRaises(
+            TranslationError, self.from_string,
+            "<div tal:define=\"__dummy 'foo'\">${__dummy}</div>",
+            )
+
+    def test_compiler_internals_are_disallowed(self):
+        from chameleon.compiler import COMPILER_INTERNALS_OR_DISALLOWED
+        from chameleon.exc import TranslationError
+
+        for name in COMPILER_INTERNALS_OR_DISALLOWED:
+            body = "<d tal:define=\"%s 'foo'\">${%s}</d>" % (name, name)
+            self.assertRaises(TranslationError, self.from_string, body)
+
+    def test_fast_translate_mapping(self):
+        template = self.from_string(
+            '<div i18n:translate="">'
+            '<span i18n:name="name">foo</span>'
+            '</div>')
+
+        self.assertEqual(template(), '<div><span>foo</span></div>')
+
+    def test_translate_is_not_an_internal(self):
+        macro = self.from_string('<span i18n:translate="">bar</span>')
+        template = self.from_string(
+            '''
+            <tal:defs define="translate string:">
+              <span i18n:translate="">foo</span>
+              <metal:macro use-macro="macro" />
+            </tal:defs>
+            ''')
+
+        result = template(macro=macro)
+        self.assertTrue('foo' in result)
+        self.assertTrue('foo' in result)
+
+    def test_literal_false(self):
+        template = self.from_string(
+            '<input type="input" tal:attributes="checked False" />'
+            '<input type="input" tal:attributes="checked True" />'
+            '<input type="input" tal:attributes="checked None" />'
+            '<input type="input" tal:attributes="checked default" />',
+            literal_false=True,
+            )
+
+        self.assertEqual(
+            template(),
+            '<input type="input" checked="False" />'
+            '<input type="input" checked="True" />'
+            '<input type="input" />'
+            '<input type="input" />',
+            template.source
+            )
+
+    def test_boolean_attributes(self):
+        template = self.from_string(
+            '<input type="input" tal:attributes="checked False" />'
+            '<input type="input" tal:attributes="checked True" />'
+            '<input type="input" tal:attributes="checked None" />'
+            '<input type="input" tal:attributes="checked \'\'" />'
+            '<input type="input" tal:attributes="checked default" />'
+            '<input type="input" checked="checked" tal:attributes="checked default" />',
+            boolean_attributes=set(['checked'])
+            )
+
+        self.assertEqual(
+            template(),
+            '<input type="input" />'
+            '<input type="input" checked="checked" />'
+            '<input type="input" />'
+            '<input type="input" />'
+            '<input type="input" />'
+            '<input type="input" checked="checked" />',
+            template.source
+            )
+
+    def test_default_debug_flag(self):
+        from chameleon.config import DEBUG_MODE
+        template = self.from_file(
+            os.path.join(self.root, 'inputs', 'hello_world.pt'),
+            )
+        self.assertEqual(template.debug, DEBUG_MODE)
+        self.assertTrue('debug' not in template.__dict__)
+
+    def test_debug_flag_on_string(self):
+        from chameleon.loader import ModuleLoader
+
+        with open(os.path.join(self.root, 'inputs', 'hello_world.pt')) as f:
+            source = f.read()
+
+        template = self.from_string(source, debug=True)
+
+        self.assertTrue(template.debug)
+        self.assertTrue(isinstance(template.loader, ModuleLoader))
+
+    def test_debug_flag_on_file(self):
+        from chameleon.loader import ModuleLoader
+        template = self.from_file(
+            os.path.join(self.root, 'inputs', 'hello_world.pt'),
+            debug=True,
+            )
+        self.assertTrue(template.debug)
+        self.assertTrue(isinstance(template.loader, ModuleLoader))
+
+    def test_tag_mismatch(self):
+        from chameleon.exc import ParseError
+
+        try:
+            self.from_string("""
+            <div metal:use-macro="layout">
+            <div metal:fill-slot="name"></dav>
+            </div>
+            """)
+        except ParseError:
+            exc = sys.exc_info()[1]
+            self.assertTrue("</dav>" in str(exc))
+        else:
+            self.fail("Expected error.")
+
+
+class ZopeTemplatesTestSuite(RenderTestCase):
+    def setUp(self):
+        self.temp_path = temp_path = tempfile.mkdtemp()
+
+        @self.addCleanup
+        def cleanup(path=temp_path):
+            shutil.rmtree(path)
+
+    def test_pt_files(self):
+        from ..zpt.template import PageTemplateFile
+
+        class Literal(object):
+            def __init__(self, s):
+                self.s = s
+
+            def __html__(self):
+                return self.s
+
+            def __str__(self):
+                raise RuntimeError(
+                    "%r is a literal." % self.s)
+
+        from chameleon.loader import TemplateLoader
+        loader = TemplateLoader(os.path.join(self.root, "inputs"))
+
+        self.execute(
+            ".pt", PageTemplateFile,
+            literal=Literal("<div>Hello world!</div>"),
+            content="<div>Hello world!</div>",
+            message=Message(),
+            load=loader.bind(PageTemplateFile),
+            )
+
+    def test_txt_files(self):
+        from ..zpt.template import PageTextTemplateFile
+        self.execute(".txt", PageTextTemplateFile)
+
+    def execute(self, ext, factory, **kwargs):
+        def translate(msgid, domain=None, mapping=None, context=None,
+                      target_language=None, default=None):
+            if default is None:
+                default = str(msgid)
+
+            if isinstance(msgid, Message):
+                default = "Message"
+
+            if mapping:
+                default = re.sub(r'\${([a-z_]+)}', r'%(\1)s', default) % \
+                          mapping
+
+            if target_language is None:
+                return default
+
+            if domain is None:
+                with_domain = ""
+            else:
+                with_domain = " with domain '%s'" % domain
+
+            stripped = default.rstrip('\n ')
+            return "%s ('%s' translation into '%s'%s)%s" % (
+                stripped, msgid, target_language, with_domain,
+                default[len(stripped):]
+                )
+
+        for input_path, output_path, language in self.find_files(ext):
+            # Make friendly title so we can locate the generated
+            # source when debugging
+            self.shortDescription = lambda: input_path
+
+            # Very implicitly enable implicit translation based on
+            # a string included in the input path:
+            implicit_i18n = 'implicit-i18n' in input_path
+            implicit_i18n_attrs = ("alt", "title") if implicit_i18n else ()
+
+            template = factory(
+                input_path,
+                keep_source=True,
+                strict=False,
+                implicit_i18n_translate=implicit_i18n,
+                implicit_i18n_attributes=implicit_i18n_attrs,
+                )
+
+            params = kwargs.copy()
+            params.update({
+                'translate': translate,
+                'target_language': language,
+                })
+
+            template.cook_check()
+
+            try:
+                got = template.render(**params)
+            except:
+                import traceback
+                e = traceback.format_exc()
+                self.fail("%s\n\n    Example source:\n\n%s" % (e, "\n".join(
+                    ["%#03.d%s" % (lineno + 1, line and " " + line or "")
+                     for (lineno, line) in
+                     enumerate(template.source.split(
+                         '\n'))])))
+
+            if isinstance(got, byte_string):
+                got = got.decode('utf-8')
+
+            from doctest import OutputChecker
+            checker = OutputChecker()
+
+            if not os.path.exists(output_path):
+                output = template.body
+            else:
+                with open(output_path, 'rb') as f:
+                    output = f.read()
+
+            from chameleon.utils import read_xml_encoding
+            from chameleon.utils import detect_encoding
+
+            if template.content_type == 'text/xml':
+                encoding = read_xml_encoding(output) or \
+                           template.default_encoding
+            else:
+                content_type, encoding = detect_encoding(
+                    output, template.default_encoding)
+
+            want = output.decode(encoding)
+
+            if checker.check_output(want, got, 0) is False:
+                from doctest import Example
+                example = Example(input_path, want)
+                diff = checker.output_difference(
+                    example, got, 0)
+                self.fail("(%s) - \n%s\n\nCode:\n%s" % (
+                    input_path, diff.rstrip('\n'),
+                    template.source.encode('utf-8')))
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py b/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tests/test_tokenizer.py
@@ -0,0 +1,47 @@
+import sys
+
+from unittest import TestCase
+
+
+class TokenizerTest(TestCase):
+    def test_sample_files(self):
+        import os
+        import traceback
+        path = os.path.join(os.path.dirname(__file__), "inputs")
+        for filename in os.listdir(path):
+            if not filename.endswith('.xml'):
+                continue
+            f = open(os.path.join(path, filename), 'rb')
+            source = f.read()
+            f.close()
+
+            from ..utils import read_encoded
+            try:
+                want = read_encoded(source)
+            except UnicodeDecodeError:
+                exc = sys.exc_info()[1]
+                self.fail("%s - %s" % (exc, filename))
+
+            from ..tokenize import iter_xml
+            try:
+                tokens = iter_xml(want)
+                got = "".join(tokens)
+            except:
+                self.fail(traceback.format_exc())
+
+            from doctest import OutputChecker
+            checker = OutputChecker()
+
+            if checker.check_output(want, got, 0) is False:
+                from doctest import Example
+                example = Example(f.name, want)
+                diff = checker.output_difference(
+                    example, got, 0)
+                self.fail("(%s) - \n%s" % (f.name, diff))
+
+    def test_token(self):
+        from chameleon.tokenize import Token
+        token = Token("abc", 1)
+
+        self.assertTrue(isinstance(token[1:], Token))
+        self.assertEqual(token[1:].pos, 2)
diff --git a/lib/Chameleon-2.9.2/src/chameleon/tokenize.py b/lib/Chameleon-2.9.2/src/chameleon/tokenize.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/tokenize.py
@@ -0,0 +1,144 @@
+# http://code.activestate.com/recipes/65125-xml-lexing-shallow-parsing/
+# by Paul Prescod
+# licensed under the PSF License
+#
+# modified to capture all non-overlapping parts of tokens
+
+import re
+
+try:
+    str = unicode
+except NameError:
+    pass
+
+class recollector:
+    def __init__(self):
+        self.res = {}
+
+    def add(self, name, reg ):
+        re.compile(reg)  # check that it is valid
+        self.res[name] = reg % self.res
+
+collector = recollector()
+a = collector.add
+
+a("TextSE", "[^<]+")
+a("UntilHyphen", "[^-]*-")
+a("Until2Hyphens", "%(UntilHyphen)s(?:[^-]%(UntilHyphen)s)*-")
+a("CommentCE", "%(Until2Hyphens)s>?")
+a("UntilRSBs", "[^\\]]*](?:[^\\]]+])*]+")
+a("CDATA_CE", "%(UntilRSBs)s(?:[^\\]>]%(UntilRSBs)s)*>" )
+a("S", "[ \\n\\t\\r]+")
+a("Simple", "[^\"'>/]+")
+a("NameStrt", "[A-Za-z_:]|[^\\x00-\\x7F]")
+a("NameChar", "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]")
+a("Name", "(?:%(NameStrt)s)(?:%(NameChar)s)*")
+a("QuoteSE", "\"[^\"]*\"|'[^']*'")
+a("DT_IdentSE" , "%(S)s%(Name)s(?:%(S)s(?:%(Name)s|%(QuoteSE)s))*" )
+a("MarkupDeclCE" , "(?:[^\\]\"'><]+|%(QuoteSE)s)*>" )
+a("S1", "[\\n\\r\\t ]")
+a("UntilQMs", "[^?]*\\?+")
+a("PI_Tail" , "\\?>|%(S1)s%(UntilQMs)s(?:[^>?]%(UntilQMs)s)*>" )
+a("DT_ItemSE",
+  "<(?:!(?:--%(Until2Hyphens)s>|[^-]%(MarkupDeclCE)s)|"
+  "\\?%(Name)s(?:%(PI_Tail)s))|%%%(Name)s;|%(S)s"
+)
+a("DocTypeCE" ,
+"%(DT_IdentSE)s(?:%(S)s)?(?:\\[(?:%(DT_ItemSE)s)*](?:%(S)s)?)?>?" )
+a("DeclCE",
+  "--(?:%(CommentCE)s)?|\\[CDATA\\[(?:%(CDATA_CE)s)?|"
+  "DOCTYPE(?:%(DocTypeCE)s)?")
+a("PI_CE", "%(Name)s(?:%(PI_Tail)s)?")
+a("EndTagCE", "%(Name)s(?:%(S)s)?>?")
+a("AttValSE", "\"[^\"]*\"|'[^']*'")
+a("ElemTagCE",
+  "(%(Name)s)(?:(%(S)s)(%(Name)s)(((?:%(S)s)?=(?:%(S)s)?)"
+  "(?:%(AttValSE)s|%(Simple)s)|(?!(?:%(S)s)?=)))*(?:%(S)s)?(/?>)?")
+a("MarkupSPE",
+  "<(?:!(?:%(DeclCE)s)?|"
+  "\\?(?:%(PI_CE)s)?|/(?:%(EndTagCE)s)?|(?:%(ElemTagCE)s)?)")
+a("XML_SPE", "%(TextSE)s|%(MarkupSPE)s")
+a("XML_MARKUP_ONLY_SPE", "%(MarkupSPE)s")
+a("ElemTagSPE", "<|%(Name)s")
+
+re_xml_spe = re.compile(collector.res['XML_SPE'])
+re_markup_only_spe = re.compile(collector.res['XML_MARKUP_ONLY_SPE'])
+
+
+def iter_xml(body, filename=None):
+    for match in re_xml_spe.finditer(body):
+        string = match.group()
+        pos = match.start()
+        yield Token(string, pos, body, filename)
+
+
+def iter_text(body, filename=None):
+    yield Token(body, 0, body, filename)
+
+
+class Token(str):
+    __slots__ = "pos", "source", "filename"
+
+    def __new__(cls, string, pos=0, source=None, filename=None):
+        inst = str.__new__(cls, string)
+        inst.pos = pos
+        inst.source = source
+        inst.filename = filename or ""
+        return inst
+
+    def __getslice__(self, i, j):
+        slice = str.__getslice__(self, i, j)
+        return Token(slice, self.pos + i, self.source, self.filename)
+
+    def __getitem__(self, index):
+        s = str.__getitem__(self, index)
+        if isinstance(index, slice):
+            return Token(
+                s, self.pos + (index.start or 0), self.source, self.filename)
+        return s
+
+    def __add__(self, other):
+        if other is None:
+            return self
+
+        return Token(
+            str.__add__(self, other), self.pos, self.source, self.filename)
+
+    def __eq__(self, other):
+        return str.__eq__(self, other)
+
+    def __hash__(self):
+        return str.__hash__(self)
+
+    def replace(self, *args):
+        s = str.replace(self, *args)
+        return Token(s, self.pos, self.source, self.filename)
+
+    def split(self, *args):
+        l = str.split(self, *args)
+        pos = self.pos
+        for i, s in enumerate(l):
+            l[i] = Token(s, pos, self.source, self.filename)
+            pos += len(s)
+        return l
+
+    def strip(self, *args):
+        return self.lstrip(*args).rstrip(*args)
+
+    def lstrip(self, *args):
+        s = str.lstrip(self, *args)
+        return Token(
+            s, self.pos + len(self) - len(s), self.source, self.filename)
+
+    def rstrip(self, *args):
+        s = str.rstrip(self, *args)
+        return Token(s, self.pos, self.source, self.filename)
+
+    @property
+    def location(self):
+        if self.source is None:
+            return 0, self.pos
+
+        body = self.source[:self.pos]
+        line = body.count('\n')
+        return line + 1, self.pos - body.rfind('\n', 0) - 1
diff --git a/lib/Chameleon-2.9.2/src/chameleon/utils.py b/lib/Chameleon-2.9.2/src/chameleon/utils.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/utils.py
@@ -0,0 +1,429 @@
+import os
+import re
+import sys
+import codecs
+import logging
+
+from copy import copy
+
+version = sys.version_info[:3]
+
+try:
+    import ast as _ast
+except ImportError:
+    from chameleon import ast24 as _ast
+
+
+class ASTProxy(object):
+    aliases = {
+        # Python 3.3
+        'TryExcept': 'Try',
+        'TryFinally': 'Try',
+        }
+
+    def __getattr__(self, name):
+        return _ast.__dict__.get(name) or getattr(_ast, self.aliases[name])
+
+
+ast = ASTProxy()
+
+log = logging.getLogger('chameleon.utils')
+
+# Python 2
+if version < (3, 0, 0):
+    import htmlentitydefs
+    import __builtin__ as builtins
+
+    from .py25 import raise_with_traceback
+
+    chr = unichr
+    native_string = str
+    decode_string = unicode
+    encode_string = str
+    unicode_string = unicode
+    string_type = basestring
+    byte_string = str
+
+    def safe_native(s, encoding='utf-8'):
+        if not isinstance(s, unicode):
+            s = decode_string(s, encoding, 'replace')
+
+        return s.encode(encoding)
+
+# Python 3
+else:
+    from html import entities as htmlentitydefs
+    import builtins
+
+    byte_string = bytes
+    string_type = str
+    native_string = str
+    decode_string = bytes.decode
+    encode_string = lambda s: bytes(s, 'utf-8')
+    unicode_string = str
+
+    def safe_native(s, encoding='utf-8'):
+        if not isinstance(s, str):
+            s = decode_string(s, encoding, 'replace')
+
+        return s
+
+    def raise_with_traceback(exc, tb):
+        exc.__traceback__ = tb
+        raise exc
+
+def text_(s, encoding='latin-1', errors='strict'):
+    """ If ``s`` is an instance of ``byte_string``, return
+    ``s.decode(encoding, errors)``, otherwise return ``s``"""
+    if isinstance(s, byte_string):
+        return s.decode(encoding, errors)
+    return s
+
+entity_re = re.compile(r'&(#?)(x?)(\d{1,5}|\w{1,8});')
+
+module_cache = {}
+
+xml_prefixes = (
+    (codecs.BOM_UTF8, 'utf-8-sig'),
+    (codecs.BOM_UTF16_BE, 'utf-16-be'),
+    (codecs.BOM_UTF16_LE, 'utf-16-le'),
+    (codecs.BOM_UTF16, 'utf-16'),
+    (codecs.BOM_UTF32_BE, 'utf-32-be'),
+    (codecs.BOM_UTF32_LE, 'utf-32-le'),
+    (codecs.BOM_UTF32, 'utf-32'),
+    )
+
+
+def _has_encoding(encoding):
+    try:
+        "".encode(encoding)
+    except LookupError:
+        return False
+    else:
+        return True
+
+
+# Precomputed prefix table
+_xml_prefixes = tuple(
+    (bom, str('<?xml').encode(encoding), encoding)
+    for bom, encoding in reversed(xml_prefixes)
+    if _has_encoding(encoding)
+    )
+
+_xml_decl = encode_string("<?xml")
+
+RE_META = re.compile(
+    r'\s*<meta\s+http-equiv=["\']?Content-Type["\']?'
+    r'\s+content=["\']?([^;]+);\s*charset=([^"\']+)["\']?\s*/?\s*>\s*',
+    re.IGNORECASE
+    )
+
+RE_ENCODING = re.compile(
+    r'encoding\s*=\s*(?:"|\')(?P<encoding>[\w\-]+)(?:"|\')'.encode('ascii'),
+    re.IGNORECASE
+    )
+
+
+def read_encoded(data):
+    return read_bytes(data, "utf-8")[0]
+
+
+def read_bytes(body, default_encoding):
+    for bom, prefix, encoding in _xml_prefixes:
+        if body.startswith(bom):
+            document = body.decode(encoding)
+            return document, encoding, \
+                   "text/xml" if document.startswith("<?xml") else None
+
+        if prefix != encode_string('<?xml') and body.startswith(prefix):
+            return body.decode(encoding), encoding, "text/xml"
+
+    if body.startswith(_xml_decl):
+        content_type = "text/xml"
+
+        encoding = read_xml_encoding(body) or default_encoding
+    else:
+        content_type, encoding = detect_encoding(body, default_encoding)
+
+    return body.decode(encoding), encoding, content_type
+
+
+def detect_encoding(body, default_encoding):
+    if not isinstance(body, str):
+        body = body.decode('ascii', 'ignore')
+
+    match = RE_META.search(body)
+    if match is not None:
+        return match.groups()
+
+    return None, default_encoding
+
+
+def read_xml_encoding(body):
+    if body.startswith('<?xml'.encode('ascii')):
+        match = RE_ENCODING.search(body)
+        if match is not None:
+            return match.group('encoding').decode('ascii')
+
+
+def mangle(filename):
+    """Mangles template filename into top-level Python module name.
+
+    >>> mangle('hello_world.pt')
+    'hello_world'
+
+    >>> mangle('foo.bar.baz.pt')
+    'foo_bar_baz'
+
+    >>> mangle('foo-bar-baz.pt')
+    'foo_bar_baz'
+
+    """
+
+    base, ext = os.path.splitext(filename)
+    return base.replace('.', '_').replace('-', '_')
+
+
+def char2entity(c):
+    cp = ord(c)
+    name = htmlentitydefs.codepoint2name.get(cp)
+    return '&%s;' % name if name is not None else '&#%d;' % cp
+
+
+def substitute_entity(match, n2cp=htmlentitydefs.name2codepoint):
+    ent = match.group(3)
+
+    if match.group(1) == "#":
+        if match.group(2) == '':
+            return chr(int(ent))
+        elif match.group(2) == 'x':
+            return chr(int('0x' + ent, 16))
+    else:
+        cp = n2cp.get(ent)
+
+        if cp:
+            return chr(cp)
+        else:
+            return match.group()
+
+
+def create_formatted_exception(exc, cls, formatter):
+    try:
+        try:
+            new = type(cls.__name__, (cls, Exception), {
+                '__str__': formatter,
+                '__new__': BaseException.__new__,
+                '__module__': cls.__module__,
+                })
+        except TypeError:
+            new = cls
+
+        try:
+            inst = BaseException.__new__(new)
+        except TypeError:
+            inst = cls.__new__(new)
+
+        BaseException.__init__(inst, *exc.args)
+        inst.__dict__ = exc.__dict__
+
+        return inst
+    except ValueError:
+        name = type(exc).__name__
+        log.warn("Unable to copy exception of type '%s'." % name)
+        raise TypeError(exc)
+
+
+def unescape(string):
+    for name in ('lt', 'gt', 'quot'):
+        cp = htmlentitydefs.name2codepoint[name]
+        string = string.replace('&%s;' % name, chr(cp))
+
+    return string
+
+
+_concat = unicode_string("").join
+
+
+def join(stream):
+    """Concatenate stream.
+
+    >>> print(join(('Hello', ' ', 'world')))
+    Hello world
+
+    >>> join(('Hello', 0))
+    Traceback (most recent call last):
+     ...
+    TypeError: ... expected ...
+
+    """
+
+    try:
+        return _concat(stream)
+    except:
+        # Loop through stream and coerce each element into unicode;
+        # this should raise an exception
+        for element in stream:
+            unicode_string(element)
+
+        # In case it didn't, re-raise the original exception
+        raise
+
+
+def decode_htmlentities(string):
+    """
+    >>> native_string(decode_htmlentities('&amp;'))
+    '&'
+
+    """
+
+    decoded = entity_re.subn(substitute_entity, string)[0]
+
+    # preserve input token data
+    return string.replace(string, decoded)
+
+
+# Taken from zope.dottedname
+def _resolve_dotted(name, module=None):
+    name = name.split('.')
+    if not name[0]:
+        if module is None:
+            raise ValueError("relative name without base module")
+        module = module.split('.')
+        name.pop(0)
+        while not name[0]:
+            module.pop()
+            name.pop(0)
+        name = module + name
+
+    used = name.pop(0)
+    found = __import__(used)
+    for n in name:
+        used += '.' + n
+        try:
+            found = getattr(found, n)
+        except AttributeError:
+            __import__(used)
+            found = getattr(found, n)
+
+    return found
+
+
+def resolve_dotted(dotted):
+    if not dotted in module_cache:
+        resolved = _resolve_dotted(dotted)
+        module_cache[dotted] = resolved
+    return module_cache[dotted]
+
+
+def limit_string(s, max_length=53):
+    if len(s) > max_length:
+        return s[:max_length - 3] + '...'
+
+    return s
+
+
+def format_kwargs(kwargs):
+    items = []
+    for name, value in kwargs.items():
+        if isinstance(value, string_type):
+            short = limit_string(value)
+            items.append((name, short.replace('\n', '\\n')))
+        elif isinstance(value, (int, float)):
+            items.append((name, value))
+        elif isinstance(value, dict):
+            items.append((name, '{...} (%d)' % len(value)))
+        else:
+            items.append((name,
+                "<%s %s at %s>" % (
+                    type(value).__name__,
+                    getattr(value, '__name__', "-"),
+                    hex(abs(id(value))))))
+
+    return ["%s: %s" % item for item in items]
+
+
+class callablestr(str):
+    __slots__ = ()
+
+    def __call__(self):
+        return self
+
+
+class callableint(int):
+    __slots__ = ()
+
+    def __call__(self):
+        return self
+
+
+class descriptorstr(object):
+    __slots__ = "function", "__name__"
+
+    def __init__(self, function):
+        self.function = function
+        self.__name__ = function.__name__
+
+    def __get__(self, context, cls):
+        return callablestr(self.function(context))
+
+
+class descriptorint(object):
+    __slots__ = "function", "__name__"
+
+    def __init__(self, function):
+        self.function = function
+        self.__name__ = function.__name__
+
+    def __get__(self, context, cls):
+        return callableint(self.function(context))
+
+
+class DebuggingOutputStream(list):
+    def append(self, value):
+        if not isinstance(value, string_type):
+            raise TypeError(value)
+
+        unicode_string(value)
+        list.append(self, value)
+
+
+class Scope(dict):
+    set_local = setLocal = dict.__setitem__
+
+    __slots__ = "set_global",
+
+    def __new__(cls, *args):
+        inst = dict.__new__(cls, *args)
+        inst.set_global = inst.__setitem__
+        return inst
+
+    def __getitem__(self, key):
+        try:
+            return dict.__getitem__(self, key)
+        except KeyError:
+            raise NameError(key)
+
+    @property
+    def vars(self):
+        return self
+
+    def copy(self):
+        inst = Scope(self)
+        inst.set_global = self.set_global
+        return inst
+
+
+class ListDictProxy(object):
+    def __init__(self, l):
+        self._l = l
+
+    def get(self, key):
+        return self._l[-1].get(key)
+
+
+class Markup(unicode_string):
+    def __html__(self):
+        return unicode_string(self)
+
+    def __repr__(self):
+        return "s'%s'" % self.s
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/__init__.py
@@ -0,0 +1,1 @@
+#
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/loader.py
@@ -0,0 +1,30 @@
+from chameleon.loader import TemplateLoader as BaseLoader
+from chameleon.zpt import template
+
+
+class TemplateLoader(BaseLoader):
+    formats = {
+        "xml": template.PageTemplateFile,
+        "text": template.PageTextTemplateFile,
+        }
+
+    default_format = "xml"
+
+    def __init__(self, *args, **kwargs):
+        formats = kwargs.pop('formats', None)
+        if formats is not None:
+            self.formats = formats
+
+        super(TemplateLoader, self).__init__(*args, **kwargs)
+
+    def load(self, filename, format=None):
+        """Load and return a template file.
+
+        The format parameter determines will parse the file. Valid
+        options are `xml` and `text`.
+        """
+
+        cls = self.formats[format or self.default_format]
+        return super(TemplateLoader, self).load(filename, cls)
+
+    __getitem__ = load
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/program.py
@@ -0,0 +1,751 @@
+import re
+
+try:
+    import ast
+except ImportError:
+    from chameleon import ast24 as ast
+
+try:
+    str = unicode
+except NameError:
+    long = int
+
+from functools import partial
+from copy import copy
+
+from ..program import ElementProgram
+
+from ..namespaces import XML_NS
+from ..namespaces import XMLNS_NS
+from ..namespaces import I18N_NS as I18N
+from ..namespaces import TAL_NS as TAL
+from ..namespaces import METAL_NS as METAL
+from ..namespaces import META_NS as META
+
+from ..astutil import Static
+from ..astutil import parse
+from ..astutil import marker
+
+from .. import tal
+from .. import metal
+from .. import i18n
+from .. import nodes
+
+from ..exc import LanguageError
+from ..exc import ParseError
+from ..exc import CompilationError
+
+from ..utils import decode_htmlentities
+
+try:
+    str = unicode
+except NameError:
+    long = int
+
+
+missing = object()
+
+re_trim = re.compile(r'($\s+|\s+^)', re.MULTILINE)
+
+def skip(node):
+    return node
+
+
+def wrap(node, *wrappers):
+    for wrapper in reversed(wrappers):
+        node = wrapper(node)
+    return node
+
+
+def validate_attributes(attributes, namespace, whitelist):
+    for ns, name in attributes:
+        if ns == namespace and name not in whitelist:
+            raise CompilationError(
+                "Bad attribute for namespace '%s'" % ns, name
+                )
+
+
+class MacroProgram(ElementProgram):
+    """Visitor class that generates a program for the ZPT language."""
+
+    DEFAULT_NAMESPACES = {
+        'xmlns': XMLNS_NS,
+        'xml': XML_NS,
+        'tal': TAL,
+        'metal': METAL,
+        'i18n': I18N,
+        'meta': META,
+        }
+
+    DROP_NS = TAL, METAL, I18N, META
+
+    VARIABLE_BLACKLIST = "default", "repeat", "nothing", \
+                         "convert", "decode", "translate"
+
+    _interpolation_enabled = True
+    _whitespace = "\n"
+    _last = ""
+
+    # Macro name (always trivial for a macro program)
+    name = None
+
+    # This default marker value has the semantics that if an
+    # expression evaluates to that value, the expression default value
+    # is returned. For an attribute, if there is no default, this
+    # means that the attribute is dropped.
+    default_marker = None
+
+    # Escape mode (true value means XML-escape)
+    escape = True
+
+    # Attributes which should have boolean behavior (on true, the
+    # value takes the attribute name, on false, the attribute is
+    # dropped)
+    boolean_attributes = set()
+
+    # If provided, this should be a set of attributes for implicit
+    # translation. Any attribute whose name is included in the set
+    # will be translated even without explicit markup. Note that all
+    # values should be lowercase strings.
+    implicit_i18n_attributes = set()
+
+    # If set, text will be translated even without explicit markup.
+    implicit_i18n_translate = False
+
+    # If set, additional attribute whitespace will be stripped.
+    trim_attribute_space = False
+
+    def __init__(self, *args, **kwargs):
+        # Internal array for switch statements
+        self._switches = []
+
+        # Internal array for current use macro level
+        self._use_macro = []
+
+        # Internal array for current interpolation status
+        self._interpolation = [True]
+
+        # Internal dictionary of macro definitions
+        self._macros = {}
+
+        # Apply default values from **kwargs to self
+        self._pop_defaults(
+            kwargs,
+            'boolean_attributes',
+            'default_marker',
+            'escape',
+            'implicit_i18n_translate',
+            'implicit_i18n_attributes',
+            'trim_attribute_space',
+            )
+
+        super(MacroProgram, self).__init__(*args, **kwargs)
+
+    @property
+    def macros(self):
+        macros = list(self._macros.items())
+        macros.append((None, nodes.Sequence(self.body)))
+
+        return tuple(
+            nodes.Macro(name, [nodes.Context(node)])
+            for name, node in macros
+            )
+
+    def visit_default(self, node):
+        return nodes.Text(node)
+
+    def visit_element(self, start, end, children):
+        ns = start['ns_attrs']
+
+        for (prefix, attr), encoded in tuple(ns.items()):
+            if prefix == TAL:
+                ns[prefix, attr] = decode_htmlentities(encoded)
+
+        # Validate namespace attributes
+        validate_attributes(ns, TAL, tal.WHITELIST)
+        validate_attributes(ns, METAL, metal.WHITELIST)
+        validate_attributes(ns, I18N, i18n.WHITELIST)
+
+        # Check attributes for language errors
+        self._check_attributes(start['namespace'], ns)
+
+        # Remember whitespace for item repetition
+        if self._last is not None:
+            self._whitespace = "\n" + " " * len(self._last.rsplit('\n', 1)[-1])
+
+        # Set element-local whitespace
+        whitespace = self._whitespace
+
+        # Set up switch
+        try:
+            clause = ns[TAL, 'switch']
+        except KeyError:
+            switch = None
+        else:
+            switch = nodes.Value(clause)
+
+        self._switches.append(switch)
+
+        body = []
+
+        # Include macro
+        use_macro = ns.get((METAL, 'use-macro'))
+        extend_macro = ns.get((METAL, 'extend-macro'))
+        if use_macro or extend_macro:
+            slots = []
+            self._use_macro.append(slots)
+
+            if use_macro:
+                inner = nodes.UseExternalMacro(
+                    nodes.Value(use_macro), slots, False
+                    )
+            else:
+                inner = nodes.UseExternalMacro(
+                    nodes.Value(extend_macro), slots, True
+                    )
+        # -or- include tag
+        else:
+            content = nodes.Sequence(body)
+
+            # tal:content
+            try:
+                clause = ns[TAL, 'content']
+            except KeyError:
+                pass
+            else:
+                key, value = tal.parse_substitution(clause)
+                xlate = True if ns.get((I18N, 'translate')) == '' else False
+                content = self._make_content_node(value, content, key, xlate)
+
+                if end is None:
+                    # Make sure start-tag has opening suffix.
+                    start['suffix']  = ">"
+
+                    # Explicitly set end-tag.
+                    end = {
+                        'prefix': '</',
+                        'name': start['name'],
+                        'space': '',
+                        'suffix': '>'
+                        }
+
+            # i18n:translate
+            try:
+                clause = ns[I18N, 'translate']
+            except KeyError:
+                pass
+            else:
+                dynamic = ns.get((TAL, 'content')) or ns.get((TAL, 'replace'))
+
+                if not dynamic:
+                    content = nodes.Translate(clause, content)
+
+            # tal:attributes
+            try:
+                clause = ns[TAL, 'attributes']
+            except KeyError:
+                TAL_ATTRIBUTES = {}
+            else:
+                TAL_ATTRIBUTES = tal.parse_attributes(clause)
+
+            # i18n:attributes
+            try:
+                clause = ns[I18N, 'attributes']
+            except KeyError:
+                I18N_ATTRIBUTES = {}
+            else:
+                I18N_ATTRIBUTES = i18n.parse_attributes(clause)
+
+            # Prepare attributes from TAL language
+            prepared = tal.prepare_attributes(
+                start['attrs'], TAL_ATTRIBUTES,
+                I18N_ATTRIBUTES, ns, self.DROP_NS
+                )
+
+            # Create attribute nodes
+            STATIC_ATTRIBUTES = self._create_static_attributes(prepared)
+            ATTRIBUTES = self._create_attributes_nodes(
+                prepared, I18N_ATTRIBUTES
+                )
+
+            # Start- and end nodes
+            start_tag = nodes.Start(
+                start['name'],
+                self._maybe_trim(start['prefix']),
+                self._maybe_trim(start['suffix']),
+                ATTRIBUTES
+                )
+
+            end_tag = nodes.End(
+                end['name'],
+                end['space'],
+                self._maybe_trim(end['prefix']),
+                self._maybe_trim(end['suffix']),
+                ) if end is not None else None
+
+            # tal:omit-tag
+            try:
+                clause = ns[TAL, 'omit-tag']
+            except KeyError:
+                omit = False
+            else:
+                clause = clause.strip()
+
+                if clause == "":
+                    omit = True
+                else:
+                    expression = nodes.Negate(nodes.Value(clause))
+                    omit = expression
+
+                    # Wrap start- and end-tags in condition
+                    start_tag = nodes.Condition(expression, start_tag)
+
+                    if end_tag is not None:
+                        end_tag = nodes.Condition(expression, end_tag)
+
+            if omit is True or start['namespace'] in self.DROP_NS:
+                inner = content
+            else:
+                inner = nodes.Element(
+                    start_tag,
+                    end_tag,
+                    content,
+                    )
+
+                # Assign static attributes dictionary to "attrs" value
+                inner = nodes.Define(
+                    [nodes.Alias(["attrs"], STATIC_ATTRIBUTES)],
+                    inner,
+                    )
+
+                if omit is not False:
+                    inner = nodes.Cache([omit], inner)
+
+            # tal:replace
+            try:
+                clause = ns[TAL, 'replace']
+            except KeyError:
+                pass
+            else:
+                key, value = tal.parse_substitution(clause)
+                xlate = True if ns.get((I18N, 'translate')) == '' else False
+                inner = self._make_content_node(value, inner, key, xlate)
+
+        # metal:define-slot
+        try:
+            clause = ns[METAL, 'define-slot']
+        except KeyError:
+            DEFINE_SLOT = skip
+        else:
+            DEFINE_SLOT = partial(nodes.DefineSlot, clause)
+
+        # tal:define
+        try:
+            clause = ns[TAL, 'define']
+        except KeyError:
+            DEFINE = skip
+        else:
+            defines = tal.parse_defines(clause)
+            if defines is None:
+                raise ParseError("Invalid define syntax.", clause)
+
+            DEFINE = partial(
+                nodes.Define,
+                [nodes.Assignment(
+                    names, nodes.Value(expr), context == "local")
+                 for (context, names, expr) in defines],
+                )
+
+        # tal:case
+        try:
+            clause = ns[TAL, 'case']
+        except KeyError:
+            CASE = skip
+        else:
+            value = nodes.Value(clause)
+            for switch in reversed(self._switches):
+                if switch is not None:
+                    break
+            else:
+                raise LanguageError(
+                    "Must define switch on a parent element.", clause
+                    )
+
+            CASE = lambda node: nodes.Define(
+                [nodes.Assignment(["default"], switch, True)],
+                nodes.Condition(
+                    nodes.Equality(switch, value),
+                    node,
+                    )
+                )
+
+        # tal:repeat
+        try:
+            clause = ns[TAL, 'repeat']
+        except KeyError:
+            REPEAT = skip
+        else:
+            defines = tal.parse_defines(clause)
+            assert len(defines) == 1
+            context, names, expr = defines[0]
+
+            expression = nodes.Value(expr)
+
+            REPEAT = partial(
+                nodes.Repeat,
+                names,
+                expression,
+                context == "local",
+                whitespace
+                )
+
+        # tal:condition
+        try:
+            clause = ns[TAL, 'condition']
+        except KeyError:
+            CONDITION = skip
+        else:
+            expression = nodes.Value(clause)
+            CONDITION = partial(nodes.Condition, expression)
+
+        # tal:switch
+        if switch is None:
+            SWITCH = skip
+        else:
+            SWITCH = partial(nodes.Cache, [switch])
+
+        # i18n:domain
+        try:
+            clause = ns[I18N, 'domain']
+        except KeyError:
+            DOMAIN = skip
+        else:
+            DOMAIN = partial(nodes.Domain, clause)
+
+        # i18n:name
+        try:
+            clause = ns[I18N, 'name']
+        except KeyError:
+            NAME = skip
+        else:
+            if not clause.strip():
+                NAME = skip
+            else:
+                NAME = partial(nodes.Name, clause)
+
+        # The "slot" node next is the first node level that can serve
+        # as a macro slot
+        slot = wrap(
+            inner,
+            DEFINE_SLOT,
+            DEFINE,
+            CASE,
+            CONDITION,
+            REPEAT,
+            SWITCH,
+            DOMAIN,
+            )
+
+        # metal:fill-slot
+        try:
+            clause = ns[METAL, 'fill-slot']
+        except KeyError:
+            pass
+        else:
+            index = -(1 + int(bool(use_macro or extend_macro)))
+
+            try:
+                slots = self._use_macro[index]
+            except IndexError:
+                raise LanguageError(
+                    "Cannot use metal:fill-slot without metal:use-macro.",
+                    clause
+                    )
+
+            slots = self._use_macro[index]
+            slots.append(nodes.FillSlot(clause, slot))
+
+        # metal:define-macro
+        try:
+            clause = ns[METAL, 'define-macro']
+        except KeyError:
+            pass
+        else:
+            self._macros[clause] = slot
+            slot = nodes.UseInternalMacro(clause)
+
+        slot = wrap(
+            slot,
+            NAME
+            )
+
+        # tal:on-error
+        try:
+            clause = ns[TAL, 'on-error']
+        except KeyError:
+            ON_ERROR = skip
+        else:
+            key, value = tal.parse_substitution(clause)
+            translate = True if ns.get((I18N, 'translate')) == '' else False
+
+            fallback = self._make_content_node(value, None, key, translate)
+
+            if omit is False and start['namespace'] not in self.DROP_NS:
+                start_tag = copy(start_tag)
+
+                start_tag.attributes = filter(
+                    lambda attribute: isinstance(attribute, nodes.Attribute) and \
+                                      isinstance(attribute.expression, ast.Str),
+                    start_tag.attributes
+                    )
+
+                if end_tag is None:
+                    # Make sure start-tag has opening suffix. We don't
+                    # allow self-closing element here.
+                    start_tag.suffix  = ">"
+
+                    # Explicitly set end-tag.
+                    end_tag = nodes.End(start_tag.name, '', '</', '>',)
+
+                fallback = nodes.Element(
+                    start_tag,
+                    end_tag,
+                    fallback,
+                )
+
+            ON_ERROR = partial(nodes.OnError, fallback, 'error')
+
+        clause = ns.get((META, 'interpolation'))
+        if clause in ('false', 'off'):
+            INTERPOLATION = False
+        elif clause in ('true', 'on'):
+            INTERPOLATION = True
+        elif clause is None:
+            INTERPOLATION = self._interpolation[-1]
+        else:
+            raise LanguageError("Bad interpolation setting.", clause)
+
+        self._interpolation.append(INTERPOLATION)
+
+        # Visit content body
+        for child in children:
+            body.append(self.visit(*child))
+
+        self._switches.pop()
+        self._interpolation.pop()
+
+        if use_macro:
+            self._use_macro.pop()
+
+        return wrap(
+            slot,
+            ON_ERROR
+            )
+
+    def visit_start_tag(self, start):
+        return self.visit_element(start, None, [])
+
+    def visit_cdata(self, node):
+        if not self._interpolation[-1] or not '${' in node:
+            return nodes.Text(node)
+
+        expr = nodes.Substitution(node, ())
+        return nodes.Interpolation(expr, True, False)
+
+    def visit_comment(self, node):
+        if node.startswith('<!--!'):
+            return
+
+        if node.startswith('<!--?'):
+            return nodes.Text('<!--' + node.lstrip('<!-?'))
+
+        if not self._interpolation[-1] or not '${' in node:
+            return nodes.Text(node)
+
+        char_escape = ('&', '<', '>') if self.escape else ()
+        expression = nodes.Substitution(node[4:-3], char_escape)
+
+        return nodes.Sequence(
+            [nodes.Text(node[:4]),
+             nodes.Interpolation(expression, True, False),
+             nodes.Text(node[-3:])
+             ])
+
+    def visit_processing_instruction(self, node):
+        if node['name'] != 'python':
+            text = '<?' + node['name'] + node['text'] + '?>'
+            return self.visit_text(text)
+
+        return nodes.CodeBlock(node['text'])
+
+    def visit_text(self, node):
+        self._last = node
+
+        translation = self.implicit_i18n_translate
+
+        if self._interpolation[-1] and '${' in node:
+            char_escape = ('&', '<', '>') if self.escape else ()
+            expression = nodes.Substitution(node, char_escape)
+            return nodes.Interpolation(expression, True, translation)
+
+        if not translation:
+            return nodes.Text(node)
+
+        seq = []
+        while node:
+            m = re.search('\s+', node)
+            if m is not None:
+                s = m.start()
+                if s:
+                    t = node[:s]
+                    seq.append(nodes.Translate(t, nodes.Text(t)))
+
+                e = m.end()
+                whitespace = nodes.Text(node[s:e])
+                seq.append(whitespace)
+
+                if e < len(node):
+                    node = node[e:]
+                    continue
+
+            else:
+                seq.append(nodes.Translate(node, nodes.Text(node)))
+
+            break
+
+        return nodes.Sequence(seq)
+
+    def _pop_defaults(self, kwargs, *attributes):
+        for attribute in attributes:
+            default = getattr(self, attribute)
+            value = kwargs.pop(attribute, default)
+            setattr(self, attribute, value)
+
+    def _check_attributes(self, namespace, ns):
+        if namespace in self.DROP_NS and ns.get((TAL, 'attributes')):
+            raise LanguageError(
+                "Dynamic attributes not allowed on elements of "
+                "the namespace: %s." % namespace,
+                ns[TAL, 'attributes'],
+                )
+
+        script = ns.get((TAL, 'script'))
+        if script is not None:
+            raise LanguageError(
+                "The script attribute is unsupported.", script)
+
+        tal_content = ns.get((TAL, 'content'))
+        if tal_content and ns.get((TAL, 'replace')):
+            raise LanguageError(
+                "You cannot use tal:content and tal:replace at the same time.",
+                tal_content
+                )
+
+        if tal_content and ns.get((I18N, 'translate')):
+            raise LanguageError(
+                "You cannot use tal:content with non-trivial i18n:translate.",
+                tal_content
+                )
+
+    def _make_content_node(self, expression, default, key, translate):
+        value = nodes.Value(expression)
+        char_escape = ('&', '<', '>') if key == 'text' else ()
+        content = nodes.Content(value, char_escape, translate)
+
+        if default is not None:
+            content = nodes.Condition(
+                nodes.Identity(value, marker("default")),
+                default,
+                content,
+                )
+
+            # Cache expression to avoid duplicate evaluation
+            content = nodes.Cache([value], content)
+
+            # Define local marker "default"
+            content = nodes.Define(
+                [nodes.Alias(["default"], marker("default"))],
+                content
+                )
+
+        return content
+
+    def _create_attributes_nodes(self, prepared, I18N_ATTRIBUTES):
+        attributes = []
+
+        for name, text, quote, space, eq, expr in prepared:
+            implicit_i18n = name.lower() in self.implicit_i18n_attributes
+
+            char_escape = ('&', '<', '>', quote)
+
+            # Use a provided default text as the default marker
+            # (aliased to the name ``default``), otherwise use the
+            # program's default marker value.
+            if text is not None:
+                default_marker = ast.Str(s=text)
+            else:
+                default_marker = self.default_marker
+
+            msgid = I18N_ATTRIBUTES.get(name, missing)
+
+            # If (by heuristic) ``text`` contains one or more
+            # interpolation expressions, apply interpolation
+            # substitution to the text
+            if expr is None and text is not None and '${' in text:
+                expr = nodes.Substitution(text, char_escape, None)
+                translation = implicit_i18n and msgid is missing
+                value = nodes.Interpolation(expr, True, translation)
+                default_marker = self.default_marker
+
+            # If the expression is non-trivial, the attribute is
+            # dynamic (computed).
+            elif expr is not None:
+                if name in self.boolean_attributes:
+                    value = nodes.Boolean(expr, name)
+                else:
+                    if text is not None:
+                        default = default_marker
+                    else:
+                        default = None
+
+                    value = nodes.Substitution(expr, char_escape, default)
+
+            # Otherwise, it's a static attribute.
+            else:
+                value = ast.Str(s=text)
+                if msgid is missing and implicit_i18n:
+                    msgid = text
+
+            # If translation is required, wrap in a translation
+            # clause
+            if msgid is not missing:
+                value = nodes.Translate(msgid, value)
+
+            space = self._maybe_trim(space)
+            attribute = nodes.Attribute(name, value, quote, eq, space)
+
+            if not isinstance(value, ast.Str):
+                # Always define a ``default`` alias for non-static
+                # expressions.
+                attribute = nodes.Define(
+                    [nodes.Alias(["default"], default_marker)],
+                    attribute,
+                    )
+
+            attributes.append(attribute)
+
+        return attributes
+
+    def _create_static_attributes(self, prepared):
+        static_attrs = {}
+
+        for name, text, quote, space, eq, expr in prepared:
+            static_attrs[name] = text if text is not None else expr
+
+        return Static(parse(repr(static_attrs)).body)
+
+    def _maybe_trim(self, string):
+        if self.trim_attribute_space:
+            return re_trim.sub(" ", string)
+
+        return string
diff --git a/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py b/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/chameleon/zpt/template.py
@@ -0,0 +1,409 @@
+try:
+    import ast
+except ImportError:
+    from chameleon import ast24 as ast
+
+from functools import partial
+from os.path import dirname
+
+from ..i18n import fast_translate
+from ..tales import PythonExpr
+from ..tales import StringExpr
+from ..tales import NotExpr
+from ..tales import ExistsExpr
+from ..tales import ImportExpr
+from ..tales import ProxyExpr
+from ..tales import StructureExpr
+from ..tales import ExpressionParser
+
+from ..tal import RepeatDict
+
+from ..template import BaseTemplate
+from ..template import BaseTemplateFile
+from ..compiler import ExpressionEngine
+from ..loader import TemplateLoader
+from ..astutil import Builtin
+from ..utils import decode_string
+from ..utils import string_type
+
+from .program import MacroProgram
+
+try:
+    bytes
+except NameError:
+    bytes = str
+
+
+class PageTemplate(BaseTemplate):
+    """Constructor for the page template language.
+
+    Takes a string input as the only positional argument::
+
+      template = PageTemplate("<div>Hello, ${name}.</div>")
+
+    Configuration (keyword arguments):
+
+      ``default_expression``
+
+        Set the default expression type. The default setting is
+        ``python``.
+
+      ``encoding``
+
+        The default text substitution value is a unicode string on
+        Python 2 or simply string on Python 3.
+
+        Pass an encoding to allow encoded byte string input
+        (e.g. UTF-8).
+
+      ``literal_false``
+
+        Attributes are not dropped for a value of ``False``. Instead,
+        the value is coerced to a string.
+
+        This setting exists to provide compatibility with the
+        reference implementation.
+
+      ``boolean_attributes``
+
+        Attributes included in this set are treated as booleans: if a
+        true value is provided, the attribute value is the attribute
+        name, e.g.::
+
+            boolean_attributes = {"selected"}
+
+        If we insert an attribute with the name "selected" and
+        provide a true value, the attribute will be rendered::
+
+            selected="selected"
+
+        If a false attribute is provided (including the empty string),
+        the attribute is dropped.
+
+        The special return value ``default`` drops or inserts the
+        attribute based on the value element attribute value.
+
+      ``translate``
+
+        Use this option to set a translation function.
+
+        Example::
+
+          def translate(msgid, domain=None, mapping=None, default=None, context=None):
+              ...
+              return translation
+
+        Note that if ``target_language`` is provided at render time,
+        the translation function must support this argument.
+
+      ``implicit_i18n_translate``
+
+        Enables implicit translation for text appearing inside
+        elements. Default setting is ``False``.
+
+        While implicit translation does work for text that includes
+        expression interpolation, each expression must be simply a
+        variable name (e.g. ``${foo}``); otherwise, the text will not
+        be marked for translation.
+
+      ``implicit_i18n_attributes``
+
+        Any attribute contained in this set will be marked for
+        implicit translation. Each entry must be a lowercase string.
+
+        Example::
+
+          implicit_i18n_attributes = set(['alt', 'title'])
+
+      ``strict``
+
+        Enabled by default. If disabled, expressions are only required
+        to be valid at evaluation time.
+
+        This setting exists to provide compatibility with the
+        reference implementation which compiles expressions at
+        evaluation time.
+
+      ``trim_attribute_space``
+
+        If set, additional attribute whitespace will be stripped.
+
+    Output is unicode on Python 2 and string on Python 3.
+    """
+
+    expression_types = {
+        'python': PythonExpr,
+        'string': StringExpr,
+        'not': NotExpr,
+        'exists': ExistsExpr,
+        'import': ImportExpr,
+        'structure': StructureExpr,
+        }
+
+    default_expression = 'python'
+
+    translate = staticmethod(fast_translate)
+
+    encoding = None
+
+    boolean_attributes = set()
+
+    literal_false = False
+
+    mode = "xml"
+
+    implicit_i18n_translate = False
+
+    implicit_i18n_attributes = set()
+
+    trim_attribute_space = False
+
+    def __init__(self, body, **config):
+        self.macros = Macros(self)
+        super(PageTemplate, self).__init__(body, **config)
+
+    def __getitem__(self, name):
+        return self.macros[name]
+
+    @property
+    def builtins(self):
+        return self._builtins()
+
+    @property
+    def engine(self):
+        if self.literal_false:
+            default_marker = ast.Str(s="__default__")
+        else:
+            default_marker = Builtin("False")
+
+        return partial(
+            ExpressionEngine,
+            self.expression_parser,
+            default_marker=default_marker,
+            )
+
+    @property
+    def expression_parser(self):
+        return ExpressionParser(self.expression_types, self.default_expression)
+
+    def parse(self, body):
+        if self.literal_false:
+            default_marker = ast.Str(s="__default__")
+        else:
+            default_marker = Builtin("False")
+
+        return MacroProgram(
+            body, self.mode, self.filename,
+            escape=True if self.mode == "xml" else False,
+            default_marker=default_marker,
+            boolean_attributes=self.boolean_attributes,
+            implicit_i18n_translate=self.implicit_i18n_translate,
+            implicit_i18n_attributes=self.implicit_i18n_attributes,
+            trim_attribute_space=self.trim_attribute_space,
+            )
+
+    def render(self, encoding=None, translate=None, **vars):
+        """Render template to string.
+
+        The ``encoding`` and ``translate`` arguments are documented in
+        the template class constructor. If passed to this method, they
+        are used instead of the class defaults.
+
+        Additional arguments:
+
+          ``target_language``
+
+            This argument will be partially applied to the translation
+            function.
+
+            An alternative is thus to simply provide a custom
+            translation function which includes this information or
+            relies on a different mechanism.
+
+        """
+
+        non_trivial_translate = translate is not None
+        translate = translate if non_trivial_translate else self.translate or \
+                    type(self).translate
+
+        # Curry language parameter if non-trivial
+        target_language = vars.get('target_language')
+        if target_language is not None:
+            translate = partial(translate, target_language=target_language)
+
+        encoding = encoding if encoding is not None else self.encoding
+        if encoding is not None:
+            txl = translate
+
+            def translate(msgid, **kwargs):
+                if isinstance(msgid, bytes):
+                    msgid = decode_string(msgid, encoding)
+                return txl(msgid, **kwargs)
+
+            def decode(inst):
+                return decode_string(inst, encoding, 'ignore')
+        else:
+            decode = decode_string
+
+        setdefault = vars.setdefault
+        setdefault("__translate", translate)
+        setdefault("__convert", translate)
+        setdefault("__decode", decode)
+
+        if non_trivial_translate:
+            vars['translate'] = translate
+
+        # Make sure we have a repeat dictionary
+        if 'repeat' not in vars: vars['repeat'] = RepeatDict({})
+
+        return super(PageTemplate, self).render(**vars)
+
+    def include(self, *args, **kwargs):
+        self.cook_check()
+        self._render(*args, **kwargs)
+
+    def _builtins(self):
+        return {
+            'template': self,
+            'macros': self.macros,
+            'nothing': None,
+            }
+
+
+class PageTemplateFile(PageTemplate, BaseTemplateFile):
+    """File-based constructor.
+
+    Takes a string input as the only positional argument::
+
+      template = PageTemplateFile(absolute_path)
+
+    Note that the file-based template class comes with the expression
+    type ``load`` which loads templates relative to the provided
+    filename.
+
+    Below are listed the configuration arguments specific to
+    file-based templates; see the string-based template class for
+    general options and documentation:
+
+    Configuration (keyword arguments):
+
+      ``loader_class``
+
+        The provided class will be used to create the template loader
+        object. The default implementation supports relative and
+        absolute path specs.
+
+        The class must accept keyword arguments ``search_path``
+        (sequence of paths to search for relative a path spec) and
+        ``default_extension`` (if provided, this should be added to
+        any path spec).
+
+      ``prepend_relative_search_path``
+
+        Inserts the path relative to the provided template file path
+        into the template search path.
+
+        The default setting is ``True``.
+
+      ``search_path``
+
+        If provided, this is used as the search path for the ``load:``
+        expression. It must be a string or an iterable yielding a
+        sequence of strings.
+
+    """
+
+    expression_types = PageTemplate.expression_types.copy()
+    expression_types['load'] = partial(ProxyExpr, '__loader')
+
+    prepend_relative_search_path = True
+
+    def __init__(self, filename, search_path=None, loader_class=TemplateLoader,
+                 **config):
+        super(PageTemplateFile, self).__init__(filename, **config)
+
+        if search_path is None:
+            search_path = []
+        else:
+            if isinstance(search_path, string_type):
+                search_path = [search_path]
+            else:
+                search_path = list(search_path)
+
+        # If the flag is set (this is the default), prepend the path
+        # relative to the template file to the search path
+        if self.prepend_relative_search_path:
+            path = dirname(self.filename)
+            search_path.insert(0, path)
+
+        loader = loader_class(search_path=search_path, **config)
+        template_class = type(self)
+
+        # Bind relative template loader instance to the same template
+        # class, providing the same keyword arguments.
+        self._loader = loader.bind(template_class)
+
+    def _builtins(self):
+        d = super(PageTemplateFile, self)._builtins()
+        d['__loader'] = self._loader
+        return d
+
+
+class PageTextTemplate(PageTemplate):
+    """Text-based template class.
+
+    Takes a non-XML input::
+
+      template = PageTextTemplate("Hello, ${name}.")
+
+    This is similar to the standard library class ``string.Template``,
+    but uses the expression engine to substitute variables.
+    """
+
+    mode = "text"
+
+
+class PageTextTemplateFile(PageTemplateFile):
+    """File-based constructor."""
+
+    mode = "text"
+
+    def render(self, **vars):
+        result = super(PageTextTemplateFile, self).render(**vars)
+        return result.encode(self.encoding or 'utf-8')
+
+
+class Macro(object):
+    __slots__ = "include",
+
+    def __init__(self, render):
+        self.include = render
+
+
+class Macros(object):
+    __slots__ = "template",
+
+    def __init__(self, template):
+        self.template = template
+
+    def __getitem__(self, name):
+        name = name.replace('-', '_')
+        self.template.cook_check()
+
+        try:
+            function = getattr(self.template, "_render_%s" % name)
+        except AttributeError:
+            raise KeyError(
+                "Macro does not exist: '%s'." % name)
+
+        return Macro(function)
+
+    @property
+    def names(self):
+        self.template.cook_check()
+
+        result = []
+        for name in self.template.__dict__:
+            if name.startswith('_render_'):
+                result.append(name[8:])
+        return result
diff --git a/lib/Chameleon-2.9.2/src/ordereddict.py b/lib/Chameleon-2.9.2/src/ordereddict.py
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/src/ordereddict.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# 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.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__end
+        except AttributeError:
+            self.clear()
+        self.update(*args, **kwds)
+
+    def clear(self):
+        self.__end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.__map = {}                 # key --> [key, prev, next]
+        dict.clear(self)
+
+    def __setitem__(self, key, value):
+        if key not in self:
+            end = self.__end
+            curr = end[1]
+            curr[2] = end[1] = self.__map[key] = [key, curr, end]
+        dict.__setitem__(self, key, value)
+
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        key, prev, next = self.__map.pop(key)
+        prev[2] = next
+        next[1] = prev
+
+    def __iter__(self):
+        end = self.__end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.__end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def popitem(self, last=True):
+        if not self:
+            raise KeyError('dictionary is empty')
+        if last:
+            key = reversed(self).next()
+        else:
+            key = iter(self).next()
+        value = self.pop(key)
+        return key, value
+
+    def __reduce__(self):
+        items = [[k, self[k]] for k in self]
+        tmp = self.__map, self.__end
+        del self.__map, self.__end
+        inst_dict = vars(self).copy()
+        self.__map, self.__end = tmp
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def keys(self):
+        return list(self)
+
+    setdefault = DictMixin.setdefault
+    update = DictMixin.update
+    pop = DictMixin.pop
+    values = DictMixin.values
+    items = DictMixin.items
+    iterkeys = DictMixin.iterkeys
+    itervalues = DictMixin.itervalues
+    iteritems = DictMixin.iteritems
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, self.items())
+
+    def copy(self):
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedDict):
+            if len(self) != len(other):
+                return False
+            for p, q in  zip(self.items(), other.items()):
+                if p != q:
+                    return False
+            return True
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other
diff --git a/lib/Chameleon-2.9.2/tox.ini b/lib/Chameleon-2.9.2/tox.ini
new file mode 100644
--- /dev/null
+++ b/lib/Chameleon-2.9.2/tox.ini
@@ -0,0 +1,53 @@
+[tox]
+envlist = 
+    py25,py26,py27,py32,pypy,cover
+
+[testenv:py25]
+commands = 
+   python setup.py test -q
+deps = 
+    ordereddict
+    unittest2
+    distribute
+
+[testenv:py26]
+commands = 
+   python setup.py test -q
+deps = 
+    ordereddict
+    unittest2
+    distribute
+
+[testenv:py27]
+commands = 
+   python setup.py test -q
+deps = 
+    distribute
+
+[testenv:py32]
+commands = 
+   python setup.py test -q
+deps = 
+    distribute
+
+[testenv:pypy]
+commands = 
+   python setup.py test -q
+deps = 
+    ordereddict
+    unittest2
+    distribute
+
+[testenv:cover]
+basepython =
+    python2.6
+commands = 
+    python setup.py nosetests --with-xunit --with-xcoverage
+deps =
+    nose
+    coverage==3.4
+    nosexcover
+    ordereddict
+    unittest2
+    distribute
+
diff --git a/make_perf3.sh b/make_perf3.sh
--- a/make_perf3.sh
+++ b/make_perf3.sh
@@ -31,9 +31,12 @@
 ${CONVERT} perf.py
 
 # Libraries that are Python 3 compatible as-is.
-SAFE_LIBS_AS_IS="pathlib"
+SAFE_LIBS_AS_IS="Chameleon-2.9.2 pathlib"
 # Libraries that work with Python 3 after passing through 2to3.
 SAFE_LIBS_TO_TRANSLATE="2to3 mako-0.3.6 mako-0.7.2"
+# Libraries whose source is Python 3 only.
+SAFE_LIBS_PORTED=""
+
 mkdir lib
 for safe_lib in ${SAFE_LIBS_AS_IS}; do
   cp -a "${srcdir}/lib/${safe_lib}" lib/${safe_lib}
@@ -44,6 +47,10 @@
   ${CONVERT} lib/${safe_lib}
 done
 
+for safe_lib in ${SAFE_LIBS_PORTED}; do
+  cp -a "${srcdir}/lib3/${safe_lib}" lib/${safe_lib}
+done
+
 cp -a "${srcdir}/performance" performance
 
 # The 2to3 benchmark looks for sample data to run over behind the
diff --git a/perf.py b/perf.py
--- a/perf.py
+++ b/perf.py
@@ -1329,6 +1329,17 @@
     return SimpleBenchmark(MeasureBzrStartup, *args, **kwargs)
 
 
+def MeasureChameleon(python, options):
+    bm_path = Relative("performance/bm_chameleon.py", python, options)
+    lib_path = Relative("lib/Chameleon-2.9.2/src", python, options)
+    bm_env = {"PYTHONPATH": lib_path}
+    return MeasureGeneric(python, options, bm_path, bm_env, iteration_scaling=3)
+
+
+def BM_Chameleon(*args, **kwargs):
+    return SimpleBenchmark(MeasureChameleon, *args, **kwargs)
+
+
 DJANGO_DIR = Relative("lib/django")
 
 
@@ -2082,7 +2093,8 @@
                 "serialize": ["slowpickle", "slowunpickle",  # Not for Python 3
                               "fastpickle", "fastunpickle",
                               "json_dump_v2", "json_load"],
-                "apps": ["2to3", "html5lib", "rietveld", "spambayes"],
+                "apps": ["2to3", "chameleon", "html5lib", "rietveld",
+                         "spambayes"],
                 "calls": ["call_simple", "call_method", "call_method_slots",
                           "call_method_unknown"],
                 "math": ["float", "nbody", "pidigits"],
@@ -2090,7 +2102,7 @@
                 "logging": ["silent_logging", "simple_logging",
                             "formatted_logging"],
                 # Benchmarks natively 2.x- and 3.x-compatible
-                "2n3": ["calls", "chaos", "fannkuch", "fastpickle",
+                "2n3": ["calls", "chameleon", "chaos", "fannkuch", "fastpickle",
                         "fastunpickle", "go", "hexiom2", "json_dump_v2",
                         "json_load", "math", "logging", "meteor_contest",
                         "normal_startup", "nqueens", "pathlib", "raytrace",
diff --git a/performance/bm_chameleon.py b/performance/bm_chameleon.py
new file mode 100644
--- /dev/null
+++ b/performance/bm_chameleon.py
@@ -0,0 +1,40 @@
+
+from chameleon import PageTemplate
+
+import compat
+
+BIGTABLE_ZPT = """\
+<table xmlns="http://www.w3.org/1999/xhtml"
+xmlns:tal="http://xml.zope.org/namespaces/tal">
+<tr tal:repeat="row python: options['table']">
+<td tal:repeat="c python: row.values()">
+<span tal:define="d python: c + 1"
+tal:attributes="class python: 'column-' + %s(d)"
+tal:content="python: d" />
+</td>
+</tr>
+</table>""" % compat.unicode.__name__
+
+def main(n):
+    tmpl = PageTemplate(BIGTABLE_ZPT)
+    options = {'table': [dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10)
+                         for x in range(1000)]}
+    import time
+    l = []
+    for k in range(n):
+        t0 = time.time()
+        tmpl(options=options)
+        l.append(time.time() - t0)
+    return l
+
+if __name__ == '__main__':
+    import util, optparse
+    parser = optparse.OptionParser(
+        usage="%prog [options]",
+        description="Test the performance of the Go benchmark")
+    util.add_standard_options_to(parser)
+    options, args = parser.parse_args()
+
+    util.run_benchmark(options, options.num_runs, main)
+
+

-- 
Repository URL: http://hg.python.org/benchmarks


More information about the Python-checkins mailing list