fa1f7726b08b
Merge.
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Mon, 18 Jul 2011 13:22:12 -0400 |
| parents | 543110450d50 (current diff) 48541d29e527 (diff) |
| children | 78819a1b530e |
| branches/tags | (none) |
| files | bundled/flask/flask.py kick review/api.py review/static/aal.css review/static/bg.png review/static/colorbox/colorbox.css review/static/colorbox/images/border.png review/static/colorbox/images/controls.png review/static/colorbox/images/internet_explorer/borderBottomCenter.png review/static/colorbox/images/internet_explorer/borderBottomLeft.png review/static/colorbox/images/internet_explorer/borderBottomRight.png review/static/colorbox/images/internet_explorer/borderMiddleLeft.png review/static/colorbox/images/internet_explorer/borderMiddleRight.png review/static/colorbox/images/internet_explorer/borderTopCenter.png review/static/colorbox/images/internet_explorer/borderTopLeft.png review/static/colorbox/images/internet_explorer/borderTopRight.png review/static/colorbox/images/loading.gif review/static/colorbox/images/loading_background.png review/static/colorbox/images/overlay.png review/static/colorbox/jquery.colorbox.js review/static/comments.js review/static/extra.css review/static/jquery-1.4.2.min.js review/static/jquery.infieldlabel.min.js review/static/style.css review/static/style.less review/static/ui.js review/static/underscore.min.js |
Changes
--- a/.hgignore Mon Jul 18 13:21:39 2011 -0400 +++ b/.hgignore Mon Jul 18 13:22:12 2011 -0400 @@ -9,3 +9,4 @@ *.swp *.log docs/_build +*.un~
--- a/README.markdown Mon Jul 18 13:21:39 2011 -0400 +++ b/README.markdown Mon Jul 18 13:22:12 2011 -0400 @@ -1,9 +1,5 @@ -hg-review is close to being released! -===================================== - -Feedback is appreciated, but things may still break before v1.0.0! -================================================================== - +hg-review is still beta! Things may break! +=========================================== Installing ========== @@ -46,4 +42,10 @@ Check out the [documentation][docs] to learn more. +If you've still got questions, there's a mailing list (hosted by +[Librelist][]). Send an email (no subject/body necessary) to +[hg.review@librelist.com][ml] to subscribe. + [docs]: http://sjl.bitbucket.org/hg-review/ +[Librelist]: http://librelist.com/ +[ml]: mailto:hg.review@librelist.com
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/.gitignore Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,10 @@ +.DS_Store +*.pyc +*.pyo +env +env* +dist +*.egg +*.egg-info +_mailinglist +.tox
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/.gitmodules Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,3 @@ +[submodule "docs/_themes"] + path = docs/_themes + url = git://github.com/mitsuhiko/flask-sphinx-themes.git
--- a/bundled/flask/AUTHORS Mon Jul 18 13:21:39 2011 -0400 +++ b/bundled/flask/AUTHORS Mon Jul 18 13:22:12 2011 -0400 @@ -9,16 +9,22 @@ Patches and Suggestions ``````````````````````` +- Adam Zapletal +- Ali Afshar - Chris Edgemon - Chris Grindstaff +- Christopher Grebs - Florent Xicluna - Georg Brandl - Justin Quick - Kenneth Reitz - Marian Sigler +- Matt Campell - Matthew Frazier +- Michael van Tellingen - Ron DuPlain - Sebastien Estienne - Simon Sapin - Stephane Wirtel +- Thomas Schranz - Zhao Xiaohong
--- a/bundled/flask/CHANGES Mon Jul 18 13:21:39 2011 -0400 +++ b/bundled/flask/CHANGES Mon Jul 18 13:22:12 2011 -0400 @@ -3,10 +3,134 @@ Here you can see the full list of changes between each Flask release. +Version 0.7 +----------- + +Release date to be announced, codename to be selected + +- Added :meth:`~flask.Flask.make_default_options_response` + which can be used by subclasses to alter the default + behaviour for `OPTIONS` responses. +- Unbound locals now raise a proper :exc:`RuntimeError` instead + of an :exc:`AttributeError`. +- Mimetype guessing and etag support based on file objects is now + deprecated for :func:`flask.send_file` because it was unreliable. + Pass filenames instead or attach your own etags and provide a + proper mimetype by hand. +- Static file handling for modules now requires the name of the + static folder to be supplied explicitly. The previous autodetection + was not reliable and caused issues on Google's App Engine. Until + 1.0 the old behaviour will continue to work but issue dependency + warnings. +- fixed a problem for Flask to run on jython. +- added a `PROPAGATE_EXCEPTIONS` configuration variable that can be + used to flip the setting of exception propagation which previously + was linked to `DEBUG` alone and is now linked to either `DEBUG` or + `TESTING`. +- Flask no longer internally depends on rules being added through the + `add_url_rule` function and can now also accept regular werkzeug + rules added to the url map. +- Added an `endpoint` method to the flask application object which + allows one to register a callback to an arbitrary endpoint with + a decorator. + +Version 0.6.1 +------------- + +Bugfix release, released on December 31st 2010 + +- Fixed an issue where the default `OPTIONS` response was + not exposing all valid methods in the `Allow` header. +- Jinja2 template loading syntax now allows "./" in front of + a template load path. Previously this caused issues with + module setups. +- Fixed an issue where the subdomain setting for modules was + ignored for the static folder. +- Fixed a security problem that allowed clients to download arbitrary files + if the host server was a windows based operating system and the client + uses backslashes to escape the directory the files where exposed from. + +Version 0.6 +----------- + +Released on July 27th 2010, codename Whisky + +- after request functions are now called in reverse order of + registration. +- OPTIONS is now automatically implemented by Flask unless the + application explicitly adds 'OPTIONS' as method to the URL rule. + In this case no automatic OPTIONS handling kicks in. +- static rules are now even in place if there is no static folder + for the module. This was implemented to aid GAE which will + remove the static folder if it's part of a mapping in the .yml + file. +- the :attr:`~flask.Flask.config` is now available in the templates + as `config`. +- context processors will no longer override values passed directly + to the render function. +- added the ability to limit the incoming request data with the + new ``MAX_CONTENT_LENGTH`` configuration value. +- the endpoint for the :meth:`flask.Module.add_url_rule` method + is now optional to be consistent with the function of the + same name on the application object. +- added a :func:`flask.make_response` function that simplifies + creating response object instances in views. +- added signalling support based on blinker. This feature is currently + optional and supposed to be used by extensions and applications. If + you want to use it, make sure to have `blinker`_ installed. +- refactored the way URL adapters are created. This process is now + fully customizable with the :meth:`~flask.Flask.create_url_adapter` + method. +- modules can now register for a subdomain instead of just an URL + prefix. This makes it possible to bind a whole module to a + configurable subdomain. + +.. _blinker: http://pypi.python.org/pypi/blinker + +Version 0.5.2 +------------- + +Bugfix Release, released on July 15th 2010 + +- fixed another issue with loading templates from directories when + modules were used. + +Version 0.5.1 +------------- + +Bugfix Release, released on July 6th 2010 + +- fixes an issue with template loading from directories when modules + where used. + +Version 0.5 +----------- + +Released on July 6th 2010, codename Calvados + +- fixed a bug with subdomains that was caused by the inability to + specify the server name. The server name can now be set with + the `SERVER_NAME` config key. This key is now also used to set + the session cookie cross-subdomain wide. +- autoescaping is no longer active for all templates. Instead it + is only active for ``.html``, ``.htm``, ``.xml`` and ``.xhtml``. + Inside templates this behaviour can be changed with the + ``autoescape`` tag. +- refactored Flask internally. It now consists of more than a + single file. +- :func:`flask.send_file` now emits etags and has the ability to + do conditional responses builtin. +- (temporarily) dropped support for zipped applications. This was a + rarely used feature and led to some confusing behaviour. +- added support for per-package template and static-file directories. +- removed support for `create_jinja_loader` which is no longer used + in 0.5 due to the improved module support. +- added a helper function to expose files from any directory. + Version 0.4 ----------- -Release date to be announced, codename to be selected. +Released on June 18th 2010, codename Rakia - added the ability to register application wide error handlers from modules. @@ -19,11 +143,12 @@ - because the Python standard library caches loggers, the name of the logger is configurable now to better support unittests. - added `TESTING` switch that can activate unittesting helpers. +- the logger switches to `DEBUG` mode now if debug is enabled. Version 0.3.1 ------------- -Bugfix release, released May 28th +Bugfix release, released on May 28th 2010 - fixed a error reporting bug with :meth:`flask.Config.from_envvar` - removed some unused code from flask @@ -34,7 +159,7 @@ Version 0.3 ----------- -Released on May 28th, codename Schnaps +Released on May 28th 2010, codename Schnaps - added support for categories for flashed messages. - the application now configures a :class:`logging.Handler` and will @@ -50,7 +175,7 @@ Version 0.2 ----------- -Released on May 12th, codename Jägermeister +Released on May 12th 2010, codename Jägermeister - various bugfixes - integrated JSON support
--- a/bundled/flask/LICENSE Mon Jul 18 13:21:39 2011 -0400 +++ b/bundled/flask/LICENSE Mon Jul 18 13:22:12 2011 -0400 @@ -3,9 +3,9 @@ Some rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +Redistribution and use in source and binary forms of the software as well +as documentation, with or without modification, are permitted provided +that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -19,14 +19,15 @@ promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -OWNER OR CONTRIBUTORS 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. +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "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 COPYRIGHT OWNER +OR CONTRIBUTORS 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE.
--- a/bundled/flask/MANIFEST.in Mon Jul 18 13:21:39 2011 -0400 +++ b/bundled/flask/MANIFEST.in Mon Jul 18 13:22:12 2011 -0400 @@ -1,9 +1,12 @@ include Makefile CHANGES LICENSE AUTHORS +recursive-include artwork * recursive-include tests * recursive-include examples * recursive-include docs * recursive-exclude docs *.pyc recursive-exclude docs *.pyo +recursive-exclude tests *.pyc +recursive-exclude tests *.pyo recursive-exclude examples *.pyc recursive-exclude examples *.pyo prune docs/_build
--- a/bundled/flask/Makefile Mon Jul 18 13:21:39 2011 -0400 +++ b/bundled/flask/Makefile Mon Jul 18 13:22:12 2011 -0400 @@ -1,10 +1,19 @@ -.PHONY: clean-pyc test upload-docs +.PHONY: clean-pyc ext-test test upload-docs docs audit all: clean-pyc test test: python setup.py test +audit: + python setup.py audit + +tox-test: + PYTHONDONTWRITEBYTECODE= tox + +ext-test: + python tests/flaskext_test.py --browse + release: python setup.py release sdist upload @@ -20,3 +29,6 @@ scp -r docs/_build/dirhtml/* pocoo.org:/var/www/flask.pocoo.org/docs/ scp -r docs/_build/latex/Flask.pdf pocoo.org:/var/www/flask.pocoo.org/docs/flask-docs.pdf scp -r docs/_build/flask-docs.zip pocoo.org:/var/www/flask.pocoo.org/docs/ + +docs: + $(MAKE) -C docs html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/artwork/LICENSE Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,20 @@ +Copyright (c) 2010 by Armin Ronacher. + +Some rights reserved. + +This logo or a modified version may be used by anyone to refer to the +Flask project, but does not indicate endorsement by the project. + +Redistribution and use in source (the SVG file) and binary forms (rendered +PNG files etc.) of the image, with or without modification, are permitted +provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice and this list of conditions. + +* The names of the contributors to the Flask software (see AUTHORS) may + not be used to endorse or promote products derived from this software + without specific prior written permission. + +Note: we would appreciate that you make the image a link to +http://flask.pocoo.org/ if you use it on a web page.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/artwork/logo-full.svg Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,290 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="460" + height="180" + id="svg2" + version="1.1" + inkscape:version="0.47 r22583" + sodipodi:docname="logo.svg"> + <defs + id="defs4"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <inkscape:perspective + id="perspective2824" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2840" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2878" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2894" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2910" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2926" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2976" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3020" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3036" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3052" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3866" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.98994949" + inkscape:cx="240.32415" + inkscape:cy="-37.836532" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1680" + inkscape:window-height="998" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-27.820801,-24.714976)"> + <path + style="fill:#000000" + d="M 96.944917,182.03377 C 89.662681,176.30608 81.894549,170.81448 76.586317,163.08166 65.416842,149.44499 56.816875,133.6567 50.937585,117.06515 47.383955,106.27654 46.166898,94.709824 41.585799,84.338096 c -4.792287,-7.533044 0.821224,-15.767897 9.072722,-18.16242 3.673742,-0.705104 10.133327,-4.170258 2.335951,-1.693539 -6.990592,5.128871 -7.667129,-4.655603 -0.498823,-5.27517 4.892026,-0.650249 6.692895,-4.655044 5.019966,-8.260251 -5.251326,-3.424464 12.733737,-7.18801 3.684373,-12.297799 -9.426987,-10.170666 13.186339,-12.128546 7.607283,-0.577786 -1.335447,8.882061 15.801226,-1.627907 11.825117,8.628945 4.041283,4.925694 15.133562,1.1211 14.85838,8.031392 5.887092,0.404678 7.907562,5.358061 13.433992,5.738347 5.72759,2.586557 16.1108,4.624792 18.0598,11.079149 -5.68242,4.498756 -18.84089,-9.292674 -19.47305,3.160397 1.71659,18.396078 1.27926,37.346439 8.00986,54.864989 3.18353,10.60759 10.9012,18.95779 17.87109,27.21946 6.66875,8.09126 15.70186,13.78715 24.90885,18.58338 8.07647,3.80901 16.78383,6.33528 25.58583,7.92044 3.5701,-2.7307 9.87303,-12.8828 15.44238,-8.60188 0.26423,4.81007 -11.0541,10.05512 -0.53248,9.5235 6.17819,-1.86378 10.46336,4.77803 15.55099,-1.21289 4.68719,5.55206 19.48197,-3.54734 16.14693,7.80115 -4.50972,2.90955 -11.08689,1.15142 -15.60404,5.15397 -7.44757,-3.71979 -13.37691,3.32843 -21.6219,2.43707 -9.15641,1.64002 -18.4716,2.30204 -27.75473,2.31642 -15.22952,-1.20328 -30.78158,-1.71049 -45.26969,-7.01291 -8.16166,-2.37161 -16.12649,-7.01887 -23.299683,-11.66829 z m 12.862043,5.5729 c 7.9696,3.44651 15.76243,7.07889 24.49656,8.17457 13.85682,1.92727 28.16653,4.89163 42.07301,2.18757 -6.2939,-2.84199 -12.80077,1.10719 -19.07096,-2.0322 -7.52033,1.61821 -15.59049,-0.41223 -23.23574,-1.41189 -8.69395,-3.87259 -18.0762,-6.53549 -26.21772,-11.56219 -10.173155,-3.71578 5.26142,4.76524 8.00873,5.45214 6.35952,3.60969 -6.99343,-1.85044 -8.87589,-3.35101 -5.32648,-2.9879 -6.00529,-2.36357 -0.52745,0.67085 1.10332,0.64577 2.19359,1.32226 3.34946,1.87216 z M 94.642259,176.88976 c 7.722781,2.86052 -0.03406,-5.43082 -3.572941,-4.94904 -1.567906,-2.72015 -5.9903,-4.43854 -2.870721,-5.89973 -5.611524,1.9481 -5.878319,-7.40814 -8.516004,-6.07139 -5.936516,-1.87454 -2.310496,-8.51501 -9.381929,-12.59292 -0.645488,-4.29697 -7.02577,-8.02393 -9.060801,-14.50525 -0.898786,-3.31843 -7.208336,-12.84783 -3.332369,-3.97927 3.300194,8.53747 9.106618,15.84879 13.93868,23.15175 3.752083,6.95328 8.182497,14.22026 15.015767,18.55788 2.303436,2.20963 4.527452,5.59533 7.780318,6.28797 z M 72.39456,152.46355 c 0.26956,-1.16626 1.412424,2.52422 0,0 z m 31.49641,27.85526 c 1.71013,-0.76577 -2.45912,-0.96476 0,0 z m 4.19228,1.52924 c -0.43419,-2.1116 -1.91376,1.18074 0,0 z m 5.24749,2.18891 c 2.49828,-2.37871 -3.85009,-1.49983 0,0 z m 8.99389,5.01274 c 1.51811,-2.2439 -4.85872,-0.84682 0,0 z m -17.2707,-12.03933 c 3.88031,-2.51023 -5.01186,-0.0347 0,0 z m 3.9366,1.96293 c -0.11004,-1.32709 -1.40297,0.59432 0,0 z m 19.67473,12.28006 c 3.16281,1.99601 18.46961,4.3749 8.88477,0.81847 -1.60377,0.33811 -17.77263,-4.57336 -8.88477,-0.81847 z M 97.430958,166.92721 c -0.307503,-1.33094 -4.909341,-1.4694 0,0 z m 9.159302,5.33813 c 2.38371,-1.66255 -4.94757,-1.28235 0,0 z m 7.70426,4.72382 c 3.42065,-1.28963 -5.54907,-1.29571 0,0 z M 93.703927,162.86805 c 3.711374,2.84621 14.967683,0.36473 5.683776,-1.69906 -4.225516,-2.2524 -13.74889,-3.79415 -7.25757,1.35821 l 1.573785,0.34088 9e-6,-3e-5 z m 25.808723,15.75216 c 1.54595,-2.63388 -6.48298,-1.50411 0,0 z m -7.84249,-6.23284 c 9.0752,2.56719 -7.63142,-5.739 -2.23911,-0.94466 l 1.19513,0.54082 1.04399,0.4039 -1e-5,-6e-5 z m 15.72354,9.0878 c 8.59474,0.082 -7.76304,-1.18486 0,1e-5 l 0,-1e-5 z M 90.396984,157.89545 c -0.335695,-1.60094 -2.120962,0.13419 0,0 z m 51.535396,31.73502 c 0.2292,-2.89141 -2.80486,2.15157 0,0 z m -36.86817,-22.75299 c -0.51986,-1.52251 -2.68548,-0.0622 0,0 z m -13.852128,-9.98649 c 4.934237,-0.29629 -6.755322,-2.17418 0,0 z M 74.802387,146.28394 c -0.614146,-2.36536 -5.369213,-4.2519 0,0 z m 43.079323,27.33941 c -0.90373,-1.0307 -0.4251,0.22546 0,0 z m 26.81408,16.45475 c -0.086,-1.57503 -1.46039,0.59616 0,0 z m -29.18712,-18.90528 c 0.48266,-2.02932 -4.20741,-0.61442 0,0 z M 95.532612,158.51286 c 3.670785,-0.39305 -5.880434,-2.48161 0,0 z M 129.32396,179.51 c 5.72042,-2.26627 -5.57541,-1.10635 0,0 z m -17.57682,-11.93145 c 6.59278,0.85002 -7.84442,-4.48425 -1.44651,-0.4773 l 1.4465,0.47734 1e-5,-4e-5 z m 22.91296,14.0886 c 6.15514,-3.67975 4.12588,8.61677 10.44254,1.0388 6.23086,-4.54942 -5.38086,5.62451 2.29838,0.81116 5.55359,-3.71438 13.75643,1.76075 18.93848,3.5472 3.72659,-0.18307 7.34938,3.22236 11.16973,1.15059 7.3542,-1.98082 -14.38097,-2.93789 -8.68344,-6.4523 -6.72914,1.95848 -11.70093,-2.33483 -15.01213,-6.64508 -7.54812,-1.74298 -16.27548,-5.602 -20.04257,-12.28184 -1.5359,-2.50802 2.21884,0.35333 -1.32586,-3.74638 -4.54834,-4.04546 -6.81948,-8.63766 -9.87278,-13.5552 -3.64755,-1.94587 -4.07249,-7.67345 -4.44123,-0.19201 0.0289,-4.72164 -4.40393,-7.89964 -5.48589,-6.57859 -0.0194,-4.54721 4.74396,-2.26787 1.40945,-5.63228 -0.71771,-4.71302 -3.08085,-9.6241 -3.79115,-14.9453 -1.1036,-2.56502 -0.15541,-8.05863 -3.76662,-2.25204 -1.31566,6.13669 -0.43668,-7.54129 1.6093,-3.03083 2.68543,-4.60251 -0.9641,-4.0612 -1.11361,-3.42211 1.74931,-3.88333 1.10719,-9.39159 -0.45644,-7.29023 0.93213,-4.11586 1.47259,-15.147529 -1.3951,-13.192579 1.73833,-4.303958 3.29668,-19.694077 -4.24961,-13.826325 -3.058358,0.04294 -8.354541,1.110195 -10.858032,2.355243 7.849502,4.326857 -0.789543,1.562577 -3.984808,0.874879 -0.416343,4.003642 -3.58119,2.272086 -7.535123,2.311339 6.315273,0.781339 -3.075253,6.458962 -6.698132,4.253506 -4.705102,2.248756 4.060621,7.862038 0.0944,9.597586 0.487433,2.616581 -7.208227,-0.944906 -6.603832,5.097711 -4.56774,-1.92155 -0.628961,7.16796 1.656273,4.09382 7.768882,2.10261 5.469108,6.89631 5.666947,11.44992 -1.265833,2.6534 -6.249495,-6.23691 -1.109939,-5.82517 -4.054715,-6.58674 -4.485232,-2.38081 -7.854566,0.67911 -0.783857,0.22222 8.5944,4.35376 2.709059,6.3967 5.177884,0.79894 5.325199,5.33008 6.379284,8.19735 3.11219,3.24152 2.475226,-3.57931 6.199071,0.31623 -2.356488,-3.4705 -12.48183,-9.77839 -4.329567,-7.7553 -0.04358,-3.49291 -1.474412,-6.30951 1.02322,-6.24118 2.473367,-4.47926 -2.590385,11.044 2.984725,5.35124 1.543285,-0.67388 1.92554,-4.48494 4.699544,0.35989 4.029096,3.96363 1.45533,6.83577 -4.228162,3.20648 1.016828,3.44946 7.603062,4.68217 6.365348,10.07646 1.3121,4.7444 3.147844,2.99695 4.747999,2.72266 1.25523,4.60973 1.968016,1.2201 2.027559,-0.97355 5.747357,1.23033 4.401142,4.62773 6.199456,7.00134 3.960416,1.78761 -5.668696,-12.11713 1.130659,-4.18106 7.153577,6.4586 2.682797,9.15464 -3.736856,8.11995 4.063129,-0.32824 5.373423,5.49305 10.455693,5.28853 4.63456,2.20477 7.77237,10.67291 -0.21613,7.1478 -2.77074,-2.49821 -12.575734,-5.5801 -4.56731,-0.82823 7.39657,3.42523 13.27117,5.47432 20.40487,9.77384 5.10535,3.64464 7.31104,7.81908 9.24607,8.64541 -4.29084,2.04946 -12.93089,-1.63655 -6.51514,-2.76618 -4.00168,-0.72894 -8.50258,-2.75259 -4.66961,2.2333 3.25926,2.72127 11.54708,2.43298 13.0328,2.74132 -1.25934,2.77488 -3.4207,2.99556 0.0516,3.21078 -3.87375,2.06438 1.24216,2.38403 1.60114,3.56362 z m -7.9215,-22.36993 c -2.35682,-2.46475 -2.9662,-7.08134 -0.41852,-3.06426 1.30648,0.52466 4.18523,7.54428 0.41857,3.06426 l -5e-5,0 z m 25.79733,16.38693 c 1.47004,-0.0952 0.0427,1.11681 0,0 z m -29.51867,-22.43039 c -0.0904,-3.72637 0.8525,2.87419 0,0 z m -2.56392,-3.44965 c -2.96446,-5.72787 3.73721,1.62212 0,0 z M 89.382646,128.35916 c 1.7416,-0.46446 0.856841,2.97864 0,0 z m 24.728294,13.40357 c 1.06957,-4.01654 1.25692,3.37014 0,0 z M 96.64115,129.61525 c -1.231543,-2.21638 2.576009,2.07865 0,0 z m 14.99279,4.80618 c -2.80851,-6.29223 1.98836,-3.43699 0.62135,1.03124 l -0.62135,-1.03124 0,0 z M 85.778757,117.17864 c -1.255624,-2.06432 -3.332663,-8.12135 -2.663982,-9.97042 0.604935,3.0114 6.403914,12.95956 2.844571,4.12096 -3.933386,-7.40908 4.701805,2.40491 5.590052,4.2529 0.413624,1.83837 -2.426789,-0.50225 -0.502192,3.80828 -3.509809,-4.90766 -2.071967,2.71088 -5.268449,-2.21172 z m -7.990701,-5.50612 c 0.328938,-4.79981 1.829262,3.29132 0,0 z m 3.594293,1.23728 c 1.715175,-3.62282 2.908243,5.05052 0,0 z m -8.64616,-6.68847 c -2.974956,-2.95622 -5.127809,-5.68132 0.139193,-1.83474 2.029482,0.0792 -4.509002,-6.19705 0.488751,-1.99305 5.25531,0.95822 2.5951,8.61674 -0.627944,3.82779 z m 4.541717,-0.11873 c 1.727646,-1.71203 0.917172,1.6853 0,0 z m 2.794587,0.8959 c -2.619181,-4.9094 3.178801,2.05822 0,0 z m -5.55546,-5.30909 c -8.64844,-7.696511 10.867309,4.02451 1.4129,1.4269 l -1.412955,-1.42683 5.5e-5,-7e-5 z m 24.77908,14.39717 c -3.742506,-2.24398 -0.991777,-15.79747 0.284503,-6.52785 3.638294,-1.17695 -0.200879,4.78728 2.512784,4.73208 -0.42767,3.76305 -1.64169,5.11594 -2.797287,1.79577 z m 9.165207,5.41684 c 0.36705,-4.08462 0.77249,2.79262 0,0 z m -1.59198,-1.57295 c 0.41206,-1.74497 0.0426,2.05487 0,0 z M 76.213566,99.16032 c -5.556046,-7.665657 16.147323,7.75413 3.558556,1.9443 -1.315432,-0.34404 -2.898208,-0.46688 -3.558556,-1.9443 z m 17.649112,9.35749 c -0.525779,-6.45461 1.174169,1.06991 -1.92e-4,-2e-5 l 1.92e-4,2e-5 z m 13.399762,8.59585 c 1.03698,-3.67668 0.0773,2.43221 0,0 z M 77.064685,96.23472 c 3.302172,-0.706291 13.684695,5.79939 4.150224,1.85832 -1.059396,-1.17279 -3.317802,-0.63994 -4.150224,-1.85832 z m 28.356745,14.13312 c 0.35296,-6.60002 1.97138,-3.94233 0.0122,0.94474 l -0.0121,-0.94473 -5e-5,-1e-5 z M 79.52277,93.938099 c 1.345456,-1.97361 -3.571631,-8.923063 0.708795,-2.492797 1.849543,1.469605 5.355103,2.461959 2.260017,3.080216 4.867744,4.294162 -1.187244,1.163612 -2.968812,-0.587419 z m 24.49612,14.368161 c 0.92952,-7.51843 0.81971,4.40485 0,0 z M 76.712755,86.993902 c 1.027706,-0.439207 0.542746,1.369335 0,0 z m 6.389622,3.803092 c 1.644416,-3.450522 3.03351,3.848297 0,0 z m 18.023553,10.026276 c -0.0174,-1.3252 0.34003,1.92765 0,0 z m -1.04404,-2.31139 c -2.501612,-6.171646 2.32693,3.26759 0,0 z m -1.536003,-4.046372 c -0.419906,-2.550188 1.427129,3.203862 -7.3e-5,-9e-6 l 7.3e-5,9e-6 z m 2.499773,-4.063514 c -1.71663,-3.025123 2.16777,-13.331073 2.60122,-6.939418 -1.81185,4.980256 -0.52268,7.766309 0.74129,1.086388 2.33417,-5.257159 -0.50421,10.374054 -3.34255,5.853057 l 4e-5,-2.7e-5 z m 2.56889,-15.326649 c 0.74833,-0.918921 0.16609,1.107082 0,0 z m -4.290016,84.534235 c -1.017552,-0.88802 0.127775,0.56506 0,0 z m 8.837726,4.47065 c 4.91599,1.26135 4.89086,-0.76487 0.44782,-1.36683 -2.3898,-2.22316 -9.930475,-4.58124 -3.18119,-0.27586 0.44699,1.13227 1.85944,1.10589 2.73337,1.64269 z M 90.708067,152.48725 c 2.708244,2.01956 10.201213,5.72375 3.858186,0.76868 2.138588,-2.48467 -4.093336,-3.80722 -2.026067,-5.46927 -5.258175,-3.21755 -4.147962,-2.93133 -0.464111,-2.8301 -6.319385,-2.82462 0.912163,-2.61333 0.571661,-4.06067 -2.436706,-0.48126 -12.103074,-4.29664 -6.416395,0.31341 -5.780887,-2.94751 -1.377603,1.09799 -3.12488,0.67029 -5.911336,-1.61178 5.264392,4.50224 -0.938845,2.98448 3.391327,2.6875 9.128301,6.88393 1.433786,2.84407 -1.013816,1.45934 5.506273,3.67136 7.106665,4.77911 z m 9.243194,5.31013 c 11.238769,3.62163 -5.510018,-4.4246 0,0 z m 47.316399,28.66432 c 0.14496,-2.22965 -1.53604,1.90201 0,0 z m 4.86324,2.04679 c 2.59297,-2.51255 0.106,4.00222 4.29655,-0.61509 0.0453,-3.30544 -0.12904,-5.25783 -4.81563,-1.24252 -1.29194,0.71648 -1.86871,3.76288 0.51908,1.85761 z M 74.932378,140.02637 c -0.796355,-3.1304 -5.581949,-3.11418 0,0 z m 5.193029,3.40294 c -1.928397,-3.19739 -6.880525,-2.89469 0,0 z m 29.543373,17.81697 c 2.8844,2.56199 13.24761,1.87984 3.50331,0.31527 -1.44321,-2.13386 -9.16415,-1.6203 -3.50331,-0.31527 z m 40.61236,25.08153 c 4.43933,-3.72512 -4.30122,1.66183 0,0 z m 9.2328,6.34473 c 0.0277,-1.19543 -1.91352,0.52338 0,0 z m 0.0142,-1.6736 c 4.91602,-5.20866 -4.76346,0.30807 -4e-5,0 l 4e-5,0 z M 62.15981,129.33339 c -4.189944,-5.97826 -2.604586,-8.66544 -6.645136,-13.54677 -0.764913,-3.73279 -6.931672,-12.20326 -3.189579,-3.22947 3.42754,5.24836 4.446054,13.37434 9.834715,16.77624 z m 95.82635,60.00977 c 9.04429,-5.84575 -3.7125,-2.54641 0,0 z m 6.9041,2.70461 c 4.52911,-3.88867 -2.86491,-0.81334 0,0 z M 73.393094,133.41838 c 1.296204,-1.92838 -3.347642,-0.24666 0,0 z m 90.055596,56.78275 c 4.38526,-2.82746 -1.01036,-2.39335 -0.79483,0.26003 l 0.79484,-0.26003 -1e-5,0 z m -59.51386,-37.51178 c -0.15075,-1.90924 -2.31574,0.16206 0,0 z m 3.67794,2.11629 c -1.16888,-2.36318 -1.79716,0.37121 0,0 z m 62.8725,37.30625 c 5.61806,-4.05283 -3.4056,-0.77594 -1.17927,0.76785 l 1.17927,-0.76785 0,0 z m -2.15131,-1.03979 c 4.57663,-3.83506 -4.83183,1.69954 0,0 z m 10.99163,7.31983 c 3.0728,-2.05816 -3.73316,-0.66575 0,0 z M 76.211249,132.02781 c 4.118965,0.92286 16.460394,10.1439 9.179466,0.63772 -3.728991,-1.10384 -1.492605,-10.21906 -5.29621,-8.60579 2.552972,4.2649 2.100461,6.08018 -3.259642,3.3914 -6.736808,-3.28853 -3.785888,1.6297 -2.469293,2.98518 -1.794185,0.40772 2.373226,1.5572 1.845679,1.59149 z m -18.76588,-14.82026 c 0.737407,-3.04991 -6.789814,-16.77881 -3.554464,-6.87916 1.167861,2.07373 1.049123,6.00387 3.554464,6.87916 z m 34.443451,21.23513 c -2.120989,-1.77378 -0.100792,-0.25103 0,0 z m 5.222997,1.21548 c -0.0027,-3.23079 -5.77326,-1.31196 0,0 z m 45.261473,28.53321 c -0.86326,-2.20739 -3.41229,-0.0512 8e-5,4e-5 l -8e-5,-4e-5 z m 2.17351,1.58769 c -0.32087,-1.23546 -1.25399,0.23848 0,0 z m 17.94015,11.3001 c 1.72546,-1.27472 -2.15318,-0.1628 0,0 z M 66.819057,119.6006 c 4.935243,-1.91072 -5.28775,-1.36248 0,0 z m 71.569733,45.08937 c -0.0549,-3.19499 -3.14622,0.79264 0,0 z M 64.869152,115.05675 c 3.170167,-1.07084 -2.932663,-0.70531 0,0 z m 9.201532,4.45726 c -0.0575,-1.05014 -0.973336,0.39747 0,0 z m 112.231406,68.82181 c 4.0765,-0.8265 13.36606,2.07489 14.86752,-1.08086 -4.95044,-0.12019 -17.12734,-3.49263 -17.70346,0.80479 l 1.08368,0.17072 1.75226,0.10534 0,1e-5 z M 76.995161,120.25099 c 0.07087,-3.23755 -2.524669,-0.12092 0,0 z M 52.801998,103.4687 c -1.098703,-6.16843 -4.178791,-0.93357 0,0 z m 5.769195,1.45013 c 0.07087,-1.9807 -5.280562,-1.78224 0,0 z m 3.296917,1.61923 c -0.953019,-0.77196 -0.745959,0.97521 0,0 z m 20.744719,13.30775 c 0.976615,-0.89718 -2.312116,-0.66455 0,0 z M 59.672204,102.88617 c -0.557624,-4.65897 -6.681999,-0.69805 0,0 z M 47.844441,95.21166 c -0.168219,-2.150189 -1.152625,0.81111 0,0 z m 1.759336,-1.328672 c -0.28703,-2.549584 -1.510515,0.324387 0,0 z m 9.720792,5.802442 c 4.110486,-1.61465 -7.487254,-3.33984 -0.839893,-0.30506 l 0.839893,0.30506 z m 130.097601,80.35913 c 2.63092,-2.4121 -3.34373,-0.74577 0,0 z m 15.71669,8.14691 c 1.05433,-3.1186 -2.65452,0.41058 0,0 z M 60.318012,94.590436 c 0.433018,-3.016773 -3.258762,0.59902 0,0 z M 46.487687,85.324242 c -0.742965,-4.25911 -0.64134,-11.735065 6.465133,-9.208583 -9.485962,1.883339 6.56534,11.790095 4.538357,3.968363 3.988626,0.195294 7.802669,-2.357284 5.709487,1.516403 7.85876,-0.867958 13.307129,-7.682612 20.898169,-6.72768 5.913058,-0.782493 12.378182,-1.375955 18.750257,-3.756157 5.23905,-0.37743 10.28235,-6.018062 7.41068,-9.361383 -7.14456,-0.604513 -14.62339,0.289393 -22.520112,1.858993 -8.750559,1.819117 -16.699014,5.275307 -25.528125,6.758866 -8.605891,1.15604 1.730998,3.185165 -0.734074,3.637227 -4.490681,1.558136 5.355488,2.608852 -0.582182,4.251428 C 57.228283,77.56448 53.411411,76.304535 54.977788,72.440196 46.7341,73.50992 39.490264,76.931325 46.003276,85.320342 l 0.484402,0.0037 9e-6,-2.56e-4 z m 19.864291,-10.1168 c 1.932856,-7.120464 10.355229,5.859274 3.168052,0.945776 -0.858453,-0.642457 -2.2703,-1.166588 -3.168052,-0.945776 z m 0.376038,-3.452197 c 2.789661,-2.078257 1.482964,1.16516 0,0 z m 3.542213,0.05622 c 0.251833,-3.27648 8.108752,1.73455 1.295517,1.179499 l -1.295517,-1.179499 0,0 z m 4.84543,-1.948193 c 1.769481,-2.067535 0.50862,1.83906 0,0 z m 1.239563,-0.83005 c 2.946379,-3.540216 16.68561,-2.259413 6.628966,-0.34519 -2.695543,-2.029363 -4.761797,1.196575 -6.628966,0.34519 z m 17.930017,-2.763886 c -0.448199,-9.670222 8.907771,3.436477 0,0 z m 5.087539,-0.02784 c 1.860022,-4.873906 7.218072,-1.955774 0.860732,-0.979407 0.13805,0.518656 -0.18642,2.516173 -0.860732,0.979407 z M 58.311842,92.088739 c 5.55753,-3.403212 -5.899945,-2.952541 0,0 l 0,0 z m 4.109214,1.141866 c 1.948513,-2.071884 -4.233857,-0.840369 0,0 z M 50.313395,84.63767 c 3.175569,-2.439416 -3.757842,-0.927473 0,0 z M 214.41578,187.30012 c 0.0918,-2.83019 -2.42718,1.27537 0,0 z m -16.67487,-11.37935 c 0.47417,-3.25845 -2.14286,0.28408 0,0 z m 21.26022,12.47672 c 4.43994,0.015 13.45265,-1.37884 3.79217,-1.37442 -1.51594,0.23641 -8.83311,0.18571 -3.79216,1.37439 l -1e-5,3e-5 z M 66.035603,91.23339 c 3.593258,-0.246807 5.621861,-3.963629 -0.694932,-3.749977 -9.789949,-1.013541 8.637508,3.352129 -1.255898,2.10383 -1.329368,0.880346 1.873606,1.889721 1.95083,1.646147 z m 3.164618,1.601748 c -0.375177,-2.307063 -1.111156,1.225591 0,0 z m 3.753896,-10.009901 c 1.559281,-1.934055 -2.157697,-0.517053 0,0 z M 61.003998,62.84999 c 6.412879,-2.181631 15.182392,-4.633087 18.210335,1.074184 -3.081589,-3.70893 -1.24361,-7.360157 1.666959,-1.937407 4.115576,5.486669 6.175915,-2.495489 3.499086,-4.335821 3.050468,3.790246 6.520044,5.581281 2.042429,0.239564 4.865693,-5.852929 -9.742712,0.766433 -13.063105,0.699775 -1.597564,0.717062 -16.493576,3.79889 -12.355704,4.259705 z m 3.75831,-7.197834 c 3.657324,-2.760416 12.648968,1.641989 6.879078,-2.743367 -0.564117,-0.498292 -12.636077,3.325475 -6.879078,2.743367 z m 13.333489,0.550473 c 4.280389,0.109225 -1.84632,-5.750287 3.254304,-3.095159 -0.837696,-2.736627 -5.938558,-3.248956 -8.432316,-4.342312 -1.410474,2.502054 2.870977,7.471102 5.178012,7.437471 z M 67.100291,44.099162 c 1.480803,-2.007406 -2.59521,1.017699 0,0 z m 5.449586,1.304353 c 6.897867,-0.914901 -1.758292,-2.970542 -1.389954,-0.07352 l 1.389954,0.07352 0,-9e-6 z M 62.374386,37.441437 c -4.856866,-6.340205 9.133987,1.065769 4.199411,-5.572646 -4.153254,-3.307245 -8.144297,3.721775 -4.199411,5.572646 z m 62.330124,33.572802 c 2.22762,-3.948988 -9.19697,-5.323011 -1.5009,-1.399578 0.70858,0.236781 0.54821,1.6727 1.5009,1.399578 z" + id="path2900" /> + <g + style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" + id="text3850"> + <path + d="m 229.85182,43.77803 c -0.79695,3.140714 -1.28913,8.414146 -1.47656,15.820313 -7e-5,1.453199 -0.65632,2.179761 -1.96875,2.179687 -1.31257,7.4e-5 -2.22663,-0.632738 -2.74219,-1.898437 -1.40631,-3.421796 -2.74225,-5.812419 -4.00781,-7.171875 -1.50006,-1.593666 -3.49225,-2.554603 -5.97656,-2.882813 -2.67193,-0.421789 -9.32818,-0.632726 -19.96875,-0.632812 -2.43754,8.6e-5 -4.03129,0.257898 -4.78125,0.773437 -0.46879,0.32821 -0.70316,1.031335 -0.70313,2.109375 l 0,31.851563 c -3e-5,1.078175 0.67966,1.5938 2.03906,1.546875 4.17184,-0.04682 10.21871,-0.328075 18.14063,-0.84375 1.54682,-0.187449 2.58979,-0.691355 3.12891,-1.511719 0.539,-0.820259 1.06634,-2.941351 1.58203,-6.363281 0.32806,-1.87494 1.42963,-2.601502 3.30468,-2.179688 1.59369,0.328186 2.27338,1.054747 2.03907,2.179688 -1.31256,6.375052 -1.73444,14.671919 -1.26563,24.890627 0.0468,1.21878 -0.72662,1.87503 -2.32031,1.96875 -1.31256,0.14065 -2.13287,-0.56247 -2.46094,-2.10938 -1.2188,-5.859333 -3.48052,-8.988236 -6.78515,-9.386716 -3.30474,-0.398394 -8.68364,-0.597612 -16.13672,-0.597656 -0.84379,4.4e-5 -1.26566,0.304731 -1.26563,0.914062 l 0,31.64063 c -3e-5,2.34375 0.86716,3.9375 2.60156,4.78125 1.35934,0.70313 4.28903,1.33594 8.78907,1.89843 2.29683,0.23438 3.30464,1.24219 3.02343,3.02344 -0.28129,1.54688 -2.34379,2.15625 -6.1875,1.82813 -11.1094,-0.89063 -20.27345,-0.84375 -27.49218,0.14062 -2.01564,0.28125 -3.02345,-0.53906 -3.02344,-2.46094 -1e-5,-1.21874 1.0078,-1.92187 3.02344,-2.10937 4.59373,-0.51562 6.8906,-4.54687 6.89062,-12.09375 l 0,-60.187502 c -2e-5,-3.093671 -0.5508,-5.472575 -1.65234,-7.136719 -1.10158,-1.663977 -3.15236,-3.175695 -6.15235,-4.535156 -1.87501,-0.843661 -2.57813,-1.992098 -2.10937,-3.445313 0.23436,-0.890532 0.60936,-1.382719 1.125,-1.476562 0.46874,-0.140532 1.71092,-0.04678 3.72656,0.28125 2.95311,0.468842 9.91404,0.703217 20.88281,0.703125 12.93746,9.2e-5 24.11713,-0.281158 33.53907,-0.84375 3.14055,-0.187407 4.71086,0.07041 4.71093,0.773437 -7e-5,0.187592 -0.0235,0.375092 -0.0703,0.5625 z" + style="font-size:144px;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2830" /> + <path + d="m 275.55495,133.14522 c -4e-5,1.875 -1.05473,2.69531 -3.16407,2.46094 -6.46877,-0.60938 -14.48439,-0.51563 -24.04687,0.28125 -1.92189,0.18749 -3.10548,0.14062 -3.55078,-0.14063 -0.44532,-0.28125 -0.66798,-1.05469 -0.66797,-2.32031 -1e-5,-1.125 1.27733,-2.07422 3.83203,-2.84766 2.55467,-0.77343 3.83202,-3.08202 3.83203,-6.92578 l 0,-63.632812 c -1e-5,-3.796796 -0.55079,-6.585856 -1.65234,-8.367188 -1.10158,-1.781164 -3.03517,-3.163975 -5.80078,-4.148437 -1.45313,-0.515537 -2.1797,-1.242099 -2.17969,-2.179688 -1e-5,-1.406158 1.05468,-2.460845 3.16406,-3.164062 3.18749,-1.031156 6.49217,-2.624904 9.91406,-4.78125 2.81248,-1.687401 4.59373,-2.53115 5.34375,-2.53125 1.73435,1e-4 2.60154,1.195412 2.60157,3.585937 -3e-5,-0.187403 -0.0938,2.156345 -0.28125,7.03125 -0.14065,4.64071 -0.18753,9.211018 -0.14063,13.710938 l 0.28125,62.789062 c -2e-5,2.85939 0.7031,4.9336 2.10938,6.22266 1.40622,1.28906 3.82028,2.14453 7.24218,2.5664 2.10934,0.23438 3.16403,1.03126 3.16407,2.39063 z" + style="font-size:144px;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2832" /> + <path + d="m 339.67995,128.43428 c -7e-5,0.98438 -1.79303,2.47266 -5.37891,4.46484 -3.58599,1.99219 -6.45708,2.98828 -8.61328,2.98829 -1.82817,-10e-6 -3.44536,-0.89063 -4.85156,-2.67188 -1.40629,-1.78125 -2.39067,-2.67187 -2.95313,-2.67187 -0.42191,0 -2.64847,0.96094 -6.67969,2.88281 -4.03128,1.92187 -8.08596,2.88281 -12.16406,2.88281 -3.84377,0 -7.0547,-1.125 -9.63281,-3.375 -2.81251,-2.48437 -4.21876,-5.85937 -4.21875,-10.125 -1e-5,-8.10935 9.28123,-13.92185 27.84375,-17.4375 3.18746,-0.60934 4.80465,-1.89841 4.85156,-3.86719 l 0.14063,-4.499997 c 0.28121,-7.687454 -3.11723,-11.5312 -10.19532,-11.53125 -2.01565,5e-5 -3.9258,1.804735 -5.73046,5.414062 -1.80471,3.609416 -4.39456,5.554727 -7.76954,5.835938 -3.84376,0.375038 -5.76563,-1.242148 -5.76562,-4.851563 -1e-5,-2.249954 2.85936,-4.874951 8.57812,-7.875 5.99998,-3.14057 11.7656,-4.710881 17.29688,-4.710937 9.51558,5.6e-5 14.22651,4.523489 14.13281,13.570312 l -0.28125,28.968755 c -0.0469,3.04688 1.24214,4.57032 3.86719,4.57031 0.51557,1e-5 1.49994,-0.11718 2.95312,-0.35156 1.45307,-0.23437 2.29682,-0.35156 2.53125,-0.35157 1.35932,1e-5 2.039,0.91407 2.03907,2.74219 z M 318.0237,112.40303 c 0.0468,-1.17185 -0.2227,-1.94529 -0.8086,-2.32031 -0.58597,-0.37498 -1.51175,-0.44529 -2.77734,-0.21094 -11.2969,2.01565 -16.94533,5.69533 -16.94531,11.03906 -2e-5,5.39064 2.92966,8.08595 8.78906,8.08594 2.34372,1e-5 4.75778,-0.44531 7.24219,-1.33594 2.90621,-1.03124 4.35933,-2.27342 4.35937,-3.72656 z" + style="font-size:144px;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2834" /> + <path + d="m 392.13307,120.06709 c -5e-5,4.96876 -1.9102,8.91798 -5.73047,11.84766 -3.82035,2.92969 -9.03519,4.39453 -15.64453,4.39453 -4.40627,0 -8.81252,-0.46875 -13.21875,-1.40625 -3.79688,-0.84375 -6.00001,-1.61719 -6.60937,-2.32031 -0.37501,-0.65625 -0.56251,-3.86718 -0.5625,-9.63281 -1e-5,-2.48436 0.56249,-3.77343 1.6875,-3.86719 1.12499,-0.14061 2.08592,0.46876 2.88281,1.82812 3.51561,6.14064 9.18748,9.21095 17.01562,9.21094 6.60934,1e-5 9.91403,-2.29687 9.91407,-6.89062 -4e-5,-2.01562 -0.75004,-3.70311 -2.25,-5.0625 -1.64066,-1.54686 -4.82816,-3.35155 -9.5625,-5.41407 -6.84377,-3.04685 -11.41408,-5.71872 -13.71094,-8.01562 -2.48439,-2.43747 -3.72657,-5.718716 -3.72656,-9.843752 -1e-5,-5.062455 1.9453,-8.999951 5.83593,-11.8125 3.60936,-2.718695 8.43748,-4.078069 14.48438,-4.078125 3.79684,5.6e-5 7.26559,0.304743 10.40625,0.914062 3.37496,0.60943 5.13277,1.359429 5.27344,2.25 0.37495,2.625051 1.14839,6.421922 2.32031,11.390625 0.14058,0.609416 -0.51567,1.101603 -1.96875,1.476563 -1.54692,0.328165 -2.57817,0.07035 -3.09375,-0.773438 -3.70317,-6.046828 -8.39066,-9.070262 -14.0625,-9.070312 -6.4219,5e-5 -9.63283,2.062548 -9.63281,6.1875 -2e-5,2.296916 0.86716,4.12504 2.60156,5.484375 1.54685,1.171912 5.17966,3.000035 10.89844,5.484372 5.99996,2.57816 10.07808,4.89847 12.23437,6.96094 2.81245,2.6719 4.2187,6.25783 4.21875,10.75781 z" + style="font-size:144px;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2836" /> + <path + d="m 473.69557,132.72334 c -7e-5,1.64063 -1.10163,2.50782 -3.30469,2.60157 -3.28131,0.0469 -7.57037,0.28124 -12.86718,0.70312 -2.62506,0.51562 -4.50006,0.1875 -5.625,-0.98437 -7.4063,-7.96875 -13.68754,-16.31249 -18.84375,-25.03125 -0.42191,-0.74998 -0.96097,-1.12498 -1.61719,-1.125 -0.79691,2e-5 -2.17972,0.70315 -4.14844,2.10937 -2.20315,1.21877 -3.30471,2.95315 -3.30469,5.20313 -2e-5,1.59376 0.0469,3.89064 0.14063,6.89062 0.0937,3.00001 0.84372,4.96876 2.25,5.90625 0.98435,0.65626 3.25778,1.17188 6.82031,1.54688 2.20309,0.28125 3.30465,1.10156 3.30469,2.46093 -4e-5,1.07813 -0.17582,1.7461 -0.52734,2.00391 -0.3516,0.25781 -1.27738,0.31641 -2.77735,0.17578 -4.68753,-0.42187 -12.60939,-0.1875 -23.76562,0.70313 -2.81251,0.23437 -4.33595,-0.11719 -4.57032,-1.05469 -0.0937,-0.32813 -0.14063,-0.79688 -0.14062,-1.40625 -1e-5,-1.45312 1.42968,-2.55469 4.28906,-3.30469 2.57811,-0.65624 3.86718,-3.67968 3.86719,-9.07031 l 0,-61.453127 c -1e-5,-3.843671 -0.37501,-6.515543 -1.125,-8.015625 -1.03126,-1.92179 -3.18751,-3.421788 -6.46875,-4.5 -1.54688,-0.515536 -2.32032,-1.242098 -2.32031,-2.179688 -1e-5,-1.359283 1.10155,-2.413969 3.30468,-3.164062 3.51562,-1.17178 6.86718,-2.788966 10.05469,-4.851563 2.57811,-1.6874 4.17186,-2.531149 4.78125,-2.53125 1.92185,1.01e-4 2.88279,1.21885 2.88281,3.65625 -2e-5,-0.328027 -0.0235,1.992283 -0.0703,6.960938 -0.0469,3.421962 -0.0703,8.015707 -0.0703,13.78125 l 0.14062,44.015627 c -2e-5,1.21878 0.3281,1.82815 0.98438,1.82812 0.7031,3e-5 1.78122,-0.60934 3.23437,-1.82812 3.8906,-3.046842 8.67184,-7.031213 14.34375,-11.953127 1.12496,-1.17183 1.68746,-2.109329 1.6875,-2.8125 -4e-5,-1.265577 -1.89848,-2.156201 -5.69531,-2.671875 -1.64066,-0.18745 -2.4141,-1.101512 -2.32031,-2.742188 0.14059,-1.64057 0.9609,-2.343695 2.46094,-2.109375 3.37495,0.468805 8.29682,0.726617 14.76562,0.773438 4.49994,0.04693 8.9765,0.07037 13.42969,0.07031 1.45306,0.04693 2.17962,0.914116 2.17969,2.601563 -7e-5,1.5938 -1.14851,2.460986 -3.44532,2.601562 -3.60943,0.140674 -7.00787,0.960986 -10.19531,2.460938 -4.45317,2.015669 -9.21098,5.554728 -14.27344,10.617187 -0.37504,0.281286 -0.56254,0.632845 -0.5625,1.054685 -4e-5,0.65629 0.79684,2.2266 2.39063,4.71094 5.85933,8.90627 11.39057,15.63283 16.59375,20.17969 3.32806,2.85938 6.44525,4.28907 9.35156,4.28906 2.15618,1e-5 3.49212,0.15235 4.00781,0.45703 0.51556,0.30469 0.77337,1.11329 0.77344,2.42578 z" + style="font-size:144px;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2838" /> + </g> + <g + style="font-size:40px;font-style:normal;font-weight:normal;line-height:89.99999762%;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" + id="text2870" + transform="translate(0,4)"> + <path + d="m 285.18048,153.2296 c -2e-5,0.16407 -0.31447,0.33269 -0.94336,0.50586 -0.41017,0.10938 -0.75653,0.48308 -1.03906,1.12109 -1.64064,3.64584 -3.10809,6.58529 -4.40234,8.81836 -0.0274,0.0547 -0.0957,0.0775 -0.20508,0.0684 -0.10028,-0.009 -0.16864,-0.041 -0.20508,-0.0957 -0.21876,-0.32813 -0.77931,-1.47201 -1.68164,-3.43164 -0.82944,-1.80469 -1.27605,-2.70703 -1.33985,-2.70703 -0.10027,0 -0.5879,0.87044 -1.46289,2.61132 -0.99349,1.94141 -1.58138,3.04883 -1.76367,3.32227 -0.0274,0.0638 -0.0912,0.0911 -0.1914,0.082 -0.10027,0 -0.17775,-0.0365 -0.23243,-0.10937 -0.66537,-1.03907 -2.19662,-3.88281 -4.59375,-8.53125 -0.27344,-0.54687 -0.57877,-0.89322 -0.91601,-1.03907 -0.58334,-0.2552 -0.875,-0.44204 -0.875,-0.56054 0,-0.35546 0.19596,-0.51497 0.58789,-0.47852 1.75911,0.1823 3.29947,0.14584 4.62109,-0.10937 0.30078,-0.0547 0.45117,0.0456 0.45117,0.30078 0,0.35548 -0.20508,0.58334 -0.61523,0.68359 -0.53777,0.12761 -0.80665,0.32814 -0.80664,0.60156 -1e-5,0.17319 0.0638,0.4284 0.19141,0.76563 0.32812,0.84766 0.8203,1.92318 1.47656,3.22656 0.65624,1.30339 1.03905,1.95508 1.14844,1.95508 0.0729,0 0.46027,-0.67903 1.16211,-2.03711 0.70181,-1.35807 1.05272,-2.11002 1.05273,-2.25586 -1e-5,-0.35546 -0.1185,-0.73827 -0.35547,-1.14844 -0.28256,-0.60155 -0.61069,-0.96158 -0.98437,-1.08008 -0.60157,-0.20962 -0.90236,-0.4147 -0.90235,-0.61523 -1e-5,-0.36457 0.20507,-0.51496 0.61524,-0.45117 1.40363,0.19142 2.88931,0.15496 4.45703,-0.10938 0.30077,-0.0547 0.45116,0.0365 0.45117,0.27344 -1e-5,0.34637 -0.22332,0.56056 -0.66992,0.64258 -0.52866,0.10027 -0.79298,0.36915 -0.79297,0.80664 -10e-6,0.20964 0.0592,0.45574 0.17773,0.73828 1.40364,3.4362 2.21483,5.1543 2.4336,5.1543 0.082,0 0.4466,-0.66992 1.09375,-2.00977 0.69269,-1.43098 1.17576,-2.58397 1.44922,-3.45898 0.0182,-0.0456 0.0273,-0.0957 0.0273,-0.15039 -2e-5,-0.39192 -0.30536,-0.69726 -0.91602,-0.91602 -0.47397,-0.15494 -0.71095,-0.32811 -0.71093,-0.51953 -2e-5,-0.319 0.15037,-0.44205 0.45117,-0.36914 0.41014,0.0912 1.14842,0.15952 2.21484,0.20508 1.00259,0.0365 1.66339,0.0319 1.98242,-0.0137 0.37368,-0.0456 0.56053,0.0592 0.56055,0.31445 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2877" /> + <path + d="m 297.29376,160.98155 c -1e-5,0.39193 -0.52865,0.87956 -1.58594,1.46289 -1.20313,0.64714 -2.43815,0.97071 -3.70507,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47266,-1.35352 -1.00261,-0.95703 -1.50391,-2.23307 -1.50391,-3.82812 0,-1.80469 0.56055,-3.2539 1.68164,-4.34766 1.04818,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90234,1e-5 1.74544,0.28712 2.5293,0.86133 0.70181,0.51042 1.16666,1.09376 1.39453,1.75 0.082,0.22787 0.20507,0.35547 0.36914,0.38281 0.23697,0.0456 0.35546,0.20509 0.35547,0.47852 -10e-6,0.3737 -0.44662,0.69271 -1.33984,0.95703 l -6.30274,1.87304 c 0.41016,2.16928 1.52213,3.25391 3.33594,3.25391 1.04817,0 2.24218,-0.38281 3.58203,-1.14844 0.20051,-0.11848 0.39648,-0.17773 0.58789,-0.17773 0.14582,0 0.21874,0.13216 0.21875,0.39648 z m -3.24023,-5.48242 c -1e-5,-0.50129 -0.20281,-0.94107 -0.6084,-1.31934 -0.40561,-0.37824 -0.90463,-0.56737 -1.49707,-0.56738 -1.67709,10e-6 -2.51563,1.20769 -2.51563,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60156,-0.17317 0.90234,-0.48762 0.90235,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2879" /> + <path + d="m 311.11603,157.13976 c -2e-5,1.80469 -0.62892,3.31771 -1.88672,4.53906 -1.20314,1.17578 -2.63412,1.76367 -4.29297,1.76367 -0.93881,0 -1.91862,-0.15495 -2.93945,-0.46484 -0.98438,-0.30078 -1.48112,-0.57422 -1.49024,-0.82032 -0.009,-0.20963 -0.005,-0.94335 0.0137,-2.20117 0.0273,-1.54036 0.041,-2.66145 0.041,-3.36328 0,-1.05728 -0.009,-2.59081 -0.0273,-4.60059 -0.0182,-2.00975 -0.0274,-3.34275 -0.0274,-3.99902 0,-0.65623 -0.10026,-1.1074 -0.30078,-1.35351 -0.18229,-0.21874 -0.57878,-0.39191 -1.18945,-0.51954 -0.23698,-0.082 -0.35547,-0.2324 -0.35547,-0.45117 0,-0.19139 0.17773,-0.35089 0.5332,-0.47851 0.51042,-0.18228 1.14388,-0.48762 1.90039,-0.91602 0.60156,-0.33722 0.97526,-0.50584 1.1211,-0.50586 0.28254,2e-5 0.42382,0.23244 0.42383,0.69727 -1e-5,0.0365 -0.0137,0.51043 -0.041,1.42187 -0.0182,0.85679 -0.0228,1.72723 -0.0137,2.61133 l 0.0273,4.73047 c 0,0.44662 0.15494,0.57423 0.46485,0.38281 1.09374,-0.62889 2.23306,-0.94335 3.41796,-0.94336 1.36718,1e-5 2.47916,0.41245 3.33594,1.23731 0.85676,0.82488 1.28514,1.90267 1.28516,3.2334 z m -2.1875,1.21679 c -1e-5,-1.24869 -0.34637,-2.27408 -1.03906,-3.07617 -0.65626,-0.7565 -1.45379,-1.13476 -2.39258,-1.13477 -0.64714,1e-5 -1.28517,0.16863 -1.91407,0.50586 -0.62891,0.33725 -0.94336,0.69272 -0.94335,1.06641 l 0,3.66406 c -1e-5,1.75912 0.97069,2.63868 2.9121,2.63867 1.01172,1e-5 1.82747,-0.32584 2.44727,-0.97753 0.61978,-0.65169 0.92968,-1.5472 0.92969,-2.68653 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2881" /> + <path + d="m 333.23712,161.93858 c 0.0365,0.082 0.0547,0.14128 0.0547,0.17774 -2e-5,0.1914 -0.46486,0.50586 -1.39453,0.94336 -1.07553,0.5013 -1.709,0.75195 -1.90039,0.75195 -0.16408,0 -0.3532,-0.27572 -0.56739,-0.82715 -0.2142,-0.55143 -0.36231,-0.82715 -0.44433,-0.82715 0.009,0 -0.50815,0.23926 -1.55176,0.71778 -1.04363,0.47851 -1.83432,0.71777 -2.37207,0.71777 -1.20313,0 -2.24675,-0.43294 -3.13086,-1.29883 -1.06641,-1.02994 -1.59961,-2.4746 -1.59961,-4.33398 0,-1.55859 0.62891,-2.90299 1.88672,-4.03321 1.11198,-0.99347 2.24674,-1.49022 3.4043,-1.49023 0.8203,1e-5 1.80012,0.10483 2.93945,0.31445 0.35546,0.0638 0.53319,-0.041 0.5332,-0.31445 l 0,-4.67578 c -1e-5,-0.52863 -0.12761,-0.90233 -0.38281,-1.12109 -0.16407,-0.14582 -0.55144,-0.319 -1.16211,-0.51954 -0.29167,-0.10935 -0.43751,-0.28709 -0.4375,-0.5332 -10e-6,-0.22785 0.19596,-0.39647 0.58789,-0.50586 0.53775,-0.16404 1.18033,-0.43748 1.92774,-0.82031 0.61978,-0.32811 1.00259,-0.49217 1.14843,-0.49219 0.33723,2e-5 0.50585,0.23244 0.50586,0.69727 -1e-5,-0.009 -0.0137,0.44435 -0.041,1.36035 -0.0274,0.91603 -0.041,1.80698 -0.041,2.67285 l 0,12.42773 c -10e-6,0.51954 0.23241,0.7793 0.69727,0.7793 0.17316,0 0.40558,-0.0273 0.69726,-0.082 0.319,-0.0547 0.53319,0.0501 0.64258,0.31445 z m -4.22461,-1.35351 0,-4.89453 c -1e-5,-0.40104 -0.35548,-0.81575 -1.0664,-1.24414 -0.75652,-0.45572 -1.57683,-0.68359 -2.46094,-0.6836 -1.90495,1e-5 -2.85743,1.17579 -2.85742,3.52735 -10e-6,1.25781 0.37825,2.33333 1.13476,3.22656 0.75651,0.89323 1.64518,1.33984 2.66602,1.33984 0.46483,0 1.01171,-0.15494 1.64062,-0.46484 0.6289,-0.3099 0.94335,-0.57878 0.94336,-0.80664 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2883" /> + <path + d="m 345.09064,160.98155 c -1e-5,0.39193 -0.52866,0.87956 -1.58594,1.46289 -1.20313,0.64714 -2.43816,0.97071 -3.70508,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47265,-1.35352 -1.00261,-0.95703 -1.50391,-2.23307 -1.50391,-3.82812 0,-1.80469 0.56054,-3.2539 1.68164,-4.34766 1.04817,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90233,1e-5 1.74543,0.28712 2.5293,0.86133 0.70181,0.51042 1.16665,1.09376 1.39453,1.75 0.082,0.22787 0.20506,0.35547 0.36914,0.38281 0.23697,0.0456 0.35545,0.20509 0.35547,0.47852 -2e-5,0.3737 -0.44663,0.69271 -1.33985,0.95703 l -6.30273,1.87304 c 0.41015,2.16928 1.52213,3.25391 3.33594,3.25391 1.04816,0 2.24217,-0.38281 3.58203,-1.14844 0.20051,-0.11848 0.39647,-0.17773 0.58789,-0.17773 0.14582,0 0.21874,0.13216 0.21875,0.39648 z m -3.24024,-5.48242 c -10e-6,-0.50129 -0.2028,-0.94107 -0.6084,-1.31934 -0.4056,-0.37824 -0.90462,-0.56737 -1.49707,-0.56738 -1.67708,10e-6 -2.51562,1.20769 -2.51562,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60155,-0.17317 0.90233,-0.48762 0.90234,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2885" /> + <path + d="m 360.08868,153.20226 c -1e-5,0.17318 -0.28712,0.35092 -0.86132,0.5332 -0.37371,0.10938 -0.69272,0.48308 -0.95704,1.12109 -0.44662,1.07553 -1.22592,2.65235 -2.33789,4.73047 -0.93881,1.75912 -1.66342,3.04427 -2.17382,3.85547 -0.0274,0.0638 -0.0866,0.0911 -0.17774,0.082 -0.0912,-0.009 -0.15951,-0.0456 -0.20508,-0.10937 -1.93229,-2.77995 -3.58659,-5.6237 -4.96289,-8.53125 -0.29167,-0.61979 -0.57878,-0.96614 -0.86133,-1.03907 -0.52864,-0.20962 -0.79296,-0.39647 -0.79296,-0.56054 0,-0.36458 0.17773,-0.52408 0.5332,-0.47852 0.55599,0.0729 1.38086,0.0912 2.47461,0.0547 1.05729,-0.0273 1.80012,-0.082 2.22851,-0.16406 0.26432,-0.0547 0.39648,0.0456 0.39649,0.30078 -10e-6,0.31902 -0.18686,0.5241 -0.56055,0.61523 -0.71094,0.19142 -1.06641,0.43751 -1.0664,0.73828 -1e-5,0.13673 0.0456,0.33269 0.13671,0.58789 0.30989,0.76564 0.86588,1.87078 1.66797,3.31543 0.80208,1.44467 1.25781,2.167 1.36719,2.167 0.082,0 0.46939,-0.69271 1.16211,-2.07813 0.72916,-1.46744 1.25324,-2.65234 1.57227,-3.55469 0.0456,-0.10025 0.0683,-0.20051 0.0684,-0.30078 -1e-5,-0.35546 -0.21876,-0.64712 -0.65625,-0.875 -0.42839,-0.17317 -0.64258,-0.33723 -0.64257,-0.49219 -10e-6,-0.319 0.14126,-0.45116 0.42382,-0.39648 0.36458,0.0638 1.00716,0.1185 1.92774,0.16406 0.92056,0.0456 1.51756,0.0547 1.79101,0.0274 0.33723,-0.0638 0.50585,0.0319 0.50586,0.28711 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2887" /> + <path + d="m 372.21564,160.98155 c -1e-5,0.39193 -0.52866,0.87956 -1.58594,1.46289 -1.20313,0.64714 -2.43816,0.97071 -3.70508,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47265,-1.35352 -1.00261,-0.95703 -1.50391,-2.23307 -1.50391,-3.82812 0,-1.80469 0.56054,-3.2539 1.68164,-4.34766 1.04817,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90233,1e-5 1.74543,0.28712 2.5293,0.86133 0.70181,0.51042 1.16665,1.09376 1.39453,1.75 0.082,0.22787 0.20506,0.35547 0.36914,0.38281 0.23697,0.0456 0.35545,0.20509 0.35547,0.47852 -2e-5,0.3737 -0.44663,0.69271 -1.33985,0.95703 l -6.30273,1.87304 c 0.41015,2.16928 1.52213,3.25391 3.33594,3.25391 1.04816,0 2.24217,-0.38281 3.58203,-1.14844 0.20051,-0.11848 0.39647,-0.17773 0.58789,-0.17773 0.14582,0 0.21874,0.13216 0.21875,0.39648 z m -3.24024,-5.48242 c -10e-6,-0.50129 -0.2028,-0.94107 -0.6084,-1.31934 -0.4056,-0.37824 -0.90462,-0.56737 -1.49707,-0.56738 -1.67708,10e-6 -2.51562,1.20769 -2.51562,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60155,-0.17317 0.90233,-0.48762 0.90234,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2889" /> + <path + d="m 380.66486,162.88194 c -10e-6,0.36459 -0.20509,0.52409 -0.61524,0.47852 -1.25782,-0.11849 -2.81641,-0.10026 -4.67578,0.0547 -0.3737,0.0365 -0.60384,0.0273 -0.69043,-0.0274 -0.0866,-0.0547 -0.12988,-0.20508 -0.12988,-0.45117 0,-0.21875 0.24837,-0.40332 0.74512,-0.55371 0.49674,-0.15039 0.74511,-0.59928 0.74511,-1.34668 l 0,-12.37305 c 0,-0.73826 -0.1071,-1.28058 -0.32129,-1.62695 -0.21419,-0.34634 -0.59017,-0.61522 -1.12793,-0.80664 -0.28255,-0.10024 -0.42383,-0.24152 -0.42382,-0.42383 -1e-5,-0.27342 0.20507,-0.4785 0.61523,-0.61523 0.61979,-0.20051 1.26237,-0.5104 1.92773,-0.92969 0.54687,-0.32811 0.89323,-0.49217 1.03907,-0.49219 0.33723,2e-5 0.50585,0.23244 0.50586,0.69727 -10e-6,-0.0364 -0.0182,0.41929 -0.0547,1.36718 -0.0273,0.90236 -0.0365,1.79104 -0.0273,2.66602 l 0.0547,12.20898 c 0,0.556 0.13672,0.95932 0.41016,1.20997 0.27343,0.25065 0.74283,0.41699 1.4082,0.49902 0.41015,0.0456 0.61523,0.20052 0.61524,0.46484 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2891" /> + <path + d="m 393.9129,157.76866 c -10e-6,1.58594 -0.5879,2.92806 -1.76367,4.02637 -1.17579,1.09831 -2.63412,1.64746 -4.375,1.64746 -1.74089,0 -3.11719,-0.48307 -4.12891,-1.44922 -0.97526,-0.94791 -1.46289,-2.20117 -1.46289,-3.75976 0,-1.61328 0.61524,-2.97135 1.84571,-4.07422 1.194,-1.0664 2.62043,-1.5996 4.27929,-1.59961 1.77734,1e-5 3.16275,0.47852 4.15625,1.43554 0.96614,0.9297 1.44921,2.18751 1.44922,3.77344 z m -2.40625,0.83399 c -10e-6,-1.43099 -0.34636,-2.5931 -1.03906,-3.48633 -0.67449,-0.86588 -1.53126,-1.29882 -2.57031,-1.29883 -0.96615,1e-5 -1.75456,0.33953 -2.36524,1.01855 -0.61068,0.67905 -0.91602,1.5062 -0.91601,2.48145 -1e-5,1.56771 0.35546,2.78907 1.0664,3.66406 0.65625,0.80209 1.51302,1.20313 2.57032,1.20313 1.00259,0 1.79556,-0.33268 2.3789,-0.99805 0.58333,-0.66536 0.87499,-1.52669 0.875,-2.58398 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2893" /> + <path + d="m 408.20001,157.39952 c -1e-5,1.70443 -0.57195,3.15137 -1.71582,4.34082 -1.14389,1.18945 -2.4769,1.78418 -3.99902,1.78418 -0.92058,0 -1.80925,-0.16406 -2.66602,-0.49219 -0.0911,-0.0365 -0.13672,0.18685 -0.13672,0.66993 l 0,4.11523 c 0,0.66536 0.54232,1.09374 1.62696,1.28516 0.50129,0.0911 0.81802,0.17545 0.95019,0.25293 0.13216,0.0775 0.19824,0.20735 0.19824,0.38964 0,0.30989 -0.20508,0.45117 -0.61523,0.42383 -1.91407,-0.12761 -3.59571,-0.082 -5.04492,0.13672 -0.30078,0.0456 -0.48763,0.0456 -0.56055,0 -0.0729,-0.0456 -0.10937,-0.16863 -0.10937,-0.36914 0,-0.15495 0.25976,-0.3418 0.77929,-0.56055 0.44662,-0.18229 0.66992,-0.61979 0.66993,-1.3125 l 0,-12.05859 c -1e-5,-0.97525 -0.26889,-1.58593 -0.80665,-1.83203 -0.63802,-0.28254 -0.95703,-0.51497 -0.95703,-0.69727 0,-0.20051 0.18685,-0.3509 0.56055,-0.45117 0.48307,-0.11848 0.97982,-0.32811 1.49023,-0.62891 0.42839,-0.24608 0.68815,-0.36912 0.7793,-0.36914 0.27344,2e-5 0.49674,0.25067 0.66992,0.75196 0.25521,0.72917 0.42383,1.09376 0.50586,1.09375 0.0182,1e-5 0.41015,-0.21419 1.17578,-0.64258 0.83854,-0.46483 1.65885,-0.69726 2.46094,-0.69727 1.30338,1e-5 2.3789,0.36915 3.22656,1.10743 1.01171,0.86589 1.51757,2.11914 1.51758,3.75976 z m -2.32422,1.09375 c -10e-6,-1.48567 -0.36915,-2.64322 -1.10742,-3.47266 -0.60157,-0.69269 -1.30795,-1.03905 -2.11914,-1.03906 -0.62891,1e-5 -1.23047,0.21876 -1.80469,0.65625 -0.75651,0.56511 -1.13477,1.35353 -1.13476,2.36524 l 0,3.86914 c -1e-5,0.24609 0.34635,0.50586 1.03906,0.77929 0.74739,0.30079 1.55859,0.45118 2.43359,0.45118 1.79557,0 2.69335,-1.20313 2.69336,-3.60938 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2895" /> + <path + d="m 432.90509,162.90929 c -2e-5,0.30078 -0.1413,0.44205 -0.42383,0.42382 -1.85939,-0.13671 -3.59116,-0.13671 -5.19531,0 -0.35549,0.0273 -0.53322,-0.13216 -0.5332,-0.47851 -2e-5,-0.27344 0.24152,-0.41927 0.72461,-0.4375 0.61065,-0.0365 0.91599,-0.5332 0.91601,-1.49024 l 0,-3.63671 c -2e-5,-2.04166 -0.82944,-3.0625 -2.48828,-3.0625 -0.87502,0 -1.6771,0.15951 -2.40625,0.47851 -0.66538,0.28256 -1.00262,0.56511 -1.01172,0.84766 l -0.0547,5.42773 c -10e-6,0.56511 0.0684,0.93881 0.20508,1.1211 0.10025,0.1276 0.32356,0.21875 0.66992,0.27343 0.80207,0.13672 1.20311,0.30534 1.20313,0.50586 -2e-5,0.17318 -0.0228,0.29167 -0.0684,0.35547 -0.0547,0.0911 -0.21877,0.13216 -0.49219,0.12305 -1.03907,-0.0365 -2.55209,-0.0182 -4.53906,0.0547 -0.28256,0.009 -0.46485,-0.0137 -0.54688,-0.0684 -0.082,-0.0547 -0.12305,-0.1823 -0.12304,-0.38282 -10e-6,-0.23697 0.25975,-0.38281 0.77929,-0.4375 0.5651,-0.0638 0.84765,-0.57877 0.84766,-1.54492 l 0,-3.71875 c -10e-6,-1.0026 -0.22787,-1.77733 -0.68359,-2.32422 -0.40105,-0.49218 -0.91147,-0.73827 -1.53125,-0.73828 -0.91147,1e-5 -1.73178,0.18458 -2.46094,0.55371 -0.72917,0.36915 -1.09376,0.76336 -1.09375,1.18262 l 0,4.99023 c -1e-5,0.56511 0.14583,0.95704 0.4375,1.17579 0.26432,0.20052 0.74283,0.32356 1.43555,0.36914 0.37369,0.0182 0.56054,0.14583 0.56054,0.38281 0,0.26432 -0.15039,0.39648 -0.45117,0.39648 -2.27865,0 -3.92839,0.0638 -4.94922,0.19141 -0.34635,0.0456 -0.56966,0.0456 -0.66992,0 -0.082,-0.0456 -0.12305,-0.15495 -0.12305,-0.32813 0,-0.22786 0.33724,-0.42382 1.01172,-0.58789 0.41016,-0.10937 0.61523,-0.64257 0.61524,-1.59961 l 0,-4.19726 c -1e-5,-1.0664 -0.28711,-1.68163 -0.86133,-1.8457 -0.48308,-0.13671 -0.77702,-0.23697 -0.88184,-0.30079 -0.10482,-0.0638 -0.15722,-0.16861 -0.15722,-0.31445 0,-0.16405 0.47395,-0.51041 1.42187,-1.03906 1.0026,-0.56509 1.61784,-0.84765 1.8457,-0.84766 0.19141,1e-5 0.35319,0.27573 0.48536,0.82715 0.13215,0.55144 0.23469,0.82716 0.30761,0.82715 0.10026,10e-6 0.37825,-0.14127 0.83399,-0.42383 0.5651,-0.35546 1.07551,-0.61978 1.53125,-0.79297 0.74739,-0.29165 1.51757,-0.43749 2.31054,-0.4375 0.63802,1e-5 1.194,0.13673 1.66797,0.41016 0.32812,0.1823 0.62434,0.43295 0.88868,0.75195 0.21873,0.27345 0.32811,0.41017 0.32812,0.41016 -10e-6,1e-5 0.23697,-0.13671 0.71094,-0.41016 0.55597,-0.319 1.09829,-0.56965 1.62695,-0.75195 0.77472,-0.27343 1.52668,-0.41015 2.25586,-0.41016 2.49738,1e-5 3.74607,1.37176 3.74609,4.11524 l 0,4.42968 c -2e-5,0.51954 0.12303,0.88868 0.36914,1.10743 0.21873,0.18229 0.64712,0.33724 1.28516,0.46484 0.48305,0.0911 0.72459,0.22787 0.72461,0.41016 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2897" /> + <path + d="m 444.45782,160.98155 c -1e-5,0.39193 -0.52865,0.87956 -1.58593,1.46289 -1.20314,0.64714 -2.43816,0.97071 -3.70508,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47266,-1.35352 -1.0026,-0.95703 -1.5039,-2.23307 -1.5039,-3.82812 0,-1.80469 0.56054,-3.2539 1.68164,-4.34766 1.04817,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90233,1e-5 1.74543,0.28712 2.52929,0.86133 0.70182,0.51042 1.16666,1.09376 1.39453,1.75 0.082,0.22787 0.20507,0.35547 0.36914,0.38281 0.23697,0.0456 0.35546,0.20509 0.35547,0.47852 -10e-6,0.3737 -0.44662,0.69271 -1.33984,0.95703 l -6.30273,1.87304 c 0.41015,2.16928 1.52213,3.25391 3.33593,3.25391 1.04817,0 2.24218,-0.38281 3.58203,-1.14844 0.20051,-0.11848 0.39648,-0.17773 0.58789,-0.17773 0.14583,0 0.21874,0.13216 0.21875,0.39648 z m -3.24023,-5.48242 c -10e-6,-0.50129 -0.20281,-0.94107 -0.6084,-1.31934 -0.4056,-0.37824 -0.90463,-0.56737 -1.49707,-0.56738 -1.67709,10e-6 -2.51563,1.20769 -2.51562,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60155,-0.17317 0.90233,-0.48762 0.90234,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2899" /> + <path + d="m 460.86407,163.03233 c -1e-5,0.28256 -0.20509,0.41016 -0.61523,0.38282 -1.95965,-0.10026 -3.44532,-0.11849 -4.45703,-0.0547 -0.51954,0.0365 -0.80209,-0.0273 -0.84766,-0.19141 -0.0182,-0.0547 -0.0273,-0.13216 -0.0273,-0.23242 -1e-5,-0.18229 0.26431,-0.34635 0.79297,-0.49219 0.48306,-0.13672 0.7246,-0.60612 0.72461,-1.4082 l 0,-3.63672 c -1e-5,-2.08723 -0.90691,-3.13085 -2.72071,-3.13086 -0.8112,1e-5 -1.56315,0.19142 -2.25586,0.57422 -0.65625,0.37371 -0.98438,0.76108 -0.98437,1.16211 l 0,5.00391 c -1e-5,0.85677 0.56054,1.33528 1.68164,1.43554 0.42838,0.0365 0.64257,0.17318 0.64258,0.41016 -10e-6,0.22786 -0.0592,0.36458 -0.17774,0.41016 -0.0547,0.0182 -0.20964,0.0228 -0.46484,0.0137 -1.43099,-0.0547 -2.90756,0.0182 -4.42969,0.21875 -0.32812,0.0456 -0.5332,0.0592 -0.61523,0.041 -0.18229,-0.0365 -0.27344,-0.17773 -0.27344,-0.42383 0,-0.21874 0.25976,-0.40559 0.7793,-0.56054 0.48307,-0.14583 0.7246,-0.75195 0.72461,-1.81836 l 0,-4.14258 c -1e-5,-0.70182 -0.0912,-1.14843 -0.27344,-1.33984 -0.12761,-0.13671 -0.55143,-0.32812 -1.27148,-0.57422 -0.1823,-0.0638 -0.27344,-0.1914 -0.27344,-0.38281 0,-0.18229 0.18685,-0.34179 0.56054,-0.47852 0.51042,-0.1914 1.07097,-0.49674 1.68165,-0.91602 0.51041,-0.34634 0.83853,-0.51952 0.98437,-0.51953 0.24609,1e-5 0.41015,0.28029 0.49219,0.84082 0.082,0.56056 0.19596,0.84083 0.34179,0.84082 -0.0729,1e-5 0.39193,-0.26659 1.39454,-0.7998 1.00259,-0.53319 1.99152,-0.7998 2.96679,-0.79981 2.36067,1e-5 3.55012,1.34441 3.56836,4.03321 l 0.0273,4.40234 c -2e-5,0.56511 0.14582,0.97071 0.4375,1.2168 0.21873,0.18229 0.64256,0.33724 1.27148,0.46484 0.41014,0.082 0.61522,0.23242 0.61523,0.45117 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2901" /> + <path + d="m 469.64142,161.99327 c -10e-6,0.4375 -0.40105,0.8112 -1.20313,1.12109 -0.71094,0.27344 -1.43099,0.41016 -2.16015,0.41016 -1.97787,0 -2.9668,-1.05273 -2.9668,-3.1582 l 0,-4.94922 c 0,-0.6289 -0.0501,-1.01399 -0.15039,-1.15527 -0.10026,-0.14127 -0.43294,-0.28027 -0.99805,-0.417 -0.14583,-0.0365 -0.21875,-0.17772 -0.21875,-0.42382 0,-0.26432 0.0547,-0.42382 0.16407,-0.47852 0.98437,-0.48306 1.84114,-1.34895 2.57031,-2.59766 0.10025,-0.17316 0.29622,-0.22785 0.58789,-0.16406 0.20051,0.0638 0.30533,0.18231 0.31445,0.35547 l 0.0547,1.70898 c -10e-6,0.12762 0.0228,0.21876 0.0684,0.27344 0.0638,0.082 0.20963,0.12306 0.4375,0.12305 l 3.04883,0 c 0.17317,1e-5 0.17317,0.2142 0,0.64258 -0.20965,0.51954 -0.51954,0.7793 -0.92969,0.77929 l -2.06445,0 c -0.35548,1e-5 -0.57423,0.0593 -0.65625,0.17774 -0.0638,0.082 -0.0957,0.30535 -0.0957,0.66992 l 0,4.4707 c 0,1.13021 0.10026,1.84571 0.30078,2.14649 0.26432,0.38281 0.87956,0.57422 1.84571,0.57422 0.319,0 0.70637,-0.0524 1.16211,-0.15723 0.45572,-0.10482 0.69725,-0.15723 0.72461,-0.15723 0.10936,0 0.16405,0.0684 0.16406,0.20508 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2903" /> + <path + d="m 475.84845,162.60851 c -1e-5,2.36979 -0.99805,4.15168 -2.99414,5.3457 -0.18229,0.10937 -0.31446,0.16406 -0.39649,0.16406 -0.1276,0 -0.24609,-0.14584 -0.35546,-0.4375 -0.0365,-0.10026 -0.0547,-0.1823 -0.0547,-0.24609 0,-0.15495 0.25976,-0.41016 0.7793,-0.76563 0.89322,-0.61979 1.33984,-1.32161 1.33984,-2.10547 0,-0.40104 -0.25977,-0.76562 -0.7793,-1.09375 -0.72917,-0.45573 -1.09375,-1.01627 -1.09375,-1.68164 0,-0.44661 0.15039,-0.81803 0.45117,-1.11426 0.30078,-0.29622 0.70182,-0.44433 1.20313,-0.44433 0.60156,0 1.06868,0.21875 1.40137,0.65625 0.33267,0.4375 0.49901,1.01172 0.49902,1.72266 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2905" /> + <path + d="m 278.95978,182.96866 c -1e-5,1.58594 -0.58791,2.92806 -1.76367,4.02637 -1.1758,1.09831 -2.63413,1.64746 -4.375,1.64746 -1.74089,0 -3.1172,-0.48307 -4.12891,-1.44922 -0.97526,-0.94791 -1.46289,-2.20117 -1.46289,-3.75977 0,-1.61327 0.61523,-2.97134 1.8457,-4.07421 1.19401,-1.0664 2.62044,-1.5996 4.2793,-1.59961 1.77733,1e-5 3.16275,0.47852 4.15625,1.43554 0.96613,0.9297 1.44921,2.18751 1.44922,3.77344 z m -2.40625,0.83399 c -1e-5,-1.43099 -0.34637,-2.5931 -1.03906,-3.48633 -0.67449,-0.86588 -1.53126,-1.29882 -2.57032,-1.29883 -0.96615,1e-5 -1.75456,0.33953 -2.36523,1.01855 -0.61068,0.67905 -0.91602,1.5062 -0.91602,2.48145 0,1.56771 0.35547,2.78906 1.06641,3.66406 0.65624,0.80209 1.51301,1.20313 2.57031,1.20313 1.0026,0 1.79557,-0.33268 2.37891,-0.99805 0.58332,-0.66536 0.87499,-1.52669 0.875,-2.58398 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2907" /> + <path + d="m 295.59845,188.23233 c -2e-5,0.28255 -0.20509,0.41016 -0.61523,0.38282 -1.95965,-0.10027 -3.44533,-0.11849 -4.45704,-0.0547 -0.51954,0.0365 -0.80209,-0.0274 -0.84765,-0.19141 -0.0182,-0.0547 -0.0274,-0.13216 -0.0274,-0.23242 -1e-5,-0.18229 0.26432,-0.34635 0.79297,-0.49219 0.48306,-0.13672 0.7246,-0.60612 0.72461,-1.4082 l 0,-3.63672 c -10e-6,-2.08723 -0.90691,-3.13085 -2.7207,-3.13086 -0.81121,1e-5 -1.56316,0.19142 -2.25586,0.57422 -0.65626,0.37371 -0.98438,0.76107 -0.98438,1.16211 l 0,5.00391 c 0,0.85677 0.56055,1.33528 1.68165,1.43554 0.42837,0.0365 0.64257,0.17318 0.64257,0.41016 0,0.22786 -0.0593,0.36458 -0.17773,0.41015 -0.0547,0.0182 -0.20964,0.0228 -0.46484,0.0137 -1.431,-0.0547 -2.90756,0.0182 -4.42969,0.21875 -0.32813,0.0456 -0.53321,0.0592 -0.61524,0.041 -0.18229,-0.0365 -0.27344,-0.17773 -0.27343,-0.42383 -10e-6,-0.21875 0.25976,-0.40559 0.77929,-0.56054 0.48307,-0.14584 0.72461,-0.75195 0.72461,-1.81836 l 0,-4.14258 c 0,-0.70182 -0.0912,-1.14843 -0.27344,-1.33984 -0.1276,-0.13671 -0.55143,-0.32812 -1.27148,-0.57422 -0.18229,-0.0638 -0.27344,-0.1914 -0.27344,-0.38282 0,-0.18228 0.18685,-0.34178 0.56055,-0.47851 0.51041,-0.1914 1.07096,-0.49674 1.68164,-0.91602 0.51041,-0.34634 0.83854,-0.51952 0.98438,-0.51953 0.24608,1e-5 0.41015,0.28029 0.49218,0.84082 0.082,0.56056 0.19596,0.84083 0.3418,0.84082 -0.0729,1e-5 0.39192,-0.26659 1.39453,-0.7998 1.0026,-0.53319 1.99153,-0.7998 2.9668,-0.79981 2.36066,1e-5 3.55011,1.34441 3.56836,4.03321 l 0.0273,4.40234 c -10e-6,0.56511 0.14582,0.9707 0.4375,1.2168 0.21874,0.18229 0.64256,0.33724 1.27149,0.46484 0.41014,0.082 0.61521,0.23242 0.61523,0.45117 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2909" /> + <path + d="m 307.02814,186.18155 c -1e-5,0.39193 -0.52866,0.87956 -1.58594,1.46289 -1.20313,0.64714 -2.43816,0.97071 -3.70508,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47265,-1.35352 -1.00261,-0.95703 -1.50391,-2.23307 -1.50391,-3.82813 0,-1.80468 0.56054,-3.25389 1.68164,-4.34765 1.04817,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90233,1e-5 1.74543,0.28712 2.5293,0.86133 0.70181,0.51042 1.16665,1.09376 1.39453,1.75 0.082,0.22787 0.20506,0.35547 0.36914,0.38281 0.23697,0.0456 0.35545,0.20508 0.35547,0.47851 -2e-5,0.37371 -0.44663,0.69272 -1.33985,0.95704 l -6.30273,1.87304 c 0.41015,2.16928 1.52213,3.25391 3.33594,3.25391 1.04816,0 2.24217,-0.38281 3.58203,-1.14844 0.20051,-0.11849 0.39647,-0.17773 0.58789,-0.17773 0.14582,0 0.21874,0.13216 0.21875,0.39648 z m -3.24024,-5.48242 c -10e-6,-0.50129 -0.2028,-0.94107 -0.6084,-1.31934 -0.4056,-0.37824 -0.90462,-0.56737 -1.49707,-0.56738 -1.67708,1e-5 -2.51562,1.20769 -2.51562,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60155,-0.17317 0.90233,-0.48762 0.90234,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2911" /> + <path + d="m 328.91681,187.13858 c 0.0364,0.082 0.0547,0.14128 0.0547,0.17774 -2e-5,0.1914 -0.46486,0.50586 -1.39453,0.94336 -1.07554,0.5013 -1.709,0.75195 -1.9004,0.75195 -0.16407,0 -0.3532,-0.27572 -0.56738,-0.82715 -0.2142,-0.55143 -0.36231,-0.82715 -0.44433,-0.82715 0.009,0 -0.50815,0.23926 -1.55176,0.71778 -1.04363,0.47851 -1.83432,0.71777 -2.37207,0.71777 -1.20313,0 -2.24675,-0.43294 -3.13086,-1.29883 -1.06641,-1.02994 -1.59961,-2.4746 -1.59961,-4.33398 0,-1.55859 0.6289,-2.90299 1.88672,-4.03321 1.11197,-0.99348 2.24674,-1.49022 3.40429,-1.49023 0.82031,1e-5 1.80013,0.10483 2.93946,0.31445 0.35546,0.0638 0.53319,-0.041 0.5332,-0.31445 l 0,-4.67578 c -1e-5,-0.52863 -0.12761,-0.90233 -0.38281,-1.1211 -0.16407,-0.14581 -0.55144,-0.31899 -1.16211,-0.51953 -0.29168,-0.10935 -0.43751,-0.28709 -0.4375,-0.5332 -10e-6,-0.22785 0.19595,-0.39647 0.58789,-0.50586 0.53775,-0.16404 1.18033,-0.43748 1.92773,-0.82031 0.61978,-0.32811 1.0026,-0.49217 1.14844,-0.49219 0.33723,2e-5 0.50585,0.23244 0.50586,0.69727 -1e-5,-0.009 -0.0137,0.44435 -0.041,1.36035 -0.0274,0.91603 -0.041,1.80698 -0.041,2.67285 l 0,12.42773 c -1e-5,0.51954 0.23241,0.7793 0.69727,0.7793 0.17316,0 0.40558,-0.0273 0.69726,-0.082 0.319,-0.0547 0.53319,0.0501 0.64258,0.31445 z m -4.22461,-1.35351 0,-4.89453 c -1e-5,-0.40104 -0.35548,-0.81575 -1.06641,-1.24414 -0.75651,-0.45572 -1.57683,-0.68359 -2.46093,-0.6836 -1.90496,1e-5 -2.85743,1.17579 -2.85743,3.52735 0,1.25781 0.37826,2.33333 1.13477,3.22656 0.7565,0.89323 1.64518,1.33984 2.66602,1.33984 0.46483,0 1.01171,-0.15494 1.64062,-0.46484 0.6289,-0.3099 0.94335,-0.57878 0.94336,-0.80664 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2913" /> + <path + d="m 339.23907,178.78507 c -1e-5,1.10287 -0.31902,1.6543 -0.95703,1.65429 -0.10027,1e-5 -0.43295,-0.0638 -0.99804,-0.1914 -0.56511,-0.1276 -0.97983,-0.1914 -1.24414,-0.19141 -1.02084,1e-5 -1.53126,0.68816 -1.53125,2.06445 l 0,4.03321 c -10e-6,0.47396 0.16405,0.8112 0.49218,1.01172 0.1914,0.11849 0.66992,0.27799 1.43555,0.47851 0.41015,0.10026 0.61523,0.25521 0.61523,0.46485 0,0.24609 -0.0342,0.3942 -0.10253,0.44433 -0.0684,0.0501 -0.23927,0.0615 -0.5127,0.0342 -2.00521,-0.20963 -3.59115,-0.21875 -4.75781,-0.0273 -0.36459,0.0638 -0.59701,0.0638 -0.69727,0 -0.082,-0.0547 -0.12305,-0.21419 -0.12304,-0.47852 -1e-5,-0.24609 0.25292,-0.44205 0.75878,-0.58789 0.50586,-0.14583 0.75879,-0.58333 0.75879,-1.3125 l 0,-4.38867 c 0,-0.57421 -0.0752,-0.96158 -0.22558,-1.16211 -0.1504,-0.20051 -0.56283,-0.46939 -1.23731,-0.80664 l -0.082,-0.041 c -0.18229,-0.0911 -0.27344,-0.21874 -0.27344,-0.38281 0,-0.18228 0.18685,-0.33723 0.56055,-0.46484 0.6289,-0.21874 1.20312,-0.52864 1.72266,-0.92969 0.42838,-0.33723 0.70182,-0.50585 0.82031,-0.50586 0.32812,1e-5 0.52408,0.28256 0.58789,0.84766 0.082,0.72006 0.17773,1.08008 0.28711,1.08008 0.009,0 0.51953,-0.34179 1.53125,-1.0254 0.66536,-0.4466 1.39452,-0.66991 2.1875,-0.66992 0.65624,1e-5 0.98436,0.35092 0.98437,1.05274 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2915" /> + <path + d="m 352.7879,182.96866 c -10e-6,1.58594 -0.5879,2.92806 -1.76367,4.02637 -1.17579,1.09831 -2.63412,1.64746 -4.375,1.64746 -1.74089,0 -3.11719,-0.48307 -4.12891,-1.44922 -0.97526,-0.94791 -1.46289,-2.20117 -1.46289,-3.75977 0,-1.61327 0.61524,-2.97134 1.84571,-4.07421 1.194,-1.0664 2.62043,-1.5996 4.27929,-1.59961 1.77734,1e-5 3.16275,0.47852 4.15625,1.43554 0.96614,0.9297 1.44921,2.18751 1.44922,3.77344 z m -2.40625,0.83399 c -10e-6,-1.43099 -0.34636,-2.5931 -1.03906,-3.48633 -0.67449,-0.86588 -1.53126,-1.29882 -2.57031,-1.29883 -0.96615,1e-5 -1.75456,0.33953 -2.36524,1.01855 -0.61068,0.67905 -0.91602,1.5062 -0.91601,2.48145 -1e-5,1.56771 0.35546,2.78906 1.0664,3.66406 0.65625,0.80209 1.51302,1.20313 2.57032,1.20313 1.00259,0 1.79556,-0.33268 2.3789,-0.99805 0.58333,-0.66536 0.87499,-1.52669 0.875,-2.58398 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2917" /> + <path + d="m 367.07501,182.59952 c -1e-5,1.70443 -0.57195,3.15137 -1.71582,4.34082 -1.14389,1.18945 -2.4769,1.78418 -3.99902,1.78418 -0.92058,0 -1.80925,-0.16406 -2.66602,-0.49219 -0.0911,-0.0365 -0.13672,0.18685 -0.13672,0.66992 l 0,4.11524 c 0,0.66536 0.54232,1.09374 1.62696,1.28516 0.50129,0.0911 0.81802,0.17544 0.95019,0.25292 0.13216,0.0775 0.19824,0.20736 0.19824,0.38965 0,0.30989 -0.20508,0.45117 -0.61523,0.42383 -1.91407,-0.12761 -3.59571,-0.082 -5.04492,0.13672 -0.30078,0.0456 -0.48763,0.0456 -0.56055,0 -0.0729,-0.0456 -0.10937,-0.16863 -0.10937,-0.36914 0,-0.15495 0.25976,-0.3418 0.77929,-0.56055 0.44662,-0.18229 0.66992,-0.61979 0.66993,-1.3125 l 0,-12.05859 c -1e-5,-0.97525 -0.26889,-1.58593 -0.80665,-1.83203 -0.63802,-0.28254 -0.95703,-0.51497 -0.95703,-0.69727 0,-0.20051 0.18685,-0.3509 0.56055,-0.45117 0.48307,-0.11848 0.97982,-0.32811 1.49023,-0.62891 0.42839,-0.24608 0.68815,-0.36913 0.7793,-0.36914 0.27344,1e-5 0.49674,0.25067 0.66992,0.75196 0.25521,0.72917 0.42383,1.09376 0.50586,1.09375 0.0182,1e-5 0.41015,-0.21419 1.17578,-0.64258 0.83854,-0.46483 1.65885,-0.69726 2.46094,-0.69727 1.30338,1e-5 2.3789,0.36915 3.22656,1.10742 1.01171,0.8659 1.51757,2.11915 1.51758,3.75977 z m -2.32422,1.09375 c -10e-6,-1.48567 -0.36915,-2.64322 -1.10742,-3.47266 -0.60157,-0.6927 -1.30795,-1.03905 -2.11914,-1.03906 -0.62891,1e-5 -1.23047,0.21876 -1.80469,0.65625 -0.75651,0.56511 -1.13477,1.35352 -1.13476,2.36524 l 0,3.86914 c -1e-5,0.24609 0.34635,0.50586 1.03906,0.77929 0.74739,0.30079 1.55859,0.45118 2.43359,0.45118 1.79557,0 2.69335,-1.20313 2.69336,-3.60938 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2919" /> + <path + d="m 387.33673,187.16593 c -10e-6,0.1914 -0.34864,0.48079 -1.0459,0.86816 -0.69727,0.38737 -1.25554,0.58106 -1.6748,0.58106 -0.35548,0 -0.66993,-0.17318 -0.94336,-0.51954 -0.27345,-0.34635 -0.46485,-0.51953 -0.57422,-0.51953 -0.082,0 -0.51498,0.18685 -1.29883,0.56055 -0.78386,0.3737 -1.57227,0.56055 -2.36523,0.56055 -0.7474,0 -1.37175,-0.21875 -1.87305,-0.65625 -0.54688,-0.48308 -0.82031,-1.13932 -0.82031,-1.96875 0,-1.57682 1.80468,-2.70703 5.41406,-3.39063 0.61978,-0.11848 0.93424,-0.36913 0.94336,-0.75195 l 0.0273,-0.875 c 0.0547,-1.49478 -0.60612,-2.24218 -1.98242,-2.24219 -0.39193,1e-5 -0.76335,0.35092 -1.11426,1.05274 -0.35091,0.70183 -0.85449,1.08008 -1.51074,1.13476 -0.7474,0.0729 -1.12109,-0.24153 -1.12109,-0.94336 0,-0.43749 0.55598,-0.94791 1.66797,-1.53125 1.16666,-0.61067 2.28775,-0.916 3.36328,-0.91601 1.85025,1e-5 2.76626,0.87956 2.74804,2.63867 l -0.0547,5.63281 c -0.009,0.59245 0.24152,0.88867 0.75195,0.88867 0.10025,0 0.29166,-0.0228 0.57422,-0.0684 0.28254,-0.0456 0.4466,-0.0683 0.49219,-0.0684 0.26431,1e-5 0.39647,0.17774 0.39648,0.53321 z m -4.21094,-3.11719 c 0.009,-0.22786 -0.0433,-0.37825 -0.15722,-0.45117 -0.11394,-0.0729 -0.29396,-0.0866 -0.54004,-0.041 -2.19662,0.39193 -3.29493,1.10743 -3.29492,2.14649 -10e-6,1.04817 0.56965,1.57226 1.70898,1.57226 0.45572,0 0.92512,-0.0866 1.4082,-0.25976 0.5651,-0.20052 0.84765,-0.44206 0.84766,-0.72461 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2921" /> + <path + d="m 396.52423,187.19327 c -10e-6,0.4375 -0.40105,0.8112 -1.20312,1.12109 -0.71095,0.27344 -1.431,0.41016 -2.16016,0.41016 -1.97787,0 -2.9668,-1.05273 -2.9668,-3.1582 l 0,-4.94922 c 0,-0.6289 -0.0501,-1.01399 -0.15039,-1.15528 -0.10026,-0.14126 -0.43294,-0.28026 -0.99804,-0.41699 -0.14584,-0.0365 -0.21876,-0.17772 -0.21875,-0.42383 -1e-5,-0.26431 0.0547,-0.42381 0.16406,-0.47851 0.98437,-0.48306 1.84114,-1.34895 2.57031,-2.59766 0.10026,-0.17316 0.29622,-0.22785 0.58789,-0.16406 0.20052,0.0638 0.30533,0.1823 0.31445,0.35547 l 0.0547,1.70898 c 0,0.12762 0.0228,0.21876 0.0684,0.27344 0.0638,0.082 0.20963,0.12306 0.4375,0.12305 l 3.04883,0 c 0.17317,1e-5 0.17317,0.2142 0,0.64258 -0.20964,0.51954 -0.51954,0.7793 -0.92969,0.77929 l -2.06445,0 c -0.35548,1e-5 -0.57422,0.0593 -0.65625,0.17774 -0.0638,0.082 -0.0957,0.30534 -0.0957,0.66992 l 0,4.4707 c -1e-5,1.13021 0.10025,1.84571 0.30078,2.14649 0.26431,0.38281 0.87955,0.57422 1.8457,0.57422 0.319,0 0.70637,-0.0524 1.16211,-0.15723 0.45572,-0.10482 0.69726,-0.15723 0.72461,-0.15723 0.10936,0 0.16405,0.0684 0.16406,0.20508 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2923" /> + <path + d="m 416.32111,187.16593 c -2e-5,0.1914 -0.34865,0.48079 -1.0459,0.86816 -0.69728,0.38737 -1.25555,0.58106 -1.67481,0.58106 -0.35547,0 -0.66993,-0.17318 -0.94336,-0.51954 -0.27344,-0.34635 -0.46485,-0.51953 -0.57422,-0.51953 -0.082,0 -0.51498,0.18685 -1.29882,0.56055 -0.78386,0.3737 -1.57227,0.56055 -2.36524,0.56055 -0.7474,0 -1.37175,-0.21875 -1.87304,-0.65625 -0.54688,-0.48308 -0.82032,-1.13932 -0.82032,-1.96875 0,-1.57682 1.80469,-2.70703 5.41407,-3.39063 0.61978,-0.11848 0.93423,-0.36913 0.94335,-0.75195 l 0.0273,-0.875 c 0.0547,-1.49478 -0.60613,-2.24218 -1.98242,-2.24219 -0.39194,1e-5 -0.76335,0.35092 -1.11426,1.05274 -0.35092,0.70183 -0.8545,1.08008 -1.51074,1.13476 -0.7474,0.0729 -1.1211,-0.24153 -1.1211,-0.94336 0,-0.43749 0.55599,-0.94791 1.66797,-1.53125 1.16666,-0.61067 2.28776,-0.916 3.36328,-0.91601 1.85025,1e-5 2.76627,0.87956 2.74805,2.63867 l -0.0547,5.63281 c -0.009,0.59245 0.24153,0.88867 0.75196,0.88867 0.10025,0 0.29165,-0.0228 0.57421,-0.0684 0.28254,-0.0456 0.44661,-0.0683 0.49219,-0.0684 0.26431,1e-5 0.39647,0.17774 0.39649,0.53321 z m -4.21094,-3.11719 c 0.009,-0.22786 -0.0433,-0.37825 -0.15723,-0.45117 -0.11394,-0.0729 -0.29395,-0.0866 -0.54004,-0.041 -2.19662,0.39193 -3.29492,1.10743 -3.29492,2.14649 0,1.04817 0.56966,1.57226 1.70899,1.57226 0.45572,0 0.92512,-0.0866 1.4082,-0.25976 0.5651,-0.20052 0.84765,-0.44206 0.84765,-0.72461 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2925" /> + <path + d="m 432.45392,187.19327 c -10e-6,0.4375 -0.40105,0.8112 -1.20313,1.12109 -0.71094,0.27344 -1.43099,0.41016 -2.16015,0.41016 -1.97787,0 -2.9668,-1.05273 -2.9668,-3.1582 l 0,-4.94922 c 0,-0.6289 -0.0501,-1.01399 -0.15039,-1.15528 -0.10026,-0.14126 -0.43294,-0.28026 -0.99805,-0.41699 -0.14583,-0.0365 -0.21875,-0.17772 -0.21875,-0.42383 0,-0.26431 0.0547,-0.42381 0.16407,-0.47851 0.98437,-0.48306 1.84114,-1.34895 2.57031,-2.59766 0.10025,-0.17316 0.29622,-0.22785 0.58789,-0.16406 0.20051,0.0638 0.30533,0.1823 0.31445,0.35547 l 0.0547,1.70898 c -10e-6,0.12762 0.0228,0.21876 0.0684,0.27344 0.0638,0.082 0.20963,0.12306 0.4375,0.12305 l 3.04883,0 c 0.17317,1e-5 0.17317,0.2142 0,0.64258 -0.20965,0.51954 -0.51954,0.7793 -0.92969,0.77929 l -2.06445,0 c -0.35548,1e-5 -0.57423,0.0593 -0.65625,0.17774 -0.0638,0.082 -0.0957,0.30534 -0.0957,0.66992 l 0,4.4707 c 0,1.13021 0.10026,1.84571 0.30078,2.14649 0.26432,0.38281 0.87956,0.57422 1.84571,0.57422 0.319,0 0.70637,-0.0524 1.16211,-0.15723 0.45572,-0.10482 0.69725,-0.15723 0.72461,-0.15723 0.10936,0 0.16405,0.0684 0.16406,0.20508 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2927" /> + <path + d="m 439.30353,172.66007 c -1e-5,0.41928 -0.15723,0.80893 -0.47168,1.16894 -0.31446,0.36004 -0.65854,0.54006 -1.03223,0.54004 -0.42839,2e-5 -0.7793,-0.12759 -1.05273,-0.38281 -0.27344,-0.25519 -0.41016,-0.58788 -0.41016,-0.99805 0,-0.40102 0.16634,-0.77472 0.49902,-1.12109 0.33268,-0.34634 0.69043,-0.51952 1.07325,-0.51953 0.92968,1e-5 1.39452,0.43751 1.39453,1.3125 z m 1.51758,15.47656 c -0.0456,0.26432 -0.15496,0.41471 -0.32813,0.45117 -0.0456,0.009 -0.26433,0 -0.65625,-0.0273 -1.35808,-0.0911 -2.69336,-0.0729 -4.00586,0.0547 -0.35547,0.0365 -0.57878,0.0228 -0.66992,-0.041 -0.0912,-0.0638 -0.13672,-0.20964 -0.13672,-0.4375 0,-0.20964 0.24154,-0.38281 0.72461,-0.51953 0.52864,-0.15495 0.79297,-0.66081 0.79297,-1.51758 l 0,-3.58203 c 0,-0.72005 -0.0729,-1.22591 -0.21875,-1.51758 -0.20052,-0.40103 -0.61524,-0.70637 -1.24414,-0.91601 -0.28256,-0.10026 -0.42383,-0.25065 -0.42383,-0.45118 0,-0.26431 0.20508,-0.46027 0.61523,-0.58789 0.76563,-0.23697 1.44466,-0.55142 2.03711,-0.94336 0.47396,-0.32811 0.76562,-0.49217 0.875,-0.49218 0.36458,1e-5 0.54232,0.23699 0.53321,0.71093 -0.0365,2.38803 -0.0547,4.82162 -0.0547,7.30078 -10e-6,0.59245 0.0866,1.01628 0.25977,1.27149 0.1914,0.28255 0.55598,0.48307 1.09375,0.60156 0.59244,0.13672 0.86132,0.35091 0.80664,0.64258 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2929" /> + <path + d="m 464.89728,188.10929 c -3e-5,0.30078 -0.1413,0.44205 -0.42383,0.42382 -1.8594,-0.13671 -3.59117,-0.13671 -5.19531,0 -0.35549,0.0274 -0.53322,-0.13216 -0.53321,-0.47851 -1e-5,-0.27344 0.24152,-0.41927 0.72461,-0.4375 0.61066,-0.0365 0.916,-0.5332 0.91602,-1.49024 l 0,-3.63671 c -2e-5,-2.04166 -0.82945,-3.0625 -2.48828,-3.0625 -0.87502,0 -1.6771,0.15951 -2.40625,0.47851 -0.66538,0.28256 -1.00262,0.56511 -1.01172,0.84766 l -0.0547,5.42773 c -10e-6,0.56511 0.0684,0.9388 0.20508,1.1211 0.10025,0.1276 0.32355,0.21875 0.66992,0.27343 0.80207,0.13672 1.20311,0.30534 1.20313,0.50586 -2e-5,0.17318 -0.0228,0.29167 -0.0684,0.35547 -0.0547,0.0911 -0.21877,0.13216 -0.49219,0.12305 -1.03908,-0.0365 -2.5521,-0.0182 -4.53906,0.0547 -0.28256,0.009 -0.46486,-0.0137 -0.54688,-0.0684 -0.082,-0.0547 -0.12305,-0.1823 -0.12304,-0.38282 -10e-6,-0.23698 0.25975,-0.38281 0.77929,-0.4375 0.5651,-0.0638 0.84765,-0.57877 0.84766,-1.54492 l 0,-3.71875 c -10e-6,-1.0026 -0.22788,-1.77733 -0.6836,-2.32422 -0.40105,-0.49218 -0.91146,-0.73827 -1.53125,-0.73828 -0.91146,1e-5 -1.73177,0.18458 -2.46093,0.55371 -0.72917,0.36915 -1.09376,0.76336 -1.09375,1.18262 l 0,4.99023 c -1e-5,0.56511 0.14583,0.95704 0.4375,1.17579 0.26431,0.20052 0.74283,0.32356 1.43554,0.36914 0.37369,0.0182 0.56054,0.14583 0.56055,0.38281 -10e-6,0.26432 -0.1504,0.39648 -0.45117,0.39648 -2.27865,0 -3.92839,0.0638 -4.94922,0.19141 -0.34636,0.0456 -0.56966,0.0456 -0.66992,0 -0.082,-0.0456 -0.12305,-0.15495 -0.12305,-0.32813 0,-0.22786 0.33724,-0.42382 1.01172,-0.58789 0.41015,-0.10937 0.61523,-0.64257 0.61523,-1.59961 l 0,-4.19726 c 0,-1.0664 -0.28711,-1.68163 -0.86132,-1.8457 -0.48308,-0.13672 -0.77702,-0.23698 -0.88184,-0.30079 -0.10482,-0.0638 -0.15723,-0.16861 -0.15723,-0.31445 0,-0.16405 0.47396,-0.51041 1.42188,-1.03906 1.0026,-0.5651 1.61783,-0.84765 1.8457,-0.84766 0.1914,1e-5 0.35319,0.27573 0.48535,0.82715 0.13216,0.55144 0.2347,0.82716 0.30762,0.82715 0.10026,1e-5 0.37825,-0.14127 0.83399,-0.42383 0.56509,-0.35546 1.07551,-0.61978 1.53125,-0.79297 0.74738,-0.29165 1.51756,-0.43749 2.31054,-0.4375 0.63801,1e-5 1.194,0.13673 1.66797,0.41016 0.32811,0.1823 0.62434,0.43295 0.88867,0.75195 0.21874,0.27345 0.32812,0.41017 0.32813,0.41016 -10e-6,1e-5 0.23696,-0.13671 0.71094,-0.41016 0.55597,-0.319 1.09829,-0.56965 1.62695,-0.75195 0.77472,-0.27343 1.52667,-0.41015 2.25586,-0.41016 2.49737,1e-5 3.74607,1.37176 3.74609,4.11524 l 0,4.42968 c -2e-5,0.51954 0.12303,0.88868 0.36914,1.10743 0.21873,0.18229 0.64712,0.33724 1.28516,0.46484 0.48305,0.0911 0.72458,0.22786 0.72461,0.41016 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2931" /> + <path + d="m 476.45001,186.18155 c -1e-5,0.39193 -0.52865,0.87956 -1.58594,1.46289 -1.20313,0.64714 -2.43815,0.97071 -3.70507,0.97071 -1.37631,0 -2.53386,-0.45118 -3.47266,-1.35352 -1.00261,-0.95703 -1.50391,-2.23307 -1.50391,-3.82813 0,-1.80468 0.56055,-3.25389 1.68164,-4.34765 1.04818,-1.02082 2.33333,-1.53124 3.85547,-1.53125 0.90234,1e-5 1.74544,0.28712 2.5293,0.86133 0.70181,0.51042 1.16666,1.09376 1.39453,1.75 0.082,0.22787 0.20507,0.35547 0.36914,0.38281 0.23697,0.0456 0.35546,0.20508 0.35547,0.47851 -10e-6,0.37371 -0.44662,0.69272 -1.33984,0.95704 l -6.30274,1.87304 c 0.41016,2.16928 1.52213,3.25391 3.33594,3.25391 1.04817,0 2.24218,-0.38281 3.58203,-1.14844 0.20051,-0.11849 0.39648,-0.17773 0.58789,-0.17773 0.14582,0 0.21874,0.13216 0.21875,0.39648 z m -3.24023,-5.48242 c -1e-5,-0.50129 -0.20281,-0.94107 -0.6084,-1.31934 -0.40561,-0.37824 -0.90463,-0.56737 -1.49707,-0.56738 -1.67709,1e-5 -2.51563,1.20769 -2.51563,3.62305 l 0,0.32812 3.71875,-1.12109 c 0.60156,-0.17317 0.90234,-0.48762 0.90235,-0.94336 z" + style="font-size:28px;font-variant:normal;font-stretch:normal;text-align:end;line-height:89.99999762%;writing-mode:lr-tb;text-anchor:end;font-family:High Tower Text;-inkscape-font-specification:High Tower Text" + id="path2933" /> + </g> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/.gitignore Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,1 @@ +_build
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/Makefile Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,118 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +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 singlehtml pickle json htmlhelp qthelp epub 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 " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " 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." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) _build/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Flask" + @echo "# ln -s _build/devhelp $$HOME/.local/share/devhelp/Flask" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @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." + +latexpdf: latex + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex + @echo "Running LaTeX files through pdflatex..." + make -C _build/latex all-pdf + @echo "pdflatex finished; the PDF files are in _build/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."
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/_templates/sidebarintro.html Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,21 @@ +<h3>About Flask</h3> +<p> + Flask is a micro webdevelopment framework for Python. You are currently + looking at the documentation of the development version. Things are + not stable yet, but if you have some feedback, + <a href="mailto:armin.ronacher@active-4.com">let me know</a>. +</p> +<h3>Other Formats</h3> +<p> + You can download the documentation in other formats as well: +</p> +<ul> + <li><a href="http://flask.pocoo.org/docs/flask-docs.pdf">as PDF</a> + <li><a href="http://flask.pocoo.org/docs/flask-docs.zip">as zipped HTML</a> +</ul> +<h3>Useful Links</h3> +<ul> + <li><a href="http://flask.pocoo.org/">The Flask Website</a></li> + <li><a href="http://pypi.python.org/pypi/Flask">Flask @ PyPI</a></li> + <li><a href="http://github.com/mitsuhiko/flask">Flask @ github</a></li> +</ul>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/_templates/sidebarlogo.html Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,3 @@ +<p class="logo"><a href="{{ pathto(master_doc) }}"> + <img class="logo" src="{{ pathto('_static/flask.png', 1) }}" alt="Logo"/> +</a></p>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/api.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,441 @@ +.. _api: + +API +=== + +.. module:: flask + +This part of the documentation covers all the interfaces of Flask. For +parts where Flask depends on external libraries, we document the most +important right here and provide links to the canonical documentation. + + +Application Object +------------------ + +.. autoclass:: Flask + :members: + :inherited-members: + + +Module Objects +-------------- + +.. autoclass:: Module + :members: + :inherited-members: + +Incoming Request Data +--------------------- + +.. autoclass:: Request + +.. class:: request + + To access incoming request data, you can use the global `request` + object. Flask parses incoming request data for you and gives you + access to it through that global object. Internally Flask makes + sure that you always get the correct data for the active thread if you + are in a multithreaded environment. + + This is a proxy. See :ref:`notes-on-proxies` for more information. + + The request object is an instance of a :class:`~werkzeug.Request` + subclass and provides all of the attributes Werkzeug defines. This + just shows a quick overview of the most important ones. + + .. attribute:: form + + A :class:`~werkzeug.MultiDict` with the parsed form data from `POST` + or `PUT` requests. Please keep in mind that file uploads will not + end up here, but instead in the :attr:`files` attribute. + + .. attribute:: args + + A :class:`~werkzeug.MultiDict` with the parsed contents of the query + string. (The part in the URL after the question mark). + + .. attribute:: values + + A :class:`~werkzeug.CombinedMultiDict` with the contents of both + :attr:`form` and :attr:`args`. + + .. attribute:: cookies + + A :class:`dict` with the contents of all cookies transmitted with + the request. + + .. attribute:: stream + + If the incoming form data was not encoded with a known mimetype + the data is stored unmodified in this stream for consumption. Most + of the time it is a better idea to use :attr:`data` which will give + you that data as a string. The stream only returns the data once. + + .. attribute:: data + + Contains the incoming request data as string in case it came with + a mimetype Flask does not handle. + + .. attribute:: files + + A :class:`~werkzeug.MultiDict` with files uploaded as part of a + `POST` or `PUT` request. Each file is stored as + :class:`~werkzeug.FileStorage` object. It basically behaves like a + standard file object you know from Python, with the difference that + it also has a :meth:`~werkzeug.FileStorage.save` function that can + store the file on the filesystem. + + .. attribute:: environ + + The underlying WSGI environment. + + .. attribute:: method + + The current request method (``POST``, ``GET`` etc.) + + .. attribute:: path + .. attribute:: script_root + .. attribute:: url + .. attribute:: base_url + .. attribute:: url_root + + Provides different ways to look at the current URL. Imagine your + application is listening on the following URL:: + + http://www.example.com/myapplication + + And a user requests the following URL:: + + http://www.example.com/myapplication/page.html?x=y + + In this case the values of the above mentioned attributes would be + the following: + + ============= ====================================================== + `path` ``/page.html`` + `script_root` ``/myapplication`` + `base_url` ``http://www.example.com/myapplication/page.html`` + `url` ``http://www.example.com/myapplication/page.html?x=y`` + `url_root` ``http://www.example.com/myapplication/`` + ============= ====================================================== + + .. attribute:: is_xhr + + `True` if the request was triggered via a JavaScript + `XMLHttpRequest`. This only works with libraries that support the + ``X-Requested-With`` header and set it to `XMLHttpRequest`. + Libraries that do that are prototype, jQuery and Mochikit and + probably some more. + + .. attribute:: json + + Contains the parsed body of the JSON request if the mimetype of + the incoming data was `application/json`. This requires Python 2.6 + or an installed version of simplejson. + +Response Objects +---------------- + +.. autoclass:: flask.Response + :members: set_cookie, data, mimetype + + .. attribute:: headers + + A :class:`Headers` object representing the response headers. + + .. attribute:: status_code + + The response status as integer. + + +Sessions +-------- + +If you have the :attr:`Flask.secret_key` set you can use sessions in Flask +applications. A session basically makes it possible to remember +information from one request to another. The way Flask does this is by +using a signed cookie. So the user can look at the session contents, but +not modify it unless he knows the secret key, so make sure to set that to +something complex and unguessable. + +To access the current session you can use the :class:`session` object: + +.. class:: session + + The session object works pretty much like an ordinary dict, with the + difference that it keeps track on modifications. + + This is a proxy. See :ref:`notes-on-proxies` for more information. + + The following attributes are interesting: + + .. attribute:: new + + `True` if the session is new, `False` otherwise. + + .. attribute:: modified + + `True` if the session object detected a modification. Be advised + that modifications on mutable structures are not picked up + automatically, in that situation you have to explicitly set the + attribute to `True` yourself. Here an example:: + + # this change is not picked up because a mutable object (here + # a list) is changed. + session['objects'].append(42) + # so mark it as modified yourself + session.modified = True + + .. attribute:: permanent + + If set to `True` the session lives for + :attr:`~flask.Flask.permanent_session_lifetime` seconds. The + default is 31 days. If set to `False` (which is the default) the + session will be deleted when the user closes the browser. + + +Application Globals +------------------- + +To share data that is valid for one request only from one function to +another, a global variable is not good enough because it would break in +threaded environments. Flask provides you with a special object that +ensures it is only valid for the active request and that will return +different values for each request. In a nutshell: it does the right +thing, like it does for :class:`request` and :class:`session`. + +.. data:: g + + Just store on this whatever you want. For example a database + connection or the user that is currently logged in. + + This is a proxy. See :ref:`notes-on-proxies` for more information. + + +Useful Functions and Classes +---------------------------- + +.. data:: current_app + + Points to the application handling the request. This is useful for + extensions that want to support multiple applications running side + by side. + + This is a proxy. See :ref:`notes-on-proxies` for more information. + +.. autofunction:: url_for + +.. function:: abort(code) + + Raises an :exc:`~werkzeug.exception.HTTPException` for the given + status code. For example to abort request handling with a page not + found exception, you would call ``abort(404)``. + + :param code: the HTTP error code. + +.. autofunction:: redirect + +.. autofunction:: make_response + +.. autofunction:: send_file + +.. autofunction:: send_from_directory + +.. autofunction:: escape + +.. autoclass:: Markup + :members: escape, unescape, striptags + +Message Flashing +---------------- + +.. autofunction:: flash + +.. autofunction:: get_flashed_messages + +Returning JSON +-------------- + +.. autofunction:: jsonify + +.. data:: json + + If JSON support is picked up, this will be the module that Flask is + using to parse and serialize JSON. So instead of doing this yourself:: + + try: + import simplejson as json + except ImportError: + import json + + You can instead just do this:: + + from flask import json + + For usage examples, read the :mod:`json` documentation. + + The :func:`~json.dumps` function of this json module is also available + as filter called ``|tojson`` in Jinja2. Note that inside `script` + tags no escaping must take place, so make sure to disable escaping + with ``|safe`` if you intend to use it inside `script` tags: + + .. sourcecode:: html+jinja + + <script type=text/javascript> + doSomethingWith({{ user.username|tojson|safe }}); + </script> + + Note that the ``|tojson`` filter escapes forward slashes properly. + +Template Rendering +------------------ + +.. autofunction:: render_template + +.. autofunction:: render_template_string + +.. autofunction:: get_template_attribute + +Configuration +------------- + +.. autoclass:: Config + :members: + +Useful Internals +---------------- + +.. data:: _request_ctx_stack + + The internal :class:`~werkzeug.LocalStack` that is used to implement + all the context local objects used in Flask. This is a documented + instance and can be used by extensions and application code but the + use is discouraged in general. + + The following attributes are always present on each layer of the + stack: + + `app` + the active Flask application. + + `url_adapter` + the URL adapter that was used to match the request. + + `request` + the current request object. + + `session` + the active session object. + + `g` + an object with all the attributes of the :data:`flask.g` object. + + `flashes` + an internal cache for the flashed messages. + + Example usage:: + + from flask import _request_ctx_stack + + def get_session(): + ctx = _request_ctx_stack.top + if ctx is not None: + return ctx.session + + .. versionchanged:: 0.4 + + The request context is automatically popped at the end of the request + for you. In debug mode the request context is kept around if + exceptions happen so that interactive debuggers have a chance to + introspect the data. With 0.4 this can also be forced for requests + that did not fail and outside of `DEBUG` mode. By setting + ``'flask._preserve_context'`` to `True` on the WSGI environment the + context will not pop itself at the end of the request. This is used by + the :meth:`~flask.Flask.test_client` for example to implement the + deferred cleanup functionality. + + You might find this helpful for unittests where you need the + information from the context local around for a little longer. Make + sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in + that situation, otherwise your unittests will leak memory. + +Signals +------- + +.. when modifying this list, also update the one in signals.rst + +.. versionadded:: 0.6 + +.. data:: signals_available + + `True` if the signalling system is available. This is the case + when `blinker`_ is installed. + +.. data:: template_rendered + + This signal is sent when a template was successfully rendered. The + signal is invoked with the instance of the template as `template` + and the context as dictionary (named `context`). + +.. data:: request_started + + This signal is sent before any request processing started but when the + request context was set up. Because the request context is already + bound, the subscriber can access the request with the standard global + proxies such as :class:`~flask.request`. + +.. data:: request_finished + + This signal is sent right before the response is sent to the client. + It is passed the response to be sent named `response`. + +.. data:: got_request_exception + + This signal is sent when an exception happens during request processing. + It is sent *before* the standard exception handling kicks in and even + in debug mode, where no exception handling happens. The exception + itself is passed to the subscriber as `exception`. + +.. currentmodule:: None + +.. class:: flask.signals.Namespace + + An alias for :class:`blinker.base.Namespace` if blinker is available, + otherwise a dummy class that creates fake signals. This class is + available for Flask extensions that want to provide the same fallback + system as Flask itself. + + .. method:: signal(name, doc=None) + + Creates a new signal for this namespace if blinker is available, + otherwise returns a fake signal that has a send method that will + do nothing but will fail with a :exc:`RuntimeError` for all other + operations, including connecting. + +.. _blinker: http://pypi.python.org/pypi/blinker + +.. _notes-on-proxies: + +Notes On Proxies +---------------- + +Some of the objects provided by Flask are proxies to other objects. The +reason behind this is that these proxies are shared between threads and +they have to dispatch to the actual object bound to a thread behind the +scenes as necessary. + +Most of the time you don't have to care about that, but there are some +exceptions where it is good to know that this object is an actual proxy: + +- The proxy objects do not fake their inherited types, so if you want to + perform actual instance checks, you have to do that on the instance + that is being proxied (see `_get_current_object` below). +- if the object reference is important (so for example for sending + :ref:`signals`) + +If you need to get access to the underlying object that is proxied, you +can use the :meth:`~werkzeug.LocalProxy._get_current_object` method:: + + app = current_app._get_current_object() + my_signal.send(app)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/becomingbig.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,88 @@ +.. _becomingbig: + +Becoming Big +============ + +Your application is becoming more and more complex? If you suddenly +realize that Flask does things in a way that does not work out for your +application there are ways to deal with that. + +Flask is powered by Werkzeug and Jinja2, two libraries that are in use at +a number of large websites out there and all Flask does is bring those +two together. Being a microframework Flask does not do much more than +combining existing libraries - there is not a lot of code involved. +What that means for large applications is that it's very easy to take the +code from Flask and put it into a new module within the applications and +expand on that. + +Flask is designed to be extended and modified in a couple of different +ways: + +- Flask extensions. For a lot of reusable functionality you can create + extensions. For extensions a number of hooks exist throughout Flask + with signals and callback functions. + +- Subclassing. The majority of functionality can be changed by creating + a new subclass of the :class:`~flask.Flask` class and overriding + methods provided for this exact purpose. + +- Forking. If nothing else works out you can just take the Flask + codebase at a given point and copy/paste it into your application + and change it. Flask is designed with that in mind and makes this + incredible easy. You just have to take the package and copy it + into your application's code and rename it (for example to + `framework`). Then you can start modifying the code in there. + +Why consider Forking? +--------------------- + +The majority of code of Flask is within Werkzeug and Jinja2. These +libraries do the majority of the work. Flask is just the paste that glues +those together. For every project there is the point where the underlying +framework gets in the way (due to assumptions the original developers +had). This is natural because if this would not be the case, the +framework would be a very complex system to begin with which causes a +steep learning curve and a lot of user frustration. + +This is not unique to Flask. Many people use patched and modified +versions of their framework to counter shortcomings. This idea is also +reflected in the license of Flask. You don't have to contribute any +changes back if you decide to modify the framework. + +The downside of forking is of course that Flask extensions will most +likely break because the new framework has a different import name. +Furthermore integrating upstream changes can be a complex process, +depending on the number of changes. Because of that, forking should be +the very last resort. + +Scaling like a Pro +------------------ + +For many web applications the complexity of the code is less an issue than +the scaling for the number of users or data entries expected. Flask by +itself is only limited in terms of scaling by your application code, the +data store you want to use and the Python implementation and webserver you +are running on. + +Scaling well means for example that if you double the amount of servers +you get about twice the performance. Scaling bad means that if you add a +new server the application won't perform any better or would not even +support a second server. + +There is only one limiting factor regarding scaling in Flask which are +the context local proxies. They depend on context which in Flask is +defined as being either a thread, process or greenlet. If your server +uses some kind of concurrency that is not based on threads or greenlets, +Flask will no longer be able to support these global proxies. However the +majority of servers are using either threads, greenlets or separate +processes to achieve concurrency which are all methods well supported by +the underlying Werkzeug library. + +Dialogue with the Community +--------------------------- + +The Flask developers are very interested to keep everybody happy, so as +soon as you find an obstacle in your way, caused by Flask, don't hesitate +to contact the developers on the mailinglist or IRC channel. The best way +for the Flask and Flask-extension developers to improve it for larger +applications is getting feedback from users.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/changelog.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,1 @@ +.. include:: ../CHANGES
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/conf.py Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +# +# Flask documentation build configuration file, created by +# sphinx-quickstart on Tue Apr 6 15:24:58 2010. +# +# 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('_themes')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] + +# 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-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Flask' +copyright = u'2010, Armin Ronacher' + +# 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. +import pkg_resources +try: + release = pkg_resources.get_distribution('Flask').version +except pkg_resources.DistributionNotFound: + print 'To build the documentation, The distribution information of Flask' + print 'Has to be available. Either install the package into your' + print 'development environment or run "setup.py develop" to setup the' + print 'metadata. A virtualenv is recommended!' + sys.exit(1) +del pkg_resources + +if 'dev' in release: + release = release.split('dev')[0] + 'dev' +version = '.'.join(release.split('.')[:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# 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 = 'flask' + +# 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 = { + 'touch_icon': 'touch-icon.png' +} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = ['_themes'] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# 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. Do not set, template magic! +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%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 = { + 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], + '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', + 'sourcelink.html', 'searchbox.html'] +} + +# 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 = False + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# 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 = 'Flaskdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('latexindex', 'Flask.tex', u'Flask Documentation', + u'Armin Ronacher', 'manual'), +] + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +latex_use_modindex = False + +latex_elements = { + 'fontpkg': r'\usepackage{mathpazo}', + 'papersize': 'a4paper', + 'pointsize': '12pt', + 'preamble': r'\usepackage{flaskstyle}' +} +latex_use_parts = True + +latex_additional_files = ['flaskstyle.sty', 'logo.pdf'] + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +#epub_title = '' +#epub_author = '' +#epub_publisher = '' +#epub_copyright = '' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +intersphinx_mapping = { + 'http://docs.python.org/dev': None, + 'http://werkzeug.pocoo.org/docs/': None, + 'http://www.sqlalchemy.org/docs/': None, + 'http://wtforms.simplecodes.com/docs/0.5/': None, + 'http://discorporate.us/projects/Blinker/docs/1.1/': None +} + +pygments_style = 'flask_theme_support.FlaskyStyle' + +# fall back if theme is not there +try: + __import__('flask_theme_support') +except ImportError, e: + print '-' * 74 + print 'Warning: Flask themes unavailable. Building with default theme' + print 'If you want the Flask themes, run this command and build again:' + print + print ' git submodule update --init' + print '-' * 74 + + pygments_style = 'tango' + html_theme = 'default' + html_theme_options = {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/config.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,236 @@ +.. _config: + +Configuration Handling +====================== + +.. versionadded:: 0.3 + +Applications need some kind of configuration. There are different things +you might want to change like toggling debug mode, the secret key, and a +lot of very similar things. + +The way Flask is designed usually requires the configuration to be +available when the application starts up. You can hardcode the +configuration in the code, which for many small applications is not +actually that bad, but there are better ways. + +Independent of how you load your config, there is a config object +available which holds the loaded configuration values: +The :attr:`~flask.Flask.config` attribute of the :class:`~flask.Flask` +object. This is the place where Flask itself puts certain configuration +values and also where extensions can put their configuration values. But +this is also where you can have your own configuration. + +Configuration Basics +-------------------- + +The :attr:`~flask.Flask.config` is actually a subclass of a dictionary and +can be modified just like any dictionary:: + + app = Flask(__name__) + app.config['DEBUG'] = True + +Certain configuration values are also forwarded to the +:attr:`~flask.Flask` object so that you can read and write them from +there:: + + app.debug = True + +To update multiple keys at once you can use the :meth:`dict.update` +method:: + + app.config.update( + DEBUG=True, + SECRET_KEY='...' + ) + +Builtin Configuration Values +---------------------------- + +The following configuration values are used internally by Flask: + +.. tabularcolumns:: |p{6.5cm}|p{8.5cm}| + +=============================== ========================================= +``DEBUG`` enable/disable debug mode +``TESTING`` enable/disable testing mode +``PROPAGATE_EXCEPTIONS`` explicitly enable or disable the + propagation of exceptions. If not set or + explicitly set to `None` this is + implicitly true if either `TESTING` or + `DEBUG` is true. +``SECRET_KEY`` the secret key +``SESSION_COOKIE_NAME`` the name of the session cookie +``PERMANENT_SESSION_LIFETIME`` the lifetime of a permanent session as + :class:`datetime.timedelta` object. +``USE_X_SENDFILE`` enable/disable x-sendfile +``LOGGER_NAME`` the name of the logger +``SERVER_NAME`` the name of the server. Required for + subdomain support (e.g.: ``'localhost'``) +``MAX_CONTENT_LENGTH`` If set to a value in bytes, Flask will + reject incoming requests with a + content length greater than this by + returning a 413 status code. +=============================== ========================================= + +.. admonition:: More on ``SERVER_NAME`` + + The ``SERVER_NAME`` key is used for the subdomain support. Because + Flask cannot guess the subdomain part without the knowledge of the + actual server name, this is required if you want to work with + subdomains. This is also used for the session cookie. + + Please keep in mind that not only Flask has the problem of not knowing + what subdomains are, your web browser does as well. Most modern web + browsers will not allow cross-subdomain cookies to be set on a + server name without dots in it. So if your server name is + ``'localhost'`` you will not be able to set a cookie for + ``'localhost'`` and every subdomain of it. Please chose a different + server name in that case, like ``'myapplication.local'`` and add + this name + the subdomains you want to use into your host config + or setup a local `bind`_. + +.. _bind: https://www.isc.org/software/bind + +.. versionadded:: 0.4 + ``LOGGER_NAME`` + +.. versionadded:: 0.5 + ``SERVER_NAME`` + +.. versionadded:: 0.6 + ``MAX_CONTENT_LENGTH`` + +.. versionadded:: 0.7 + ``PROPAGATE_EXCEPTIONS`` + +Configuring from Files +---------------------- + +Configuration becomes more useful if you can configure from a file, and +ideally that file would be outside of the actual application package so that +you can install the package with distribute (:ref:`distribute-deployment`) +and still modify that file afterwards. + +So a common pattern is this:: + + app = Flask(__name__) + app.config.from_object('yourapplication.default_settings') + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + +This first loads the configuration from the +`yourapplication.default_settings` module and then overrides the values +with the contents of the file the :envvar:`YOURAPPLICATION_SETTINGS` +environment variable points to. This environment variable can be set on +Linux or OS X with the export command in the shell before starting the +server:: + + $ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg + $ python run-app.py + * Running on http://127.0.0.1:5000/ + * Restarting with reloader... + +On Windows systems use the `set` builtin instead:: + + >set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg + +The configuration files themselves are actual Python files. Only values +in uppercase are actually stored in the config object later on. So make +sure to use uppercase letters for your config keys. + +Here is an example configuration file:: + + DEBUG = False + SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' + +Make sure to load the configuration very early on so that extensions have +the ability to access the configuration when starting up. There are other +methods on the config object as well to load from individual files. For a +complete reference, read the :class:`~flask.Config` object's +documentation. + + +Configuration Best Practices +---------------------------- + +The downside with the approach mentioned earlier is that it makes testing +a little harder. There is no one 100% solution for this problem in +general, but there are a couple of things you can do to improve that +experience: + +1. create your application in a function and register modules on it. + That way you can create multiple instances of your application with + different configurations attached which makes unittesting a lot + easier. You can use this to pass in configuration as needed. + +2. Do not write code that needs the configuration at import time. If you + limit yourself to request-only accesses to the configuration you can + reconfigure the object later on as needed. + + +Development / Production +------------------------ + +Most applications need more than one configuration. There will at least +be a separate configuration for a production server and one used during +development. The easiest way to handle this is to use a default +configuration that is always loaded and part of version control, and a +separate configuration that overrides the values as necessary as mentioned +in the example above:: + + app = Flask(__name__) + app.config.from_object('yourapplication.default_settings') + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + +Then you just have to add a separate `config.py` file and export +``YOURAPPLICATION_SETTINGS=/path/to/config.py`` and you are done. However +there are alternative ways as well. For example you could use imports or +subclassing. + +What is very popular in the Django world is to make the import explicit in +the config file by adding an ``from yourapplication.default_settings +import *`` to the top of the file and then overriding the changes by hand. +You could also inspect an environment variable like +``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc +and import different hardcoded files based on that. + +An interesting pattern is also to use classes and inheritance for +configuration:: + + class Config(object): + DEBUG = False + TESTING = False + DATABASE_URI = 'sqlite://:memory:' + + class ProductionConfig(Config): + DATABASE_URI = 'mysql://user@localhost/foo' + + class DevelopmentConfig(Config): + DEBUG = True + + class TestinConfig(Config): + TESTING = True + +To enable such a config you just have to call into +:meth:`~flask.Config.from_object`:: + + app.config.from_object('configmodule.ProductionConfig') + +There are many different ways and it's up to you how you want to manage +your configuration files. However here a list of good recommendations: + +- keep a default configuration in version control. Either populate the + config with this default configuration or import it in your own + configuration files before overriding values. +- use an environment variable to switch between the configurations. + This can be done from outside the Python interpreter and makes + development and deployment much easier because you can quickly and + easily switch between different configs without having to touch the + code at all. If you are working often on different projects you can + even create your own script for sourcing that activates a virtualenv + and exports the development configuration for you. +- Use a tool like `fabric`_ in production to push code and + configurations separately to the production server(s). For some + details about how to do that, head over to the :ref:`deploy` pattern. + +.. _fabric: http://fabfile.org/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/contents.rst.inc Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,52 @@ +User's Guide +------------ + +This part of the documentation, which is mostly prose, begins with some +background information about Flask, then focuses on step-by-step +instructions for web development with Flask. + +.. toctree:: + :maxdepth: 2 + + foreword + installation + quickstart + tutorial/index + templating + testing + errorhandling + config + signals + shell + patterns/index + deploying/index + becomingbig + +API Reference +------------- + +If you are looking for information on a specific function, class or +method, this part of the documentation is for you. + +.. toctree:: + :maxdepth: 2 + + api + +Additional Notes +---------------- + +Design notes, legal information and changelog are here for the interested. + +.. toctree:: + :maxdepth: 2 + + design + htmlfaq + security + unicode + extensiondev + styleguide + upgrading + changelog + license
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/deploying/cgi.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,47 @@ +CGI +=== + +If all other deployment methods do not work, CGI will work for sure. CGI +is supported by all major servers but usually has a less-than-optimal +performance. + +This is also the way you can use a Flask application on Google's +`App Engine`_, there however the execution does happen in a CGI-like +environment. The application's performance is unaffected because of that. + +.. admonition:: Watch Out + + Please make sure in advance that your ``app.run()`` call you might + have in your application file, is inside an ``if __name__ == + '__main__':`` or moved to a separate file. Just make sure it's not + called because this will always start a local WSGI server which we do + not want if we deploy that application to CGI / app engine. + +.. _App Engine: http://code.google.com/appengine/ + +Creating a `.cgi` file +---------------------- + +First you need to create the CGI application file. Let's call it +`yourapplication.cgi`:: + + #!/usr/bin/python + from wsgiref.handlers import CGIHandler + from yourapplication import app + + CGIHandler().run(app) + +Server Setup +------------ + +Usually there are two ways to configure the server. Either just copy the +`.cgi` into a `cgi-bin` (and use `mod_rewrite` or something similar to +rewrite the URL) or let the server point to the file directly. + +In Apache for example you can put a like like this into the config: + +.. sourcecode:: apache + + ScriptAlias /app /path/to/the/application.cgi + +For more information consult the documentation of your webserver.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/deploying/fastcgi.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,139 @@ +FastCGI +======= + +A very popular deployment setup on servers like `lighttpd`_ and `nginx`_ +is FastCGI. To use your WSGI application with any of them you will need +a FastCGI server first. + +The most popular one is `flup`_ which we will use for this guide. Make +sure to have it installed. + +.. admonition:: Watch Out + + Please make sure in advance that your ``app.run()`` call you might + have in your application file, is inside an ``if __name__ == + '__main__':`` or moved to a separate file. Just make sure it's not + called because this will always start a local WSGI server which we do + not want if we deploy that application to FastCGI. + +Creating a `.fcgi` file +----------------------- + +First you need to create the FastCGI server file. Let's call it +`yourapplication.fcgi`:: + + #!/usr/bin/python + from flup.server.fcgi import WSGIServer + from yourapplication import app + + WSGIServer(app).run() + +This is enough for Apache to work, however lighttpd and nginx need a +socket to communicate with the FastCGI server. For that to work you +need to pass the path to the socket to the +:class:`~flup.server.fcgi.WSGIServer`:: + + WSGIServer(application, bindAddress='/path/to/fcgi.sock').run() + +The path has to be the exact same path you define in the server +config. + +Save the `yourapplication.fcgi` file somewhere you will find it again. +It makes sense to have that in `/var/www/yourapplication` or something +similar. + +Make sure to set the executable bit on that file so that the servers +can execute it: + +.. sourcecode:: text + + # chmod +x /var/www/yourapplication/yourapplication.fcgi + +Configuring lighttpd +-------------------- + +A basic FastCGI configuration for lighttpd looks like that:: + + fastcgi.server = ("/yourapplication" => + "yourapplication" => ( + "socket" => "/tmp/yourapplication-fcgi.sock", + "bin-path" => "/var/www/yourapplication/yourapplication.fcgi", + "check-local" => "disable" + ) + ) + +This configuration binds the application to `/yourapplication`. If you +want the application to work in the URL root you have to work around a +lighttpd bug with the :class:`~werkzeug.contrib.fixers.LighttpdCGIRootFix` +middleware. + +Make sure to apply it only if you are mounting the application the URL +root. + +Configuring nginx +----------------- + +Installing FastCGI applications on nginx is a bit different because by default +no FastCGI parameters are forwarded. + +A basic flask FastCGI configuration for nginx looks like this:: + + location = /yourapplication { rewrite ^ /yourapplication/ last; } + location /yourapplication { try_files $uri @yourapplication; } + location @yourapplication { + include fastcgi_params; + fastcgi_split_path_info ^(/yourapplication)(.*)$; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_pass unix:/tmp/yourapplication-fcgi.sock; + } + +This configuration binds the application to `/yourapplication`. If you want +to have it in the URL root it's a bit simpler because you don't have to figure +out how to calculate `PATH_INFO` and `SCRIPT_NAME`:: + + location / { try_files $uri @yourapplication; } + location @yourapplication { + include fastcgi_params; + fastcgi_param PATH_INFO $fastcgi_script_name; + fastcgi_param SCRIPT_NAME ""; + fastcgi_pass unix:/tmp/yourapplication-fcgi.sock; + } + +Since Nginx doesn't load FastCGI apps, you have to do it by yourself. You +can either write an `init.d` script for that or execute it inside a screen +session:: + + $ screen + $ /var/www/yourapplication/yourapplication.fcgi + +Debugging +--------- + +FastCGI deployments tend to be hard to debug on most webservers. Very often the +only thing the server log tells you is something along the lines of "premature +end of headers". In order to debug the application the only thing that can +really give you ideas why it breaks is switching to the correct user and +executing the application by hand. + +This example assumes your application is called `application.fcgi` and that your +webserver user is `www-data`:: + + $ su www-data + $ cd /var/www/yourapplication + $ python application.fcgi + Traceback (most recent call last): + File "yourapplication.fcgi", line 4, in <module> + ImportError: No module named yourapplication + +In this case the error seems to be "yourapplication" not being on the python +path. Common problems are: + +- relative paths being used. Don't rely on the current working directory +- the code depending on environment variables that are not set by the + web server. +- different python interpreters being used. + +.. _lighttpd: http://www.lighttpd.net/ +.. _nginx: http://nginx.net/ +.. _flup: http://trac.saddi.com/flup
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/deploying/index.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,19 @@ +Deployment Options +================== + +Depending on what you have available there are multiple ways to run Flask +applications. A very common method is to use the builtin server during +development and maybe behind a proxy for simple applications, but there +are more options available. + +If you have a different WSGI server look up the server documentation about +how to use a WSGI app with it. Just remember that your application object +is the actual WSGI application. + +.. toctree:: + :maxdepth: 2 + + mod_wsgi + cgi + fastcgi + others
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/deploying/mod_wsgi.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,166 @@ +.. _mod_wsgi-deployment: + +mod_wsgi (Apache) +================= + +If you are using the `Apache`_ webserver you should consider using `mod_wsgi`_. + +.. admonition:: Watch Out + + Please make sure in advance that your ``app.run()`` call you might + have in your application file, is inside an ``if __name__ == + '__main__':`` or moved to a separate file. Just make sure it's not + called because this will always start a local WSGI server which we do + not want if we deploy that application to mod_wsgi. + +.. _Apache: http://httpd.apache.org/ + +Installing `mod_wsgi` +--------------------- + +If you don't have `mod_wsgi` installed yet you have to either install it using +a package manager or compile it yourself. + +The mod_wsgi `installation instructions`_ cover source installations on UNIX +systems. + +If you are using Ubuntu/Debian you can apt-get it and activate it as follows: + +.. sourcecode:: text + + # apt-get install libapache2-mod-wsgi + +On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by using +pkg_add: + +.. sourcecode:: text + + # pkg_add -r mod_wsgi + +If you are using pkgsrc you can install `mod_wsgi` by compiling the +`www/ap2-wsgi` package. + +If you encounter segfaulting child processes after the first apache reload you +can safely ignore them. Just restart the server. + +Creating a `.wsgi` file +----------------------- + +To run your application you need a `yourapplication.wsgi` file. This file +contains the code `mod_wsgi` is executing on startup to get the application +object. The object called `application` in that file is then used as +application. + +For most applications the following file should be sufficient:: + + from yourapplication import app as application + +If you don't have a factory function for application creation but a singleton +instance you can directly import that one as `application`. + +Store that file somewhere that you will find it again (e.g.: +`/var/www/yourapplication`) and make sure that `yourapplication` and all +the libraries that are in use are on the python load path. If you don't +want to install it system wide consider using a `virtual python`_ instance. + +Configuring Apache +------------------ + +The last thing you have to do is to create an Apache configuration file for +your application. In this example we are telling `mod_wsgi` to execute the +application under a different user for security reasons: + +.. sourcecode:: apache + + <VirtualHost *> + ServerName example.com + + WSGIDaemonProcess yourapplication user=user1 group=group1 threads=5 + WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi + + <Directory /var/www/yourapplication> + WSGIProcessGroup yourapplication + WSGIApplicationGroup %{GLOBAL} + Order deny,allow + Allow from all + </Directory> + </VirtualHost> + +For more information consult the `mod_wsgi wiki`_. + +.. _mod_wsgi: http://code.google.com/p/modwsgi/ +.. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide +.. _virtual python: http://pypi.python.org/pypi/virtualenv +.. _mod_wsgi wiki: http://code.google.com/p/modwsgi/wiki/ + +Troubleshooting +--------------- + +If your application does not run, follow this guide to troubleshoot: + +**Problem:** application does not run, errorlog shows SystemExit ignored + You have a ``app.run()`` call in your application file that is not + guarded by an ``if __name__ == '__main__':`` condition. Either remove + that :meth:`~flask.Flask.run` call from the file and move it into a + separate `run.py` file or put it into such an if block. + +**Problem:** application gives permission errors + Probably caused by your application running as the wrong user. Make + sure the folders the application needs access to have the proper + privileges set and the application runs as the correct user (``user`` + and ``group`` parameter to the `WSGIDaemonProcess` directive) + +**Problem:** application dies with an error on print + Keep in mind that mod_wsgi disallows doing anything with + :data:`sys.stdout` and :data:`sys.stderr`. You can disable this + protection from the config by setting the `WSGIRestrictStdout` to + ``off``: + + .. sourcecode:: apache + + WSGIRestrictStdout Off + + Alternatively you can also replace the standard out in the .wsgi file + with a different stream:: + + import sys + sys.stdout = sys.stderr + +**Problem:** accessing resources gives IO errors + Your application probably is a single .py file you symlinked into the + site-packages folder. Please be aware that this does not work, + instead you either have to put the folder into the pythonpath the file + is stored in, or convert your application into a package. + + The reason for this is that for non-installed packages, the module + filename is used to locate the resources and for symlinks the wrong + filename is picked up. + +Support for Automatic Reloading +------------------------------- + +To help deployment tools you can activate support for automatic reloading. +Whenever something changes the `.wsgi` file, `mod_wsgi` will reload all +the daemon processes for us. + +For that, just add the following directive to your `Directory` section: + +.. sourcecode:: apache + + WSGIScriptReloading On + +Working with Virtual Environments +--------------------------------- + +Virtual environments have the advantage that they never install the +required dependencies system wide so you have a better control over what +is used where. If you want to use a virtual environment with mod_wsgi you +have to modify your `.wsgi` file slightly. + +Add the following lines to the top of your `.wsgi` file:: + + activate_this = '/path/to/env/bin/activate_this.py' + execfile(activate_this, dict(__file__=activate_this)) + +This sets up the load paths according to the settings of the virtual +environment. Keep in mind that the path has to be absolute.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/deploying/others.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,98 @@ +Other Servers +============= + +There are popular servers written in Python that allow the execution of +WSGI applications as well. Keep in mind though that some of these servers +were written for very specific applications and might not work as well for +standard WSGI application such as Flask powered ones. + + +Tornado +-------- + +`Tornado`_ is an open source version of the scalable, non-blocking web +server and tools that power `FriendFeed`_. Because it is non-blocking and +uses epoll, it can handle thousands of simultaneous standing connections, +which means it is ideal for real-time web services. Integrating this +service with Flask is a trivial task:: + + from tornado.wsgi import WSGIContainer + from tornado.httpserver import HTTPServer + from tornado.ioloop import IOLoop + from yourapplication import app + + http_server = HTTPServer(WSGIContainer(app)) + http_server.listen(5000) + IOLoop.instance().start() + + +.. _Tornado: http://www.tornadoweb.org/ +.. _FriendFeed: http://friendfeed.com/ + + +Gevent +------- + +`Gevent`_ is a coroutine-based Python networking library that uses +`greenlet`_ to provide a high-level synchronous API on top of `libevent`_ +event loop:: + + from gevent.wsgi import WSGIServer + from yourapplication import app + + http_server = WSGIServer(('', 5000), app) + http_server.serve_forever() + +.. _Gevent: http://www.gevent.org/ +.. _greenlet: http://codespeak.net/py/0.9.2/greenlet.html +.. _libevent: http://monkey.org/~provos/libevent/ + + +Gunicorn +-------- + +`Gunicorn`_ 'Green Unicorn' is a WSGI HTTP Server for UNIX. It's a pre-fork +worker model ported from Ruby's Unicorn project. It supports both `eventlet`_ +and `greenlet`_. Running a Flask application on this server is quite simple:: + + gunicorn myproject:app + +.. _Gunicorn: http://gunicorn.org/ +.. _eventlet: http://eventlet.net/ +.. _greenlet: http://codespeak.net/py/0.9.2/greenlet.html + + +Proxy Setups +------------ + +If you deploy your application behind an HTTP proxy you will need to +rewrite a few headers in order for the application to work. The two +problematic values in the WSGI environment usually are `REMOTE_ADDR` and +`HTTP_HOST`. Werkzeug ships a fixer that will solve some common setups, +but you might want to write your own WSGI middleware for specific setups. + +The most common setup invokes the host being set from `X-Forwarded-Host` +and the remote address from `X-Forward-For`:: + + from werkzeug.contrib.fixers import ProxyFix + app.wsgi_app = ProxyFix(app.wsgi_app) + +Please keep in mind that it is a security issue to use such a middleware +in a non-proxy setup because it will blindly trust the incoming +headers which might be forged by malicious clients. + +If you want to rewrite the headers from another header, you might want to +use a fixer like this:: + + class CustomProxyFix(object): + + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + host = environ.get('HTTP_X_FHOST', '') + if host: + environ['HTTP_HOST'] = host + return self.app(environ, start_response) + + app.wsgi_app = CustomProxyFix(app.wsgi_app)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/design.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,175 @@ +.. _design: + +Design Decisions in Flask +========================= + +If you are curious why Flask does certain things the way it does and not +differently, this section is for you. This should give you an idea about +some of the design decisions that may appear arbitrary and surprising at +first, especially in direct comparison with other frameworks. + + +The Explicit Application Object +------------------------------- + +A Python web application based on WSGI has to have one central callable +object that implements the actual application. In Flask this is an +instance of the :class:`~flask.Flask` class. Each Flask application has +to create an instance of this class itself and pass it the name of the +module, but why can't Flask do that itself? + +Without such an explicit application object the following code:: + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def index(): + return 'Hello World!' + +Would look like this instead:: + + from hypothetical_flask import route + + @route('/') + def index(): + return 'Hello World!' + +There are three major reasons for this. The most important one is that +implicit application objects require that there may only be one instance at +the time. There are ways to fake multiple applications with a single +application object, like maintaining a stack of applications, but this +causes some problems I won't outline here in detail. Now the question is: +when does a microframework need more than one application at the same +time? A good example for this is unittesting. When you want to test +something it can be very helpful to create a minimal application to test +specific behavior. When the application object is deleted everything it +allocated will be freed again. + +Another thing that becomes possible when you have an explicit object lying +around in your code is that you can subclass the base class +(:class:`~flask.Flask`) to alter specific behaviour. This would not be +possible without hacks if the object were created ahead of time for you +based on a class that is not exposed to you. + +But there is another very important reason why Flask depends on an +explicit instantiation of that class: the package name. Whenever you +create a Flask instance you usually pass it `__name__` as package name. +Flask depends on that information to properly load resources relative +to your module. With Python's outstanding support for reflection it can +then access the package to figure out where the templates and static files +are stored (see :meth:`~flask.Flask.open_resource`). Now obviously there +are frameworks around that do not need any configuration and will still be +able to load templates relative to your application module. But they have +to use the current working directory for that, which is a very unreliable +way to determine where the application is. The current working directory +is process-wide and if you are running multiple applications in one +process (which could happen in a webserver without you knowing) the paths +will be off. Worse: many webservers do not set the working directory to +the directory of your application but to the document root which does not +have to be the same folder. + +The third reason is "explicit is better than implicit". That object is +your WSGI application, you don't have to remember anything else. If you +want to apply a WSGI middleware, just wrap it and you're done (though +there are better ways to do that so that you do not lose the reference +to the application object :meth:`~flask.Flask.wsgi_app`). + +Furthermore this design makes it possible to use a factory function to +create the application which is very helpful for unittesting and similar +things (:ref:`app-factories`). + +One Template Engine +------------------- + +Flask decides on one template engine: Jinja2. Why doesn't Flask have a +pluggable template engine interface? You can obviously use a different +template engine, but Flask will still configure Jinja2 for you. While +that limitation that Jinja2 is *always* configured will probably go away, +the decision to bundle one template engine and use that will not. + +Template engines are like programming languages and each of those engines +has a certain understanding about how things work. On the surface they +all work the same: you tell the engine to evaluate a template with a set +of variables and take the return value as string. + +But that's about where similarities end. Jinja2 for example has an +extensive filter system, a certain way to do template inheritance, support +for reusable blocks (macros) that can be used from inside templates and +also from Python code, uses Unicode for all operations, supports +iterative template rendering, configurable syntax and more. On the other +hand an engine like Genshi is based on XML stream evaluation, template +inheritance by taking the availability of XPath into account and more. +Mako on the other hand treats templates similar to Python modules. + +When it comes to connecting a template engine with an application or +framework there is more than just rendering templates. For instance, +Flask uses Jinja2's extensive autoescaping support. Also it provides +ways to access macros from Jinja2 templates. + +A template abstraction layer that would not take the unique features of +the template engines away is a science on its own and a too large +undertaking for a microframework like Flask. + +Furthermore extensions can then easily depend on one template language +being present. You can easily use your own templating language, but an +extension could still depend on Jinja itself. + + +Micro with Dependencies +----------------------- + +Why does Flask call itself a microframework and yet it depends on two +libraries (namely Werkzeug and Jinja2). Why shouldn't it? If we look +over to the Ruby side of web development there we have a protocol very +similar to WSGI. Just that it's called Rack there, but besides that it +looks very much like a WSGI rendition for Ruby. But nearly all +applications in Ruby land do not work with Rack directly, but on top of a +library with the same name. This Rack library has two equivalents in +Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but +from my understanding it's sort of deprecated in favour of WebOb. The +development of WebOb and Werkzeug started side by side with similar ideas +in mind: be a good implementation of WSGI for other applications to take +advantage. + +Flask is a framework that takes advantage of the work already done by +Werkzeug to properly interface WSGI (which can be a complex task at +times). Thanks to recent developments in the Python package +infrastructure, packages with dependencies are no longer an issue and +there are very few reasons against having libraries that depend on others. + + +Thread Locals +------------- + +Flask uses thread local objects (context local objects in fact, they +support greenlet contexts as well) for request, session and an extra +object you can put your own things on (:data:`~flask.g`). Why is that and +isn't that a bad idea? + +Yes it is usually not such a bright idea to use thread locals. They cause +troubles for servers that are not based on the concept of threads and make +large applications harder to maintain. However Flask is just not designed +for large applications or asynchronous servers. Flask wants to make it +quick and easy to write a traditional web application. + +Also see the :ref:`becomingbig` section of the documentation for some +inspiration for larger applications based on Flask. + + +What Flask is, What Flask is Not +-------------------------------- + +Flask will never have a database layer. It will not have a form library +or anything else in that direction. Flask itself just bridges to Werkzeug +to implement a proper WSGI application and to Jinja2 to handle templating. +It also binds to a few common standard library packages such as logging. +Everything else is up for extensions. + +Why is this the case? Because people have different preferences and +requirements and Flask could not meet those if it would force any of this +into the core. The majority of web applications will need a template +engine in some sort. However not every application needs a SQL database. + +The idea of Flask is to build a good foundation for all applications. +Everything else is up to you or extensions.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/errorhandling.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,237 @@ +.. _application-errors: + +Handling Application Errors +=========================== + +.. versionadded:: 0.3 + +Applications fail, servers fail. Sooner or later you will see an exception +in production. Even if your code is 100% correct, you will still see +exceptions from time to time. Why? Because everything else involved will +fail. Here some situations where perfectly fine code can lead to server +errors: + +- the client terminated the request early and the application was still + reading from the incoming data. +- the database server was overloaded and could not handle the query. +- a filesystem is full +- a harddrive crashed +- a backend server overloaded +- a programming error in a library you are using +- network connection of the server to another system failed. + +And that's just a small sample of issues you could be facing. So how do we +deal with that sort of problem? By default if your application runs in +production mode, Flask will display a very simple page for you and log the +exception to the :attr:`~flask.Flask.logger`. + +But there is more you can do, and we will cover some better setups to deal +with errors. + +Error Mails +----------- + +If the application runs in production mode (which it will do on your +server) you won't see any log messages by default. Why is that? Flask +tries to be a zero-configuration framework. Where should it drop the logs +for you if there is no configuration? Guessing is not a good idea because +chances are, the place it guessed is not the place where the user has +permission to create a logfile. Also, for most small applications nobody +will look at the logs anyways. + +In fact, I promise you right now that if you configure a logfile for the +application errors you will never look at it except for debugging an issue +when a user reported it for you. What you want instead is a mail the +second the exception happened. Then you get an alert and you can do +something about it. + +Flask uses the Python builtin logging system, and it can actually send +you mails for errors which is probably what you want. Here is how you can +configure the Flask logger to send you mails for exceptions:: + + ADMINS = ['yourname@example.com'] + if not app.debug: + import logging + from logging.handlers import SMTPHandler + mail_handler = SMTPHandler('127.0.0.1', + 'server-error@example.com', + ADMINS, 'YourApplication Failed') + mail_handler.setLevel(logging.ERROR) + app.logger.addHandler(mail_handler) + +So what just happened? We created a new +:class:`~logging.handlers.SMTPHandler` that will send mails with the mail +server listening on ``127.0.0.1`` to all the `ADMINS` from the address +*server-error@example.com* with the subject "YourApplication Failed". If +your mail server requires credentials, these can also be provided. For +that check out the documentation for the +:class:`~logging.handlers.SMTPHandler`. + +We also tell the handler to only send errors and more critical messages. +Because we certainly don't want to get a mail for warnings or other +useless logs that might happen during request handling. + +Before you run that in production, please also look at :ref:`logformat` to +put more information into that error mail. That will save you from a lot +of frustration. + + +Logging to a File +----------------- + +Even if you get mails, you probably also want to log warnings. It's a +good idea to keep as much information around that might be required to +debug a problem. Please note that Flask itself will not issue any +warnings in the core system, so it's your responsibility to warn in the +code if something seems odd. + +There are a couple of handlers provided by the logging system out of the +box but not all of them are useful for basic error logging. The most +interesting are probably the following: + +- :class:`~logging.FileHandler` - logs messages to a file on the + filesystem. +- :class:`~logging.handlers.RotatingFileHandler` - logs messages to a file + on the filesystem and will rotate after a certain number of messages. +- :class:`~logging.handlers.NTEventLogHandler` - will log to the system + event log of a Windows system. If you are deploying on a Windows box, + this is what you want to use. +- :class:`~logging.handlers.SysLogHandler` - sends logs to a UNIX + syslog. + +Once you picked your log handler, do like you did with the SMTP handler +above, just make sure to use a lower setting (I would recommend +`WARNING`):: + + if not app.debug: + import logging + from themodule import TheHandler YouWant + file_handler = TheHandlerYouWant(...) + file_handler.setLevel(logging.WARNING) + app.logger.addHandler(file_handler) + +.. _logformat: + +Controlling the Log Format +-------------------------- + +By default a handler will only write the message string into a file or +send you that message as mail. A log record stores more information, +and it makes a lot of sense to configure your logger to also contain that +information so that you have a better idea of why that error happened, and +more importantly, where it did. + +A formatter can be instantiated with a format string. Note that +tracebacks are appended to the log entry automatically. You don't have to +do that in the log formatter format string. + +Here some example setups: + +Email +````` + +:: + + from logging import Formatter + mail_handler.setFormatter(Formatter(''' + Message type: %(levelname)s + Location: %(pathname)s:%(lineno)d + Module: %(module)s + Function: %(funcName)s + Time: %(asctime)s + + Message: + + %(message)s + ''')) + +File logging +```````````` + +:: + + from logging import Formatter + file_handler.setFormatter(Formatter( + '%(asctime)s %(levelname)s: %(message)s ' + '[in %(pathname)s:%(lineno)d]' + )) + + +Complex Log Formatting +`````````````````````` + +Here is a list of useful formatting variables for the format string. Note +that this list is not complete, consult the official documentation of the +:mod:`logging` package for a full list. + +.. tabularcolumns:: |p{3cm}|p{12cm}| + ++------------------+----------------------------------------------------+ +| Format | Description | ++==================+====================================================+ +| ``%(levelname)s``| Text logging level for the message | +| | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``, | +| | ``'ERROR'``, ``'CRITICAL'``). | ++------------------+----------------------------------------------------+ +| ``%(pathname)s`` | Full pathname of the source file where the | +| | logging call was issued (if available). | ++------------------+----------------------------------------------------+ +| ``%(filename)s`` | Filename portion of pathname. | ++------------------+----------------------------------------------------+ +| ``%(module)s`` | Module (name portion of filename). | ++------------------+----------------------------------------------------+ +| ``%(funcName)s`` | Name of function containing the logging call. | ++------------------+----------------------------------------------------+ +| ``%(lineno)d`` | Source line number where the logging call was | +| | issued (if available). | ++------------------+----------------------------------------------------+ +| ``%(asctime)s`` | Human-readable time when the LogRecord` was | +| | created. By default this is of the form | +| | ``"2003-07-08 16:49:45,896"`` (the numbers after | +| | the comma are millisecond portion of the time). | +| | This can be changed by subclassing the formatter | +| | and overriding the | +| | :meth:`~logging.Formatter.formatTime` method. | ++------------------+----------------------------------------------------+ +| ``%(message)s`` | The logged message, computed as ``msg % args`` | ++------------------+----------------------------------------------------+ + +If you want to further customize the formatting, you can subclass the +formatter. The formatter has three interesting methods: + +:meth:`~logging.Formatter.format`: + handles the actual formatting. It is passed a + :class:`~logging.LogRecord` object and has to return the formatted + string. +:meth:`~logging.Formatter.formatTime`: + called for `asctime` formatting. If you want a different time format + you can override this method. +:meth:`~logging.Formatter.formatException` + called for exception formatting. It is passed an :attr:`~sys.exc_info` + tuple and has to return a string. The default is usually fine, you + don't have to override it. + +For more information, head over to the official documentation. + + +Other Libraries +--------------- + +So far we only configured the logger your application created itself. +Other libraries might log themselves as well. For example, SQLAlchemy uses +logging heavily in its core. While there is a method to configure all +loggers at once in the :mod:`logging` package, I would not recommend using +it. There might be a situation in which you want to have multiple +separate applications running side by side in the same Python interpreter +and then it becomes impossible to have different logging setups for those. + +Instead, I would recommend figuring out which loggers you are interested +in, getting the loggers with the :func:`~logging.getLogger` function and +iterating over them to attach handlers:: + + from logging import getLogger + loggers = [app.logger, getLogger('sqlalchemy'), + getLogger('otherlibrary')] + for logger in loggers: + logger.addHandler(mail_handler) + logger.addHandler(file_handler)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/extensiondev.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,327 @@ +Flask Extension Development +=========================== + +Flask, being a microframework, often requires some repetitive steps to get +a third party library working. Because very often these steps could be +abstracted to support multiple projects the `Flask Extension Registry`_ +was created. + +If you want to create your own Flask extension for something that does not +exist yet, this guide to extension development will help you get your +extension running in no time and to feel like users would expect your +extension to behave. + +.. _Flask Extension Registry: http://flask.pocoo.org/extensions/ + +Anatomy of an Extension +----------------------- + +Extensions are all located in a package called ``flaskext.something`` +where "something" is the name of the library you want to bridge. So for +example if you plan to add support for a library named `simplexml` to +Flask, you would name your extension's package ``flaskext.simplexml``. + +The name of the actual extension (the human readable name) however would +be something like "Flask-SimpleXML". Make sure to include the name +"Flask" somewhere in that name and that you check the capitalization. +This is how users can then register dependencies to your extension in +their `setup.py` files. + +The magic that makes it possible to have your library in a package called +``flaskext.something`` is called a "namespace package". Check out the +guide below how to create something like that. + +But how do extensions look like themselves? An extension has to ensure +that it works with multiple Flask application instances at once. This is +a requirement because many people will use patterns like the +:ref:`app-factories` pattern to create their application as needed to aid +unittests and to support multiple configurations. Because of that it is +crucial that your application supports that kind of behaviour. + +Most importantly the extension must be shipped with a `setup.py` file and +registered on PyPI. Also the development checkout link should work so +that people can easily install the development version into their +virtualenv without having to download the library by hand. + +Flask extensions must be licensed as BSD or MIT or a more liberal license +to be enlisted on the Flask Extension Registry. Keep in mind that the +Flask Extension Registry is a moderated place and libraries will be +reviewed upfront if they behave as required. + +"Hello Flaskext!" +----------------- + +So let's get started with creating such a Flask extension. The extension +we want to create here will provide very basic support for SQLite3. + +There is a script on github called `Flask Extension Wizard`_ which helps +you create the initial folder structure. But for this very basic example +we want to create all by hand to get a better feeling for it. + +First we create the following folder structure:: + + flask-sqlite3/ + flaskext/ + __init__.py + sqlite3.py + setup.py + LICENSE + +Here's the contents of the most important files: + +flaskext/__init__.py +```````````````````` + +The only purpose of this file is to mark the package as namespace package. +This is required so that multiple modules from different PyPI packages can +reside in the same Python package:: + + __import__('pkg_resources').declare_namespace(__name__) + +If you want to know exactly what is happening there, checkout the +distribute or setuptools docs which explain how this works. + +Just make sure to not put anything else in there! + +setup.py +```````` + +The next file that is absolutely required is the `setup.py` file which is +used to install your Flask extension. The following contents are +something you can work with:: + + """ + Flask-SQLite3 + ------------- + + This is the description for that library + """ + from setuptools import setup + + + setup( + name='Flask-SQLite3', + version='1.0', + url='http://example.com/flask-sqlite3/', + license='BSD', + author='Your Name', + author_email='your-email@example.com', + description='Very short description', + long_description=__doc__, + packages=['flaskext'], + namespace_packages=['flaskext'], + zip_safe=False, + platforms='any', + install_requires=[ + 'Flask' + ], + classifiers=[ + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Topic :: Software Development :: Libraries :: Python Modules' + ] + ) + +That's a lot of code but you can really just copy/paste that from existing +extensions and adapt. This is also what the wizard creates for you if you +use it. + +flaskext/sqlite3.py +``````````````````` + +Now this is where your extension code goes. But how exactly should such +an extension look like? What are the best practices? Continue reading +for some insight. + + +Initializing Extensions +----------------------- + +Many extensions will need some kind of initialization step. For example, +consider your application is currently connecting to SQLite like the +documentation suggests (:ref:`sqlite3`) you will need to provide a few +functions and before / after request handlers. So how does the extension +know the name of the application object? + +Quite simple: you pass it to it. + +There are two recommended ways for an extension to initialize: + +initialization functions: + If your extension is called `helloworld` you might have a function + called ``init_helloworld(app[, extra_args])`` that initializes the + extension for that application. It could attach before / after + handlers etc. + +classes: + Classes work mostly like initialization functions but can later be + used to further change the behaviour. For an example look at how the + `OAuth extension`_ works: there is an `OAuth` object that provides + some helper functions like `OAuth.remote_app` to create a reference to + a remote application that uses OAuth. + +What to use depends on what you have in mind. For the SQLite 3 extension +we will need to use the class based approach because we have to use a +controller object that can be used to connect to the database. + +The Extension Code +------------------ + +Here's the contents of the `flaskext/sqlite3.py` for copy/paste:: + + from __future__ import absolute_import + import sqlite3 + from flask import g + + class SQLite3(object): + + def __init__(self, app): + self.app = app + self.app.config.setdefault('SQLITE3_DATABASE', ':memory:') + + self.app.before_request(self.before_request) + self.app.after_request(self.after_request) + + def connect(self): + return sqlite3.connect(self.app.config['SQLITE3_DATABASE']) + + def before_request(self): + g.sqlite3_db = self.connect() + + def after_request(self, response): + g.sqlite3_db.close() + return response + +So here's what the lines of code do: + +1. the ``__future__`` import is necessary to activate absolute imports. + This is needed because otherwise we could not call our module + `sqlite3.py` and import the top-level `sqlite3` module which actually + implements the connection to SQLite. +2. We create a class for our extension that sets a default configuration + for the SQLite 3 database if it's not there (:meth:`dict.setdefault`) + and connects two functions as before and after request handlers. +3. Then it implements a `connect` function that returns a new database + connection and the two handlers. + +So why did we decide on a class based approach here? Because using that +extension looks something like this:: + + from flask import Flask, g + from flaskext.sqlite3 import SQLite3 + + app = Flask(__name__) + app.config.from_pyfile('the-config.cfg') + db = SQLite(app) + +Either way you can use the database from the views like this:: + + @app.route('/') + def show_all(): + cur = g.sqlite3_db.cursor() + cur.execute(...) + +But how would you open a database connection from outside a view function? +This is where the `db` object now comes into play: + +>>> from yourapplication import db +>>> con = db.connect() +>>> cur = con.cursor() + +If you don't need that, you can go with initialization functions. + +Initialization Functions +------------------------ + +Here's what the module would look like with initialization functions:: + + from __future__ import absolute_import + import sqlite3 + from flask import g + + def init_sqlite3(app): + app = app + app.config.setdefault('SQLITE3_DATABASE', ':memory:') + + @app.before_request + def before_request(): + g.sqlite3_db = sqlite3.connect(self.app.config['SQLITE3_DATABASE']) + + @app.after_request + def after_request(response): + g.sqlite3_db.close() + return response + +Learn from Others +----------------- + +This documentation only touches the bare minimum for extension +development. If you want to learn more, it's a very good idea to check +out existing extensions on the `Flask Extension Registry`_. If you feel +lost there is still the `mailinglist`_ and the `IRC channel`_ to get some +ideas for nice looking APIs. Especially if you do something nobody before +you did, it might be a very good idea to get some more input. This not +only to get an idea about what people might want to have from an +extension, but also to avoid having multiple developers working on pretty +much the same side by side. + +Remember: good API design is hard, so introduce your project on the +mailinglist, and let other developers give you a helping hand with +designing the API. + +The best Flask extensions are extensions that share common idioms for the +API. And this can only work if collaboration happens early. + + +Approved Extensions +------------------- + +Flask also has the concept of approved extensions. Approved extensions +are tested as part of Flask itself to ensure extensions do not break on +new releases. These approved extensions are listed on the `Flask +Extension Registry`_ and marked appropriately. If you want your own +extension to be approved you have to follow these guidelines: + +1. An approved Flask extension must provide exactly one package or module + inside the `flaskext` namespace package. +2. It must ship a testsuite that can either be invoked with ``make test`` + or ``python setup.py test``. For testsuites invoked with ``make + test`` the extension has to ensure that all dependencies for the test + are installed automatically, in case of ``python setup.py test`` + dependencies for tests alone can be specified in the `setup.py` + file. The testsuite also has to be part of the distribution. +3. APIs of approved extensions will be checked for the following + characteristics: + + - an approved extension has to support multiple applications + running in the same Python process. + - it must be possible to use the factory pattern for creating + applications. + +4. The license must be BSD/MIT/WTFPL licensed. +5. The naming scheme for official extensions is *Flask-ExtensionName* or + *ExtensionName-Flask*. +6. Approved extensions must define all their dependencies in the + `setup.py` file unless a dependency cannot be met because it is not + available on PyPI. +7. The extension must have documentation that uses one of the two Flask + themes for Sphinx documentation. +8. The setup.py description (and thus the PyPI description) has to + link to the documentation, website (if there is one) and there + must be a link to automatically install the development version + (``PackageName==dev``). +9. The ``zip_safe`` flag in the setup script must be set to ``False``, + even if the extension would be safe for zipping. +10. An extension currently has to support Python 2.5, 2.6 as well as + Python 2.7 + + +.. _Flask Extension Wizard: + http://github.com/mitsuhiko/flask-extension-wizard +.. _OAuth extension: http://packages.python.org/Flask-OAuth/ +.. _mailinglist: http://flask.pocoo.org/mailinglist/ +.. _IRC channel: http://flask.pocoo.org/community/irc/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/flaskext.py Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,86 @@ +# flasky extensions. flasky pygments style based on tango style +from pygments.style import Style +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Whitespace, Punctuation, Other, Literal + + +class FlaskyStyle(Style): + background_color = "#f8f8f8" + default_style = "" + + styles = { + # No corresponding class for the following: + #Text: "", # class: '' + Whitespace: "underline #f8f8f8", # class: 'w' + Error: "#a40000 border:#ef2929", # class: 'err' + Other: "#000000", # class 'x' + + Comment: "italic #8f5902", # class: 'c' + Comment.Preproc: "noitalic", # class: 'cp' + + Keyword: "bold #004461", # class: 'k' + Keyword.Constant: "bold #004461", # class: 'kc' + Keyword.Declaration: "bold #004461", # class: 'kd' + Keyword.Namespace: "bold #004461", # class: 'kn' + Keyword.Pseudo: "bold #004461", # class: 'kp' + Keyword.Reserved: "bold #004461", # class: 'kr' + Keyword.Type: "bold #004461", # class: 'kt' + + Operator: "#582800", # class: 'o' + Operator.Word: "bold #004461", # class: 'ow' - like keywords + + Punctuation: "bold #000000", # class: 'p' + + # because special names such as Name.Class, Name.Function, etc. + # are not recognized as such later in the parsing, we choose them + # to look the same as ordinary variables. + Name: "#000000", # class: 'n' + Name.Attribute: "#c4a000", # class: 'na' - to be revised + Name.Builtin: "#004461", # class: 'nb' + Name.Builtin.Pseudo: "#3465a4", # class: 'bp' + Name.Class: "#000000", # class: 'nc' - to be revised + Name.Constant: "#000000", # class: 'no' - to be revised + Name.Decorator: "#888", # class: 'nd' - to be revised + Name.Entity: "#ce5c00", # class: 'ni' + Name.Exception: "bold #cc0000", # class: 'ne' + Name.Function: "#000000", # class: 'nf' + Name.Property: "#000000", # class: 'py' + Name.Label: "#f57900", # class: 'nl' + Name.Namespace: "#000000", # class: 'nn' - to be revised + Name.Other: "#000000", # class: 'nx' + Name.Tag: "bold #004461", # class: 'nt' - like a keyword + Name.Variable: "#000000", # class: 'nv' - to be revised + Name.Variable.Class: "#000000", # class: 'vc' - to be revised + Name.Variable.Global: "#000000", # class: 'vg' - to be revised + Name.Variable.Instance: "#000000", # class: 'vi' - to be revised + + Number: "#990000", # class: 'm' + + Literal: "#000000", # class: 'l' + Literal.Date: "#000000", # class: 'ld' + + String: "#4e9a06", # class: 's' + String.Backtick: "#4e9a06", # class: 'sb' + String.Char: "#4e9a06", # class: 'sc' + String.Doc: "italic #8f5902", # class: 'sd' - like a comment + String.Double: "#4e9a06", # class: 's2' + String.Escape: "#4e9a06", # class: 'se' + String.Heredoc: "#4e9a06", # class: 'sh' + String.Interpol: "#4e9a06", # class: 'si' + String.Other: "#4e9a06", # class: 'sx' + String.Regex: "#4e9a06", # class: 'sr' + String.Single: "#4e9a06", # class: 's1' + String.Symbol: "#4e9a06", # class: 'ss' + + Generic: "#000000", # class: 'g' + Generic.Deleted: "#a40000", # class: 'gd' + Generic.Emph: "italic #000000", # class: 'ge' + Generic.Error: "#ef2929", # class: 'gr' + Generic.Heading: "bold #000080", # class: 'gh' + Generic.Inserted: "#00A000", # class: 'gi' + Generic.Output: "#888", # class: 'go' + Generic.Prompt: "#745334", # class: 'gp' + Generic.Strong: "bold #000000", # class: 'gs' + Generic.Subheading: "bold #800080", # class: 'gu' + Generic.Traceback: "bold #a40000", # class: 'gt' + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/flaskstyle.sty Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,118 @@ +\definecolor{TitleColor}{rgb}{0,0,0} +\definecolor{InnerLinkColor}{rgb}{0,0,0} + +\renewcommand{\maketitle}{% + \begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \ifsphinxpdfoutput + \begingroup + % This \def is required to deal with multi-line authors; it + % changes \\ to ', ' (comma-space), making it pass muster for + % generating document info in the PDF file. + \def\\{, } + \pdfinfo{ + /Author (\@author) + /Title (\@title) + } + \endgroup + \fi + \begin{flushright}% + %\sphinxlogo% + {\center + \vspace*{3cm} + \includegraphics{logo.pdf} + \vspace{3cm} + \par + {\rm\Huge \@title \par}% + {\em\LARGE \py@release\releaseinfo \par} + {\large + \@date \par + \py@authoraddress \par + }}% + \end{flushright}%\par + \@thanks + \end{titlepage}% + \cleardoublepage% + \setcounter{footnote}{0}% + \let\thanks\relax\let\maketitle\relax + %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + +\fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\thepage}} + \fancyfoot[LO]{{\nouppercase{\rightmark}}} + \fancyfoot[RE]{{\nouppercase{\leftmark}}} + \fancyhead[LE,RO]{{ \@title, \py@release}} + \renewcommand{\headrulewidth}{0.4pt} + \renewcommand{\footrulewidth}{0.4pt} +} + +\fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} +} + +\titleformat{\section}{\Large}% + {\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor} +\titleformat{\subsection}{\large}% + {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} +\titleformat{\subsubsection}{}% + {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} +\titleformat{\paragraph}{\large}% + {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor} + +\ChNameVar{\raggedleft\normalsize} +\ChNumVar{\raggedleft \bfseries\Large} +\ChTitleVar{\raggedleft \rm\Huge} + +\renewcommand\thepart{\@Roman\c@part} +\renewcommand\part{% + \pagestyle{empty} + \if@noskipsec \leavevmode \fi + \cleardoublepage + \vspace*{6cm}% + \@afterindentfalse + \secdef\@part\@spart} + +\def\@part[#1]#2{% + \ifnum \c@secnumdepth >\m@ne + \refstepcounter{part}% + \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}% + \else + \addcontentsline{toc}{part}{#1}% + \fi + {\parindent \z@ %\center + \interlinepenalty \@M + \normalfont + \ifnum \c@secnumdepth >\m@ne + \rm\Large \partname~\thepart + \par\nobreak + \fi + \MakeUppercase{\rm\Huge #2}% + \markboth{}{}\par}% + \nobreak + \vskip 8ex + \@afterheading} +\def\@spart#1{% + {\parindent \z@ %\center + \interlinepenalty \@M + \normalfont + \huge \bfseries #1\par}% + \nobreak + \vskip 3ex + \@afterheading} + +% use inconsolata font +\usepackage{inconsolata} + +% fix single quotes, for inconsolata. (does not work) +%%\usepackage{textcomp} +%%\begingroup +%% \catcode`'=\active +%% \g@addto@macro\@noligs{\let'\textsinglequote} +%% \endgroup +%%\endinput
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/foreword.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,109 @@ +Foreword +======== + +Read this before you get started with Flask. This hopefully answers some +questions about the purpose and goals of the project, and when you +should or should not be using it. + +What does "micro" mean? +----------------------- + +To me, the "micro" in microframework refers not only to the simplicity and +small size of the framework, but also to the typically limited complexity +and size of applications that are written with the framework. Also the +fact that you can have an entire application in a single Python file. To +be approachable and concise, a microframework sacrifices a few features +that may be necessary in larger or more complex applications. + +For example, Flask uses thread-local objects internally so that you don't +have to pass objects around from function to function within a request in +order to stay threadsafe. While this is a really easy approach and saves +you a lot of time, it might also cause some troubles for very large +applications because changes on these thread-local objects can happen +anywhere in the same thread. + +Flask provides some tools to deal with the downsides of this approach but +it might be an issue for larger applications because in theory +modifications on these objects might happen anywhere in the same thread. + +Flask is also based on convention over configuration, which means that +many things are preconfigured. For example, by convention, templates and +static files are in subdirectories within the Python source tree of the +application. + +The main reason however why Flask is called a "microframework" is the idea +to keep the core simple but extensible. There is no database abstraction +layer, no form validation or anything else where different libraries +already exist that can handle that. However Flask knows the concept of +extensions that can add this functionality into your application as if it +was implemented in Flask itself. There are currently extensions for +object relational mappers, form validation, upload handling, various open +authentication technologies and more. + +However Flask is not much code and it is built on a very solid foundation +and with that it is very easy to adapt for large applications. If you are +interested in that, check out the :ref:`becomingbig` chapter. + +If you are curious about the Flask design principles, head over to the +section about :ref:`design`. + +A Framework and an Example +-------------------------- + +Flask is not only a microframework; it is also an example. Based on +Flask, there will be a series of blog posts that explain how to create a +framework. Flask itself is just one way to implement a framework on top +of existing libraries. Unlike many other microframeworks, Flask does not +try to implement everything on its own; it reuses existing code. + +Web Development is Dangerous +---------------------------- + +I'm not joking. Well, maybe a little. If you write a web +application, you are probably allowing users to register and leave their +data on your server. The users are entrusting you with data. And even if +you are the only user that might leave data in your application, you still +want that data to be stored securely. + +Unfortunately, there are many ways the security of a web application can be +compromised. Flask protects you against one of the most common security +problems of modern web applications: cross-site scripting (XSS). Unless +you deliberately mark insecure HTML as secure, Flask and the underlying +Jinja2 template engine have you covered. But there are many more ways to +cause security problems. + +The documentation will warn you about aspects of web development that +require attention to security. Some of these security concerns +are far more complex than one might think, and we all sometimes underestimate +the likelihood that a vulnerability will be exploited, until a clever +attacker figures out a way to exploit our applications. And don't think +that your application is not important enough to attract an attacker. +Depending on the kind of attack, chances are that automated bots are +probing for ways to fill your database with spam, links to malicious +software, and the like. + +So always keep security in mind when doing web development. + +The Status of Python 3 +---------------------- + +Currently the Python community is in the process of improving libraries to +support the new iteration of the Python programming language. +Unfortunately there are a few problems with Python 3, namely the missing +consent on what WSGI for Python 3 should look like. These problems are +partially caused by changes in the language that went unreviewed for too +long, also partially the ambitions of everyone involved to drive the WSGI +standard forward. + +Because of that we strongly recommend against using Python 3 for web +development of any kind and wait until the WSGI situation is resolved. +You will find a couple of frameworks and web libraries on PyPI that claim +Python 3 support, but this support is based on the broken WSGI +implementation provided by Python 3.0 and 3.1 which will most likely +change in the near future. + +Werkzeug and Flask will be ported to Python 3 as soon as a solution for +WSGI is found, and we will provide helpful tips how to upgrade existing +applications to Python 3. Until then, we strongly recommend using Python +2.6 and 2.7 with activated Python 3 warnings during development, as well +as the Unicode literals `__future__` feature.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/htmlfaq.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,207 @@ +HTML/XHTML FAQ +============== + +The Flask documentation and example applications are using HTML5. You +may notice that in many situations, when end tags are optional they are +not used, so that the HTML is cleaner and faster to load. Because there +is much confusion about HTML and XHTML among developers, this document tries +to answer some of the major questions. + + +History of XHTML +---------------- + +For a while, it appeared that HTML was about to be replaced by XHTML. +However, barely any websites on the Internet are actual XHTML (which is +HTML processed using XML rules). There are a couple of major reasons +why this is the case. One of them is Internet Explorer's lack of proper +XHTML support. The XHTML spec states that XHTML must be served with the MIME +type `application/xhtml+xml`, but Internet Explorer refuses to read files +with that MIME type. +While it is relatively easy to configure Web servers to serve XHTML properly, +few people do. This is likely because properly using XHTML can be quite +painful. + +One of the most important causes of pain is XML's draconian (strict and +ruthless) error handling. When an XML parsing error is encountered, +the browser is supposed to show the user an ugly error message, instead +of attempting to recover from the error and display what it can. Most of +the (X)HTML generation on the web is based on non-XML template engines +(such as Jinja, the one used in Flask) which do not protect you from +accidentally creating invalid XHTML. There are XML based template engines, +such as Kid and the popular Genshi, but they often come with a larger +runtime overhead and, are not as straightforward to use because they have +to obey XML rules. + +The majority of users, however, assumed they were properly using XHTML. +They wrote an XHTML doctype at the top of the document and self-closed all +the necessary tags (``<br>`` becomes ``<br/>`` or ``<br></br>`` in XHTML). +However, even if the document properly validates as XHTML, what really +determines XHTML/HTML processing in browsers is the MIME type, which as +said before is often not set properly. So the valid XHTML was being treated +as invalid HTML. + +XHTML also changed the way JavaScript is used. To properly work with XHTML, +programmers have to use the namespaced DOM interface with the XHTML +namespace to query for HTML elements. + +History of HTML5 +---------------- + +Development of the HTML5 specification was started in 2004 under the name +"Web Applications 1.0" by the Web Hypertext Application Technology Working +Group, or WHATWG (which was formed by the major browser vendors Apple, +Mozilla, and Opera) with the goal of writing a new and improved HTML +specification, based on existing browser behaviour instead of unrealistic +and backwards-incompatible specifications. + +For example, in HTML4 ``<title/Hello/`` theoretically parses exactly the +same as ``<title>Hello</title>``. However, since people were using +XHTML-like tags along the lines of ``<link />``, browser vendors implemented +the XHTML syntax over the syntax defined by the specification. + +In 2007, the specification was adopted as the basis of a new HTML +specification under the umbrella of the W3C, known as HTML5. Currently, +it appears that XHTML is losing traction, as the XHTML 2 working group has +been disbanded and HTML5 is being implemented by all major browser vendors. + +HTML versus XHTML +----------------- + +The following table gives you a quick overview of features available in +HTML 4.01, XHTML 1.1 and HTML5. (XHTML 1.0 is not included, as it was +superseded by XHTML 1.1 and the barely-used XHTML5.) + +.. tabularcolumns:: |p{9cm}|p{2cm}|p{2cm}|p{2cm}| + ++-----------------------------------------+----------+----------+----------+ +| | HTML4.01 | XHTML1.1 | HTML5 | ++=========================================+==========+==========+==========+ +| ``<tag/value/`` == ``<tag>value</tag>`` | |Y| [1]_ | |N| | |N| | ++-----------------------------------------+----------+----------+----------+ +| ``<br/>`` supported | |N| | |Y| | |Y| [2]_ | ++-----------------------------------------+----------+----------+----------+ +| ``<script/>`` supported | |N| | |Y| | |N| | ++-----------------------------------------+----------+----------+----------+ +| should be served as `text/html` | |Y| | |N| [3]_ | |Y| | ++-----------------------------------------+----------+----------+----------+ +| should be served as | |N| | |Y| | |N| | +| `application/xhtml+xml` | | | | ++-----------------------------------------+----------+----------+----------+ +| strict error handling | |N| | |Y| | |N| | ++-----------------------------------------+----------+----------+----------+ +| inline SVG | |N| | |Y| | |Y| | ++-----------------------------------------+----------+----------+----------+ +| inline MathML | |N| | |Y| | |Y| | ++-----------------------------------------+----------+----------+----------+ +| ``<video>`` tag | |N| | |N| | |Y| | ++-----------------------------------------+----------+----------+----------+ +| ``<audio>`` tag | |N| | |N| | |Y| | ++-----------------------------------------+----------+----------+----------+ +| New semantic tags like ``<article>`` | |N| | |N| | |Y| | ++-----------------------------------------+----------+----------+----------+ + +.. [1] This is an obscure feature inherited from SGML. It is usually not + supported by browsers, for reasons detailed above. +.. [2] This is for compatibility with server code that generates XHTML for + tags such as ``<br>``. It should not be used in new code. +.. [3] XHTML 1.0 is the last XHTML standard that allows to be served + as `text/html` for backwards compatibility reasons. + +.. |Y| image:: _static/yes.png + :alt: Yes +.. |N| image:: _static/no.png + :alt: No + +What does "strict" mean? +------------------------ + +HTML5 has strictly defined parsing rules, but it also specifies exactly +how a browser should react to parsing errors - unlike XHTML, which simply +states parsing should abort. Some people are confused by apparently +invalid syntax that still generates the expected results (for example, +missing end tags or unquoted attribute values). + +Some of these work because of the lenient error handling most browsers use +when they encounter a markup error, others are actually specified. The +following constructs are optional in HTML5 by standard, but have to be +supported by browsers: + +- Wrapping the document in an ``<html>`` tag +- Wrapping header elements in ``<head>`` or the body elements in + ``<body>`` +- Closing the ``<p>``, ``<li>``, ``<dt>``, ``<dd>``, ``<tr>``, + ``<td>``, ``<th>``, ``<tbody>``, ``<thead>``, or ``<tfoot>`` tags. +- Quoting attributes, so long as they contain no whitespace or + special characters (like ``<``, ``>``, ``'``, or ``"``). +- Requiring boolean attributes to have a value. + +This means the following page in HTML5 is perfectly valid: + +.. sourcecode:: html + + <!doctype html> + <title>Hello HTML5</title> + <div class=header> + <h1>Hello HTML5</h1> + <p class=tagline>HTML5 is awesome + </div> + <ul class=nav> + <li><a href=/index>Index</a> + <li><a href=/downloads>Downloads</a> + <li><a href=/about>About</a> + </ul> + <div class=body> + <h2>HTML5 is probably the future</h2> + <p> + There might be some other things around but in terms of + browser vendor support, HTML5 is hard to beat. + <dl> + <dt>Key 1 + <dd>Value 1 + <dt>Key 2 + <dd>Value 2 + </dl> + </div> + + +New technologies in HTML5 +------------------------- + +HTML5 adds many new features that make Web applications easier to write +and to use. + +- The ``<audio>`` and ``<video>`` tags provide a way to embed audio and + video without complicated add-ons like QuickTime or Flash. +- Semantic elements like ``<article>``, ``<header>``, ``<nav>``, and + ``<time>`` that make content easier to understand. +- The ``<canvas>`` tag, which supports a powerful drawing API, reducing + the need for server-generated images to present data graphically. +- New form control types like ``<input type="date">`` that allow user + agents to make entering and validating values easier. +- Advanced JavaScript APIs like Web Storage, Web Workers, Web Sockets, + geolocation, and offline applications. + +Many other features have been added, as well. A good guide to new features +in HTML5 is Mark Pilgrim's soon-to-be-published book, `Dive Into HTML5`_. +Not all of them are supported in browsers yet, however, so use caution. + +.. _Dive Into HTML5: http://www.diveintohtml5.org/ + +What should be used? +-------------------- + +Currently, the answer is HTML5. There are very few reasons to use XHTML +considering the latest developments in Web browsers. To summarize the +reasons given above: + +- Internet Explorer (which, sadly, currently leads in market share) + has poor support for XHTML. +- Many JavaScript libraries also do not support XHTML, due to the more + complicated namespacing API it requires. +- HTML5 adds several new features, including semantic tags and the + long-awaited ``<audio>`` and ``<video>`` tags. +- It has the support of most browser vendors behind it. +- It is much easier to write, and more compact. + +For most applications, it is undoubtedly better to use HTML5 than XHTML.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/index.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,30 @@ +:orphan: + +Welcome to Flask +================ + +.. image:: _static/logo-full.png + :alt: Flask: web development, one drop at a time + :class: floatingflask + +Welcome to Flask's documentation. This documentation is divided into +different parts. I recommend that you get started with +:ref:`installation` and then head over to the :ref:`quickstart`. +Besides the quickstart there is also a more detailed :ref:`tutorial` that +shows how to create a complete (albeit small) application with Flask. If +you'd rather dive into the internals of Flask, check out +the :ref:`api` documentation. Common patterns are described in the +:ref:`patterns` section. + +Flask depends on two external libraries: the `Jinja2`_ template +engine and the `Werkzeug`_ WSGI toolkit. These libraries are not documented +here. If you want to dive into their documentation check out the +following links: + +- `Jinja2 Documentation <http://jinja.pocoo.org/2/documentation/>`_ +- `Werkzeug Documentation <http://werkzeug.pocoo.org/documentation/>`_ + +.. _Jinja2: http://jinja.pocoo.org/2/ +.. _Werkzeug: http://werkzeug.pocoo.org/ + +.. include:: contents.rst.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/installation.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,175 @@ +.. _installation: + +Installation +============ + +Flask depends on two external libraries, `Werkzeug +<http://werkzeug.pocoo.org/>`_ and `Jinja2 <http://jinja.pocoo.org/2/>`_. +Werkzeug is a toolkit for WSGI, the standard Python interface between web +applications and a variety of servers for both development and deployment. +Jinja2 renders templates. + +So how do you get all that on your computer quickly? There are many ways +which this section will explain, but the most kick-ass method is +virtualenv, so let's look at that first. + +Either way, you will need Python 2.5 or higher to get started, so be sure +to have an up to date Python 2.x installation. At the time of writing, +the WSGI specification is not yet finalized for Python 3, so Flask cannot +support the 3.x series of Python. + +.. _virtualenv: + +virtualenv +---------- + +Virtualenv is probably what you want to use during development, and in +production too if you have shell access there. + +What problem does virtualenv solve? If you like Python as I do, +chances are you want to use it for other projects besides Flask-based +web applications. But the more projects you have, the more likely it is +that you will be working with different versions of Python itself, or at +least different versions of Python libraries. Let's face it; quite often +libraries break backwards compatibility, and it's unlikely that any serious +application will have zero dependencies. So what do you do if two or more +of your projects have conflicting dependencies? + +Virtualenv to the rescue! It basically enables multiple side-by-side +installations of Python, one for each project. It doesn't actually +install separate copies of Python, but it does provide a clever way +to keep different project environments isolated. + +So let's see how virtualenv works! + +If you are on Mac OS X or Linux, chances are that one of the following two +commands will work for you:: + + $ sudo easy_install virtualenv + +or even better:: + + $ sudo pip install virtualenv + +One of these will probably install virtualenv on your system. Maybe it's +even in your package manager. If you use Ubuntu, try:: + + $ sudo apt-get install python-virtualenv + +If you are on Windows and don't have the `easy_install` command, you must +install it first. Check the :ref:`windows-easy-install` section for more +information about how to do that. Once you have it installed, run the +same commands as above, but without the `sudo` prefix. + +Once you have virtualenv installed, just fire up a shell and create +your own environment. I usually create a project folder and an `env` +folder within:: + + $ mkdir myproject + $ cd myproject + $ virtualenv env + New python executable in env/bin/python + Installing setuptools............done. + +Now, whenever you want to work on a project, you only have to activate +the corresponding environment. On OS X and Linux, do the following:: + + $ . env/bin/activate + +(Note the space between the dot and the script name. The dot means that +this script should run in the context of the current shell. If this command +does not work in your shell, try replacing the dot with ``source``) + +If you are a Windows user, the following command is for you:: + + $ env\scripts\activate + +Either way, you should now be using your virtualenv (see how the prompt of +your shell has changed to show the virtualenv). + +Now you can just enter the following command to get Flask activated in +your virtualenv:: + + $ easy_install Flask + +A few seconds later you are good to go. + + +System Wide Installation +------------------------ + +This is possible as well, but I do not recommend it. Just run +`easy_install` with root rights:: + + $ sudo easy_install Flask + +(Run it in an Admin shell on Windows systems and without `sudo`). + + +Living on the Edge +------------------ + +If you want to work with the latest version of Flask, there are two ways: you +can either let `easy_install` pull in the development version, or tell it +to operate on a git checkout. Either way, virtualenv is recommended. + +Get the git checkout in a new virtualenv and run in development mode:: + + $ git clone http://github.com/mitsuhiko/flask.git + Initialized empty Git repository in ~/dev/flask/.git/ + $ cd flask + $ virtualenv env + $ . env/bin/activate + New python executable in env/bin/python + Installing setuptools............done. + $ python setup.py develop + ... + Finished processing dependencies for Flask + +This will pull in the dependencies and activate the git head as the current +version inside the virtualenv. Then you just have to ``git pull origin`` +to get the latest version. + +To just get the development version without git, do this instead:: + + $ mkdir flask + $ cd flask + $ virtualenv env + $ . env/bin/activate + New python executable in env/bin/python + Installing setuptools............done. + $ easy_install Flask==dev + ... + Finished processing dependencies for Flask==dev + +.. _windows-easy-install: + +`easy_install` on Windows +------------------------- + +On Windows, installation of `easy_install` is a little bit trickier because +slightly different rules apply on Windows than on Unix-like systems, but +it's not difficult. The easiest way to do it is to download the +`ez_setup.py`_ file and run it. The easiest way to run the file is to +open your downloads folder and double-click on the file. + +Next, add the `easy_install` command and other Python scripts to the +command search path, by adding your Python installation's Scripts folder +to the `PATH` environment variable. To do that, right-click on the +"Computer" icon on the Desktop or in the Start menu, and choose +"Properties". Then, on Windows Vista and Windows 7 click on "Advanced System +settings"; on Windows XP, click on the "Advanced" tab instead. Then click +on the "Environment variables" button and double click on the "Path" +variable in the "System variables" section. There append the path of your +Python interpreter's Scripts folder; make sure you delimit it from +existing values with a semicolon. Assuming you are using Python 2.6 on +the default path, add the following value:: + + ;C:\Python26\Scripts + +Then you are done. To check that it worked, open the Command Prompt and +execute ``easy_install``. If you have User Account Control enabled on +Windows Vista or Windows 7, it should prompt you for admin privileges. + + +.. _ez_setup.py: http://peak.telecommunity.com/dist/ez_setup.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/latexindex.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,6 @@ +:orphan: + +Flask Documentation +=================== + +.. include:: contents.rst.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/license.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,48 @@ +License +======= + +Flask is licensed under a three clause BSD License. It basically means: +do whatever you want with it as long as the copyright in Flask sticks +around, the conditions are not modified and the disclaimer is present. +Furthermore you must not use the names of the authors to promote derivatives +of the software without written consent. + +The full license text can be found below (:ref:`flask-license`). For the +documentation and artwork different licenses apply. + +.. _authors: + +Authors +------- + +.. include:: ../AUTHORS + +General License Definitions +--------------------------- + +The following section contains the full license texts for Flask and the +documentation. + +- "AUTHORS" hereby refers to all the authors listed in the + :ref:`authors` section. + +- The ":ref:`flask-license`" applies to all the sourcecode shipped as + part of Flask (Flask itself as well as the examples and the unittests) + as well as documentation. + +- The ":ref:`artwork-license`" applies to the project's Horn-Logo. + +.. _flask-license: + +Flask License +------------- + +.. include:: ../LICENSE + + +.. _artwork-license: + +Flask Artwork License +--------------------- + +.. include:: ../artwork/LICENSE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/make.bat Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,139 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :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. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. changes to make an overview over 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 + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "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. + goto end +) + +if "%1" == "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\Flask.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Flask.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% _build/devhelp + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "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. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/appfactories.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,75 @@ +.. _app-factories: + +Application Factories +===================== + +If you are already using packages and modules for your application +(:ref:`packages`) there are a couple of really nice ways to further improve +the experience. A common pattern is creating the application object when +the module is imported. But if you move the creation of this object, +into a function, you can then create multiple instances of this and later. + +So why would you want to do this? + +1. Testing. You can have instances of the application with different + settings to test every case. +2. Multiple instances. Imagine you want to run different versions of the + same application. Of course you could have multiple instances with + different configs set up in your webserver, but if you use factories, + you can have multiple instances of the same application running in the + same application process which can be handy. + +So how would you then actually implement that? + +Basic Factories +--------------- + +The idea is to set up the application in a function. Like this:: + + def create_app(config_filename): + app = Flask(__name__) + app.config.from_pyfile(config_filename) + + from yourapplication.views.admin import admin + from yourapplication.views.frontend import frontend + app.register_module(admin) + app.register_module(frontend) + + return app + +The downside is that you cannot use the application object in the modules +at import time. You can however use it from within a request. How do you +get access the application with the config? Use +:data:`~flask.current_app`:: + + from flask import current_app, Module, render_template + admin = Module(__name__, url_prefix='/admin') + + @admin.route('/') + def index(): + return render_template(current_app.config['INDEX_TEMPLATE']) + +Here we look up the name of a template in the config. + +Using Applications +------------------ + +So to use such an application you then have to create the application +first. Here an example `run.py` file that runs such an application:: + + from yourapplication import create_app + app = create_app('/path/to/config.cfg') + app.run() + +Factory Improvements +-------------------- + +The factory function from above is not very clever so far, you can improve +it. The following changes are straightforward and possible: + +1. make it possible to pass in configuration values for unittests so that + you don't have to create config files on the filesystem +2. call a function from a module when the application is setting up so + that you have a place to modify attributes of the application (like + hooking in before / after request handlers etc.) +3. Add in WSGI middlewares when the application is creating if necessary.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/caching.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,69 @@ +.. _caching-pattern: + +Caching +======= + +When your application runs slow, throw some caches in. Well, at least +it's the easiest way to speed up things. What does a cache do? Say you +have a function that takes some time to complete but the results would +still be good enough if they were 5 minutes old. So then the idea is that +you actually put the result of that calculation into a cache for some +time. + +Flask itself does not provide caching for you, but Werkzeug, one of the +libraries it is based on, has some very basic cache support. It supports +multiple cache backends, normally you want to use a memcached server. + +Setting up a Cache +------------------ + +You create a cache object once and keep it around, similar to how +:class:`~flask.Flask` objects are created. If you are using the +development server you can create a +:class:`~werkzeug.contrib.cache.SimpleCache` object, that one is a simple +cache that keeps the item stored in the memory of the Python interpreter:: + + from werkzeug.contrib.cache import SimpleCache + cache = SimpleCache() + +If you want to use memcached, make sure to have one of the memcache modules +supported (you get them from `PyPI <http://pypi.python.org/>`_) and a +memcached server running somewhere. This is how you connect to such an +memcached server then:: + + from werkzeug.contrib.cache import MemcachedCache + cache = MemcachedCache(['127.0.0.1:11211']) + +If you are using App Engine, you can connect to the App Engine memcache +server easily:: + + from werkzeug.contrib.cache import GAEMemcachedCache + cache = GAEMemcachedCache() + +Using a Cache +------------- + +Now how can one use such a cache? There are two very important +operations: :meth:`~werkzeug.contrib.cache.BaseCache.get` and +:meth:`~werkzeug.contrib.cache.BaseCache.set`. This is how to use them: + +To get an item from the cache call +:meth:`~werkzeug.contrib.cache.BaseCache.get` with a string as key name. +If something is in the cache, it is returned. Otherwise that function +will return `None`:: + + rv = cache.get('my-item') + +To add items to the cache, use the :meth:`~werkzeug.contrib.cache.BaseCache.set` +method instead. The first argument is the key and the second the value +that should be set. Also a timeout can be provided after which the cache +will automatically remove item. + +Here a full example how this looks like normally:: + + def get_my_item(): + rv = cache.get('my-item') + if rv is None: + rv = calculate_value() + cache.set('my-item', rv, timeout=5 * 60) + return rv
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/distribute.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,166 @@ +.. _distribute-deployment: + +Deploying with Distribute +========================= + +`distribute`_, formerly setuptools, is an extension library that is +commonly used to (like the name says) distribute Python libraries and +extensions. It extends distutils, a basic module installation system +shipped with Python to also support various more complex constructs that +make larger applications easier to distribute: + +- **support for dependencies**: a library or application can declare a + list of other libraries it depends on which will be installed + automatically for you. +- **package registry**: setuptools registers your package with your + Python installation. This makes it possible to query information + provided by one package from another package. The best known feature of + this system is the entry point support which allows one package to + declare an "entry point" another package can hook into to extend the + other package. +- **installation manager**: `easy_install`, which comes with distribute + can install other libraries for you. You can also use `pip`_ which + sooner or later will replace `easy_install` which does more than just + installing packages for you. + +Flask itself, and all the libraries you can find on the cheeseshop +are distributed with either distribute, the older setuptools or distutils. + +In this case we assume your application is called +`yourapplication.py` and you are not using a module, but a :ref:`package +<larger-applications>`. Distributing resources with standard modules is +not supported by `distribute`_ so we will not bother with it. If you have +not yet converted your application into a package, head over to the +:ref:`larger-applications` pattern to see how this can be done. + +A working deployment with distribute is the first step into more complex +and more automated deployment scenarios. If you want to fully automate +the process, also read the :ref:`fabric-deployment` chapter. + +Basic Setup Script +------------------ + +Because you have Flask running, you either have setuptools or distribute +available on your system anyways. If you do not, fear not, there is a +script to install it for you: `distribute_setup.py`_. Just download and +run with your Python interpreter. + +Standard disclaimer applies: :ref:`you better use a virtualenv +<virtualenv>`. + +Your setup code always goes into a file named `setup.py` next to your +application. The name of the file is only convention, but because +everybody will look for a file with that name, you better not change it. + +Yes, even if you are using `distribute`, you are importing from a package +called `setuptools`. `distribute` is fully backwards compatible with +`setuptools`, so it also uses the same import name. + +A basic `setup.py` file for a Flask application looks like this:: + + from setuptools import setup + + setup( + name='Your Application', + version='1.0', + long_description=__doc__, + packages=['yourapplication'], + include_package_data=True, + zip_safe=False, + install_requires=['Flask'] + ) + +Please keep in mind that you have to list subpackages explicitly. If you +want distribute to lookup the packages for you automatically, you can use +the `find_packages` function:: + + from setuptools import setup, find_packages + + setup( + ... + packages=find_packages() + ) + +Most parameters to the `setup` function should be self explanatory, +`include_package_data` and `zip_safe` might not be. +`include_package_data` tells distribute to look for a `MANIFEST.in` file +and install all the entries that match as package data. We will use this +to distribute the static files and templates along with the Python module +(see :ref:`distributing-resources`). The `zip_safe` flag can be used to +force or prevent zip Archive creation. In general you probably don't want +your packages to be installed as zip files because some tools do not +support them and they make debugging a lot harder. + + +.. _distributing-resources: + +Distributing Resources +---------------------- + +If you try to install the package you just created, you will notice that +folders like `static` or `templates` are not installed for you. The +reason for this is that distribute does not know which files to add for +you. What you should do, is to create a `MANIFEST.in` file next to your +`setup.py` file. This file lists all the files that should be added to +your tarball:: + + recursive-include yourapplication/templates * + recursive-include yourapplication/static * + +Don't forget that even if you enlist them in your `MANIFEST.in` file, they +won't be installed for you unless you set the `include_package_data` +parameter of the `setup` function to `True`! + + +Declaring Dependencies +---------------------- + +Dependencies are declared in the `install_requires` parameter as list. +Each item in that list is the name of a package that should be pulled from +PyPI on installation. By default it will always use the most recent +version, but you can also provide minimum and maximum version +requirements. Here some examples:: + + install_requires=[ + 'Flask>=0.2', + 'SQLAlchemy>=0.6', + 'BrokenPackage>=0.7,<=1.0' + ] + +I mentioned earlier that dependencies are pulled from PyPI. What if you +want to depend on a package that cannot be found on PyPI and won't be +because it is an internal package you don't want to share with anyone? +Just still do as if there was a PyPI entry for it and provide a list of +alternative locations where distribute should look for tarballs:: + + dependency_links=['http://example.com/yourfiles'] + +Make sure that page has a directory listing and the links on the page are +pointing to the actual tarballs with their correct filenames as this is +how distribute will find the files. If you have an internal company +server that contains the packages, provide the URL to that server there. + + +Installing / Developing +----------------------- + +To install your application (ideally into a virtualenv) just run the +`setup.py` script with the `install` parameter. It will install your +application into the virtualenv's site-packages folder and also download +and install all dependencies:: + + $ python setup.py install + +If you are developing on the package and also want the requirements to be +installed, you can use the `develop` command instead:: + + $ python setup.py develop + +This has the advantage of just installing a link to the site-packages +folder instead of copying the data over. You can then continue to work on +the code without having to run `install` again after each change. + + +.. _distribute: http://pypi.python.org/pypi/distribute +.. _pip: http://pypi.python.org/pypi/pip +.. _distribute_setup.py: http://python-distribute.org/distribute_setup.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/errorpages.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,77 @@ +Custom Error Pages +================== + +Flask comes with a handy :func:`~flask.abort` function that aborts a +request with an HTTP error code early. It will also provide a plain black +and white error page for you with a basic description, but nothing fancy. + +Depending on the error code it is less or more likely for the user to +actually see such an error. + +Common Error Codes +------------------ + +The following error codes are some that are often displayed to the user, +even if the application behaves correctly: + +*404 Not Found* + The good old "chap, you made a mistake typing that URL" message. So + common that even novices to the internet know that 404 means: damn, + the thing I was looking for is not there. It's a very good idea to + make sure there is actually something useful on a 404 page, at least a + link back to the index. + +*403 Forbidden* + If you have some kind of access control on your website, you will have + to send a 403 code for disallowed resources. So make sure the user + is not lost when he tries to access a resource he cannot access. + +*410 Gone* + Did you know that there the "404 Not Found" has a brother named "410 + Gone"? Few people actually implement that, but the idea is that + resources that previously existed and got deleted answer with 410 + instead of 404. If you are not deleting documents permanently from + the database but just mark them as deleted, do the user a favour and + use the 410 code instead and display a message that what he was + looking for was deleted for all eternity. + +*500 Internal Server Error* + Usually happens on programming errors or if the server is overloaded. + A terrible good idea to have a nice page there, because your + application *will* fail sooner or later (see also: + :ref:`application-errors`). + + +Error Handlers +-------------- + +An error handler is a function, just like a view function, but it is +called when an error happens and is passed that error. The error is most +likely a :exc:`~werkzeug.exceptions.HTTPException`, but in one case it +can be a different error: a handler for internal server errors will be +passed other exception instances as well if they are uncaught. + +An error handler is registered with the :meth:`~flask.Flask.errorhandler` +decorator and the error code of the exception. Keep in mind that Flask +will *not* set the error code for you, so make sure to also provide the +HTTP status code when returning a response. + +Here an example implementation for a "404 Page Not Found" exception:: + + from flask import render_template + + @app.errorhandler(404) + def page_not_found(e): + return render_template('404.html'), 404 + +An example template might be this: + +.. sourcecode:: html+jinja + + {% extends "layout.html" %} + {% block title %}Page Not Found{% endblock %} + {% block body %} + <h1>Page Not Found</h1> + <p>What you were looking for is just not there. + <p><a href="{{ url_for('index') }}">go somewhere nice</a> + {% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/fabric.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,196 @@ +.. _fabric-deployment: + +Deploying with Fabric +===================== + +`Fabric`_ is a tool for Python similar to Makefiles but with the ability +to execute commands on a remote server. In combination with a properly +set up Python package (:ref:`larger-applications`) and a good concept for +configurations (:ref:`config`) it is very easy to deploy Flask +applications to external servers. + +Before we get started, here a quick checklist of things we have to ensure +upfront: + +- Fabric 1.0 has to be installed locally. This tutorial assumes the + latest version of Fabric. +- The application already has to be a package and requires a working + `setup.py` file (:ref:`distribute-deployment`). +- In the following example we are using `mod_wsgi` for the remote + servers. You can of course use your own favourite server there, but + for this example we chose Apache + `mod_wsgi` because it's very easy + to setup and has a simple way to reload applications without root + access. + +Creating the first Fabfile +-------------------------- + +A fabfile is what controls what Fabric executes. It is named `fabfile.py` +and executed by the `fab` command. All the functions defined in that file +will show up as `fab` subcommands. They are executed on one or more +hosts. These hosts can be defined either in the fabfile or on the command +line. In this case we will add them to the fabfile. + +This is a basic first example that has the ability to upload the current +sourcecode to the server and install it into a already existing +virtual environment:: + + from fabric.api import * + + # the user to use for the remote commands + env.user = 'appuser' + # the servers where the commands are executed + env.hosts = ['server1.example.com', 'server2.example.com'] + + def pack(): + # create a new source distribution as tarball + local('python setup.py sdist --formats=gztar', capture=False) + + def deploy(): + # figure out the release name and version + dist = local('python setup.py --fullname').strip() + # upload the source tarball to the temporary folder on the server + put('dist/%s.tar.gz' % dist, '/tmp/yourapplication.tar.gz') + # create a place where we can unzip the tarball, then enter + # that directory and unzip it + run('mkdir yourapplication') + with cd('/tmp/yourapplication'): + run('tar xzf /tmp/yourapplication.tar.gz') + # now setup the package with our virtual environment's + # python interpreter + run('/var/www/yourapplication/env/bin/python setup.py install') + # now that all is set up, delete the folder again + run('rm -rf /tmp/yourapplication /tmp/yourapplication.tar.gz') + # and finally touch the .wsgi file so that mod_wsgi triggers + # a reload of the application + run('touch /var/www/yourapplication.wsgi') + +The example above is well documented and should be straightforward. Here +a recap of the most common commands fabric provides: + +- `run` - executes a command on a remote server +- `local` - executes a command on the local machine +- `put` - uploads a file to the remote server +- `cd` - changes the directory on the serverside. This has to be used + in combination with the `with` statement. + +Running Fabfiles +---------------- + +Now how do you execute that fabfile? You use the `fab` command. To +deploy the current version of the code on the remote server you would use +this command:: + + $ fab pack deploy + +However this requires that our server already has the +``/var/www/yourapplication`` folder created and +``/var/www/yourapplication/env`` to be a virtual environment. Furthermore +are we not creating the configuration or `.wsgi` file on the server. So +how do we bootstrap a new server into our infrastructure? + +This now depends on the number of servers we want to set up. If we just +have one application server (which the majority of applications will +have), creating a command in the fabfile for this is overkill. But +obviously you can do that. In that case you would probably call it +`setup` or `bootstrap` and then pass the servername explicitly on the +command line:: + + $ fab -H newserver.example.com bootstrap + +To setup a new server you would roughly do these steps: + +1. Create the directory structure in ``/var/www``:: + + $ mkdir /var/www/yourapplication + $ cd /var/www/yourapplication + $ virtualenv --distribute env + +2. Upload a new `application.wsgi` file to the server and the + configuration file for the application (eg: `application.cfg`) + +3. Create a new Apache config for `yourapplication` and activate it. + Make sure to activate watching for changes of the `.wsgi` file so + that we can automatically reload the application by touching it. + (See :ref:`mod_wsgi-deployment` for more information) + +So now the question is, where do the `application.wsgi` and +`application.cfg` files come from? + +The WSGI File +------------- + +The WSGI file has to import the application and also to set an environment +variable so that the application knows where to look for the config. This +is a short example that does exactly that:: + + import os + os.environ['YOURAPPLICATION_CONFIG'] = '/var/www/yourapplication/application.cfg' + from yourapplication import app + +The application itself then has to initialize itself like this to look for +the config at that environment variable:: + + app = Flask(__name__) + app.config.from_object('yourapplication.default_config') + app.config.from_envvar('YOURAPPLICATION_CONFIG') + +This approach is explained in detail in the :ref:`config` section of the +documentation. + +The Configuration File +---------------------- + +Now as mentioned above, the application will find the correct +configuration file by looking up the `YOURAPPLICATION_CONFIG` environment +variable. So we have to put the configuration in a place where the +application will able to find it. Configuration files have the unfriendly +quality of being different on all computers, so you do not version them +usually. + +A popular approach is to store configuration files for different servers +in a separate version control repository and check them out on all +servers. Then symlink the file that is active for the server into the +location where it's expected (eg: ``/var/www/yourapplication``). + +Either way, in our case here we only expect one or two servers and we can +upload them ahead of time by hand. + +First Deployment +---------------- + +Now we can do our first deployment. We have set up the servers so that +they have their virtual environments and activated apache configs. Now we +can pack up the application and deploy it:: + + $ fab pack deploy + +Fabric will now connect to all servers and run the commands as written +down in the fabfile. First it will execute pack so that we have our +tarball ready and then it will execute deploy and upload the source code +to all servers and install it there. Thanks to the `setup.py` file we +will automatically pull in the required libraries into our virtual +environment. + +Next Steps +---------- + +From that point onwards there is so much that can be done to make +deployment actually fun: + +- Create a `bootstrap` command that initializes new servers. It could + initialize a new virtual environment, setup apache appropriately etc. +- Put configuration files into a separate version control repository + and symlink the active configs into place. +- You could also put your application code into a repository and check + out the latest version on the server and then install. That way you + can also easily go back to older versions. +- hook in testing functionality so that you can deploy to an external + server and run the testsuite. + +Working with Fabric is fun and you will notice that it's quite magical to +type ``fab deploy`` and see your application being deployed automatically +to one or more remote servers. + + +.. _Fabric: http://fabfile.org/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/favicon.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,53 @@ +Adding a favicon +================ + +A "favicon" is an icon used by browsers for tabs and bookmarks. This helps +to distinguish your website and to give it a unique brand. + +A common question is how to add a favicon to a flask application. First, of +course, you need an icon. It should be 16 × 16 pixels and in the ICO file +format. This is not a requirement but a de-facto standard supported by all +relevant browsers. Put the icon in your static directory as +:file:`favicon.ico`. + +Now, to get browsers to find your icon, the correct way is to add a link +tag in your HTML. So, for example: + +.. sourcecode:: html+jinja + + <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"> + +That's all you need for most browsers, however some really old ones do not +support this standard. The old de-facto standard is to serve this file, +with this name, at the website root. If your application is not mounted at +the root path of the domain you either need to configure the webserver to +serve the icon at the root or if you can't do that you're out of luck. If +however your application is the root you can simply route a redirect:: + + app.add_url_rule('/favicon.ico', + redirect_to=url_for('static', filename='favicon.ico')) + +If you want to save the extra redirect request you can also write a view +using :func:`~flask.send_from_directory`:: + + import os + from flask import send_from_directory + + @app.route('/favicon.ico') + def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + +We can leave out the explicit mimetype and it will be guessed, but we may +as well specify it to avoid the extra guessing, as it will always be the +same. + +The above will serve the icon via your application and if possible it's +better to configure your dedicated web server to serve it; refer to the +webserver's documentation. + +See also +-------- + +* The `Favicon <http://en.wikipedia.org/wiki/Favicon>`_ article on + Wikipedia
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/fileuploads.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,180 @@ +.. _uploading-files: + +Uploading Files +=============== + +Ah yes, the good old problem of file uploads. The basic idea of file +uploads is actually quite simple. It basically works like this: + +1. A ``<form>`` tag is marked with ``enctype=multipart/form-data`` + and an ``<input type=file>`` is placed in that form. +2. The application accesses the file from the :attr:`~flask.request.files` + dictionary on the request object. +3. use the :meth:`~werkzeug.FileStorage.save` method of the file to save + the file permanently somewhere on the filesystem. + +A Gentle Introduction +--------------------- + +Let's start with a very basic application that uploads a file to a +specific upload folder and displays a file to the user. Let's look at the +bootstrapping code for our application:: + + import os + from flask import Flask, request, redirect, url_for + from werkzeug import secure_filename + + UPLOAD_FOLDER = '/path/to/the/uploads' + ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) + + app = Flask(__name__) + +So first we need a couple of imports. Most should be straightforward, the +:func:`werkzeug.secure_filename` is explained a little bit later. The +`UPLOAD_FOLDER` is where we will store the uploaded files and the +`ALLOWED_EXTENSIONS` is the set of allowed file extensions. Then we add a +URL rule by hand to the application. Now usually we're not doing that, so +why here? The reasons is that we want the webserver (or our development +server) to serve these files for us and so we only need a rule to generate +the URL to these files. + +Why do we limit the extensions that are allowed? You probably don't want +your users to be able to upload everything there if the server is directly +sending out the data to the client. That way you can make sure that users +are not able to upload HTML files that would cause XSS problems (see +:ref:`xss`). Also make sure to disallow `.php` files if the server +executes them, but who has PHP installed on his server, right? :) + +Next the functions that check if an extension is valid and that uploads +the file and redirects the user to the URL for the uploaded file:: + + def allowed_file(filename): + return '.' in filename and \ + filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS + + @app.route('/', methods=['GET', 'POST']) + def upload_file(): + if request.method == 'POST': + file = request.files['file'] + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + file.save(os.path.join(UPLOAD_FOLDER, filename)) + return redirect(url_for('uploaded_file', + filename=filename)) + return ''' + <!doctype html> + <title>Upload new File</title> + <h1>Upload new File</h1> + <form action="" method=post enctype=multipart/form-data> + <p><input type=file name=file> + <input type=submit value=Upload> + </form> + ''' + +So what does that :func:`~werkzeug.secure_filename` function actually do? +Now the problem is that there is that principle called "never trust user +input". This is also true for the filename of an uploaded file. All +submitted form data can be forged, and filenames can be dangerous. For +the moment just remember: always use that function to secure a filename +before storing it directly on the filesystem. + +.. admonition:: Information for the Pros + + So you're interested in what that :func:`~werkzeug.secure_filename` + function does and what the problem is if you're not using it? So just + imagine someone would send the following information as `filename` to + your application:: + + filename = "../../../../home/username/.bashrc" + + Assuming the number of ``../`` is correct and you would join this with + the `UPLOAD_FOLDER` the user might have the ability to modify a file on + the server's filesystem he should not modify. This does require some + knowledge about how the application looks like, but trust me, hackers + are patient :) + + Now let's look how that function works: + + >>> secure_filename('../../../../home/username/.bashrc') + 'home_username_.bashrc' + +Now one last thing is missing: the serving of the uploaded files. As of +Flask 0.5 we can use a function that does that for us:: + + from flask import send_from_directory + + @app.route('/uploads/<filename>') + def uploaded_file(filename): + return send_from_directory(app.config['UPLOAD_FOLDER'], + filename) + +Alternatively you can register `uploaded_file` as `build_only` rule and +use the :class:`~werkzeug.SharedDataMiddleware`. This also works with +older versions of Flask:: + + from werkzeug import SharedDataMiddleware + app.add_url_rule('/uploads/<filename>', 'uploaded_file', + build_only=True) + app.wsgi_app = SharedDataMiddleware(app.wsgi_app, { + '/uploads': UPLOAD_FOLDER + }) + +If you now run the application everything should work as expected. + + +Improving Uploads +----------------- + +.. versionadded:: 0.6 + +So how exactly does Flask handle uploads? Well it will store them in the +webserver's memory if the files are reasonable small otherwise in a +temporary location (as returned by :func:`tempfile.gettempdir`). But how +do you specify the maximum file size after which an upload is aborted? By +default Flask will happily accept file uploads to an unlimited amount of +memory, but you can limit that by setting the ``MAX_CONTENT_LENGTH`` +config key:: + + from flask import Flask, Request + + app = Flask(__name__) + app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 + +The code above will limited the maximum allowed payload to 16 megabytes. +If a larger file is transmitted, Flask will raise an +:exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception. + +This feature was added in Flask 0.6 but can be achieved in older versions +as well by subclassing the request object. For more information on that +consult the Werkzeug documentation on file handling. + + +Upload Progress Bars +-------------------- + +A while ago many developers had the idea to read the incoming file in +small chunks and store the upload progress in the database to be able to +poll the progress with JavaScript from the client. Long story short: the +client asks the server every 5 seconds how much he has transmitted +already. Do you realize the irony? The client is asking for something he +should already know. + +Now there are better solutions to that work faster and more reliable. The +web changed a lot lately and you can use HTML5, Java, Silverlight or Flash +to get a nicer uploading experience on the client side. Look at the +following libraries for some nice examples how to do that: + +- `Plupload <http://www.plupload.com/>`_ - HTML5, Java, Flash +- `SWFUpload <http://www.swfupload.org/>`_ - Flash +- `JumpLoader <http://jumploader.com/>`_ - Java + + +An Easier Solution +------------------ + +Because the common pattern for file uploads exists almost unchanged in all +applications dealing with uploads, there is a Flask extension called +`Flask-Uploads`_ that implements a full fledged upload mechanism with +white and blacklisting of extensions and more. + +.. _Flask-Uploads: http://packages.python.org/Flask-Uploads/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/flashing.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,119 @@ +.. _message-flashing-pattern: + +Message Flashing +================ + +Good applications and user interfaces are all about feedback. If the user +does not get enough feedback he will probably end up hating the +application. Flask provides a really simple way to give feedback to a +user with the flashing system. The flashing system basically makes it +possible to record a message at the end of a request and access it next +request and only next request. This is usually combined with a layout +template that does this. + +Simple Flashing +--------------- + +So here is a full example:: + + from flask import flash, redirect, url_for, render_template + + @app.route('/') + def index(): + return render_template('index.html') + + @app.route('/login', methods=['GET', 'POST']) + def login(): + error = None + if request.method == 'POST': + if request.form['username'] != 'admin' or \ + request.form['password'] != 'secret': + error = 'Invalid credentials' + else: + flash('You were successfully logged in') + return redirect(url_for('index')) + return render_template('login.html', error=error) + +And here the ``layout.html`` template which does the magic: + +.. sourcecode:: html+jinja + + <!doctype html> + <title>My Application</title> + {% with messages = get_flashed_messages() %} + {% if messages %} + <ul class=flashes> + {% for message in messages %} + <li>{{ message }}</li> + {% endfor %} + </ul> + {% endif %} + {% endwith %} + {% block body %}{% endblock %} + +And here the index.html template: + +.. sourcecode:: html+jinja + + {% extends "layout.html" %} + {% block body %} + <h1>Overview</h1> + <p>Do you want to <a href="{{ url_for('login') }}">log in?</a> + {% endblock %} + +And of course the login template: + +.. sourcecode:: html+jinja + + {% extends "layout.html" %} + {% block body %} + <h1>Login</h1> + {% if error %} + <p class=error><strong>Error:</strong> {{ error }} + {% endif %} + <form action="" method=post> + <dl> + <dt>Username: + <dd><input type=text name=username value="{{ + request.form.username }}"> + <dt>Password: + <dd><input type=password name=password> + </dl> + <p><input type=submit value=Login> + </form> + {% endblock %} + +Flashing With Categories +------------------------ + +.. versionadded:: 0.3 + +It is also possible to provide categories when flashing a message. The +default category if nothing is provided is ``'message'``. Alternative +categories can be used to give the user better feedback. For example +error messages could be displayed with a red background. + +To flash a message with a different category, just use the second argument +to the :func:`~flask.flash` function:: + + flash(u'Invalid password provided', 'error') + +Inside the template you then have to tell the +:func:`~flask.get_flashed_messages` function to also return the +categories. The loop looks slightly different in that situation then: + +.. sourcecode:: html+jinja + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + <ul class=flashes> + {% for category, message in messages %} + <li class="{{ category }}">{{ message }}</li> + {% endfor %} + </ul> + {% endif %} + {% endwith %} + +This is just one example of how to render these flashed messages. One +might also use the category to add a prefix such as +``<strong>Error:</strong>`` to the message.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/index.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,35 @@ +.. _patterns: + +Patterns for Flask +================== + +Certain things are common enough that the chances are high you will find +them in most web applications. For example quite a lot of applications +are using relational databases and user authentication. In that case, +chances are they will open a database connection at the beginning of the +request and get the information of the currently logged in user. At the +end of the request, the database connection is closed again. + +There are more user contributed snippets and patterns in the `Flask +Snippet Archives <http://flask.pocoo.org/snippets/>`_. + +.. toctree:: + :maxdepth: 2 + + packages + appfactories + distribute + fabric + sqlite3 + sqlalchemy + fileuploads + caching + viewdecorators + wtforms + templateinheritance + flashing + jquery + errorpages + lazyloading + mongokit + favicon
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/jquery.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,167 @@ +AJAX with jQuery +================ + +`jQuery`_ is a small JavaScript library commonly used to simplify working +with the DOM and JavaScript in general. It is the perfect tool to make +web applications more dynamic by exchanging JSON between server and +client. + +JSON itself is a very lightweight transport format, very similar to how +Python primitives (numbers, strings, dicts and lists) look like which is +widely supported and very easy to parse. It became popular a few years +ago and quickly replaced XML as transport format in web applications. + +If you have Python 2.6 JSON will work out of the box, in Python 2.5 you +will have to install the `simplejson`_ library from PyPI. + +.. _jQuery: http://jquery.com/ +.. _simplejson: http://pypi.python.org/pypi/simplejson + +Loading jQuery +-------------- + +In order to use jQuery, you have to download it first and place it in the +static folder of your application and then ensure it's loaded. Ideally +you have a layout template that is used for all pages where you just have +to add a script statement to your `head` to load jQuery: + +.. sourcecode:: html + + <script type=text/javascript src="{{ + url_for('static', filename='jquery.js') }}"></script> + +Another method is using Google's `AJAX Libraries API +<http://code.google.com/apis/ajaxlibs/documentation/>`_ to load jQuery: + +.. sourcecode:: html + + <script type=text/javascript + src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> + +In this case you don't have to put jQuery into your static folder, it will +instead be loaded from Google directly. This has the advantage that your +website will probably load faster for users if they went to at least one +other website before using the same jQuery version from Google because it +will already be in the browser cache. Downside is that if you don't have +network connectivity during development jQuery will not load. + +Where is My Site? +----------------- + +Do you know where your application is? If you are developing the answer +is quite simple: it's on localhost port something and directly on the root +of that server. But what if you later decide to move your application to +a different location? For example to ``http://example.com/myapp``? On +the server side this never was a problem because we were using the handy +:func:`~flask.url_for` function that could answer that question for +us, but if we are using jQuery we should not hardcode the path to +the application but make that dynamic, so how can we do that? + +A simple method would be to add a script tag to our page that sets a +global variable to the prefix to the root of the application. Something +like this: + +.. sourcecode:: html+jinja + + <script type=text/javascript> + $SCRIPT_ROOT = {{ request.script_root|tojson|safe }}; + </script> + +The ``|safe`` is necessary so that Jinja does not escape the JSON encoded +string with HTML rules. Usually this would be necessary, but we are +inside a `script` block here where different rules apply. + +.. admonition:: Information for Pros + + In HTML the `script` tag is declared `CDATA` which means that entities + will not be parsed. Everything until ``</script>`` is handled as script. + This also means that there must never be any ``</`` between the script + tags. ``|tojson`` is kind enough to do the right thing here and + escape slashes for you (``{{ "</script>"|tojson|safe }}`` is rendered as + ``"<\/script>"``). + + +JSON View Functions +------------------- + +Now let's create a server side function that accepts two URL arguments of +numbers which should be added together and then sent back to the +application in a JSON object. This is a really ridiculous example and is +something you usually would do on the client side alone, but a simple +example that shows how you would use jQuery and Flask nonetheless:: + + from flask import Flask, jsonify, render_template, request + app = Flask(__name__) + + @app.route('/_add_numbers') + def add_numbers(): + a = request.args.get('a', 0, type=int) + b = request.args.get('b', 0, type=int) + return jsonify(result=a + b) + + @app.route('/') + def index(): + return render_template('index.html') + +As you can see I also added an `index` method here that renders a +template. This template will load jQuery as above and have a little form +we can add two numbers and a link to trigger the function on the server +side. + +Note that we are using the :meth:`~werkzeug.MultiDict.get` method here +which will never fail. If the key is missing a default value (here ``0``) +is returned. Furthermore it can convert values to a specific type (like +in our case `int`). This is especially handy for code that is +triggered by a script (APIs, JavaScript etc.) because you don't need +special error reporting in that case. + +The HTML +-------- + +Your index.html template either has to extend a `layout.html` template with +jQuery loaded and the `$SCRIPT_ROOT` variable set, or do that on the top. +Here's the HTML code needed for our little application (`index.html`). +Notice that we also drop the script directly into the HTML here. It is +usually a better idea to have that in a separate script file: + +.. sourcecode:: html + + <script type=text/javascript> + $(function() { + $('a#calculate').bind('click', function() { + $.getJSON($SCRIPT_ROOT + '/_add_numbers', { + a: $('input[name="a"]').val(), + b: $('input[name="b"]').val() + }, function(data) { + $("#result").text(data.result); + }); + return false; + }); + }); + </script> + <h1>jQuery Example</h1> + <p><input type=text size=5 name=a> + + <input type=text size=5 name=b> = + <span id=result>?</span> + <p><a href=# id=calculate>calculate server side</a> + +I won't got into detail here about how jQuery works, just a very quick +explanation of the little bit of code above: + +1. ``$(function() { ... })`` specifies code that should run once the + browser is done loading the basic parts of the page. +2. ``$('selector')`` selects an element and lets you operate on it. +3. ``element.bind('event', func)`` specifies a function that should run + when the user clicked on the element. If that function returns + `false`, the default behaviour will not kick in (in this case, navigate + to the `#` URL). +4. ``$.getJSON(url, data, func)`` sends a `GET` request to `url` and will + send the contents of the `data` object as query parameters. Once the + data arrived, it will call the given function with the return value as + argument. Note that we can use the `$SCRIPT_ROOT` variable here that + we set earlier. + +If you don't get the whole picture, download the `sourcecode +for this example +<http://github.com/mitsuhiko/flask/tree/master/examples/jqueryexample>`_ +from github.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/lazyloading.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,104 @@ +Lazily Loading Views +==================== + +Flask is usually used with the decorators. Decorators are simple and you +have the URL right next to the function that is called for that specific +URL. However there is a downside to this approach: it means all your code +that uses decorators has to be imported upfront or Flask will never +actually find your function. + +This can be a problem if your application has to import quick. It might +have to do that on systems like Google's App Engine or other systems. So +if you suddenly notice that your application outgrows this approach you +can fall back to a centralized URL mapping. + +The system that enables having a central URL map is the +:meth:`~flask.Flask.add_url_rule` function. Instead of using decorators, +you have a file that sets up the application with all URLs. + +Converting to Centralized URL Map +--------------------------------- + +Imagine the current application looks somewhat like this:: + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def index(): + pass + + @app.route('/user/<username>') + def user(username): + pass + +Then the centralized approach you would have one file with the views +(`views.py`) but without any decorator:: + + def index(): + pass + + def user(username): + pass + +And then a file that sets up an application which maps the functions to +URLs:: + + from flask import Flask + from yourapplication import views + app = Flask(__name__) + app.add_url_rule('/', view_func=views.index) + app.add_url_rule('/user/<username>', view_func=views.user) + +Loading Late +------------ + +So far we only split up the views and the routing, but the module is still +loaded upfront. The trick to actually load the view function as needed. +This can be accomplished with a helper class that behaves just like a +function but internally imports the real function on first use:: + + from werkzeug import import_string, cached_property + + class LazyView(object): + + def __init__(self, import_name): + self.__module__, self.__name__ = import_name.rsplit('.', 1) + self.import_name = import_name + + @cached_property + def view(self): + return import_string(self.import_name) + + def __call__(self, *args, **kwargs): + return self.view(*args, **kwargs) + +What's important here is is that `__module__` and `__name__` are properly +set. This is used by Flask internally to figure out how to name the +URL rules in case you don't provide a name for the rule yourself. + +Then you can define your central place to combine the views like this:: + + from flask import Flask + from yourapplication.helpers import LazyView + app = Flask(__name__) + app.add_url_rule('/', + view_func=LazyView('yourapplication.views.index')) + app.add_url_rule('/user/<username>', + view_func=LazyView('yourapplication.views.user')) + +You can further optimize this in terms of amount of keystrokes needed to +write this by having a function that calls into +:meth:`~flask.Flask.add_url_rule` by prefixing a string with the project +name and a dot, and by wrapping `view_func` in a `LazyView` as needed:: + + def url(url_rule, import_name, **options): + view = LazyView('yourapplication.' + import_name) + app.add_url_rule(url_rule, view_func=view, **options) + + url('/', 'views.index') + url('/user/<username>', 'views.user') + +One thing to keep in mind is that before and after request handlers have +to be in a file that is imported upfront to work properly on the first +request. The same goes for any kind of remaining decorator.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/mongokit.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,144 @@ +.. mongokit-pattern: + +MongoKit in Flask +================= + +Using a document database rather than a full DBMS gets more common these days. +This pattern shows how to use MongoKit, a document mapper library, to +integrate with MongoDB. + +This pattern requires a running MongoDB server and the MongoKit library +installed. + +There are two very common ways to use MongoKit. I will outline each of them +here: + + +Declarative +----------- + +The default behaviour of MongoKit is the declarative one that is based on +common ideas from Django or the SQLAlchemy declarative extension. + +Here an example `app.py` module for your application:: + + from flask import Flask + from mongokit import Connection, Document + + # configuration + MONGODB_HOST = 'localhost' + MONGODB_PORT = 27017 + + # create the little application object + app = Flask(__name__) + app.config.from_object(__name__) + + # connect to the database + connection = Connection(app.config['MONGODB_HOST'], + app.config['MONGODB_PORT']) + + +To define your models, just subclass the `Document` class that is imported +from MongoKit. If you've seen the SQLAlchemy pattern you may wonder why we do +not have a session and even do not define a `init_db` function here. On the +one hand, MongoKit does not have something like a session. This sometimes +makes it more to type but also makes it blazingly fast. On the other hand, +MongoDB is schemaless. This means you can modify the data structure from one +insert query to the next without any problem. MongoKit is just schemaless +too, but implements some validation to ensure data integrity. + +Here is an example document (put this also into `app.py`, e.g.):: + + def max_length(length): + def validate(value): + if len(value) <= length: + return True + raise Exception('%s must be at most %s characters long' % length) + return validate + + class User(Document): + structure = { + 'name': unicode, + 'email': unicode, + } + validators = { + 'name': max_length(50), + 'email': max_length(120) + } + use_dot_notation = True + def __repr__(self): + return '<User %r>' % (self.name) + + # register the User document with our current connection + connection.register([User]) + + +This example shows you how to define your schema (named structure), a +validator for the maximum character length and uses a special MongoKit feature +called `use_dot_notation`. Per default MongoKit behaves like a python +dictionary but with `use_dot_notation` set to `True` you can use your +documents like you use models in nearly any other ORM by using dots to +separate between attributes. + +You can insert entries into the database like this: + +>>> from yourapplication.database import connection +>>> from yourapplication.models import User +>>> collection = connection['test'].users +>>> user = collection.User() +>>> user['name'] = u'admin' +>>> user['email'] = u'admin@localhost' +>>> user.save() + +Note that MongoKit is kinda strict with used column types, you must not use a +common `str` type for either `name` or `email` but unicode. + +Querying is simple as well: + +>>> list(collection.User.find()) +[<User u'admin'>] +>>> collection.User.find_one({'name': u'admin'}) +<User u'admin'> + +.. _MongoKit: http://bytebucket.org/namlook/mongokit/ + + +PyMongo Compatibility Layer +--------------------------- + +If you just want to use PyMongo, you can do that with MongoKit as well. You +may use this process if you need the best performance to get. Note that this +example does not show how to couple it with Flask, see the above MongoKit code +for examples:: + + from MongoKit import Connection + + connection = Connection() + +To insert data you can use the `insert` method. We have to get a +collection first, this is somewhat the same as a table in the SQL world. + +>>> collection = connection['test'].users +>>> user = {'name': u'admin', 'email': u'admin@localhost'} +>>> collection.insert(user) + +print list(collection.find()) +print collection.find_one({'name': u'admin'}) + +MongoKit will automatically commit for us. + +To query your database, you use the collection directly: + +>>> list(collection.find()) +[{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'}] +>>> collection.find_one({'name': u'admin'}) +{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'} + +These results are also dict-like objects: + +>>> r = collection.find_one({'name': u'admin'}) +>>> r['email'] +u'admin@localhost' + +For more information about MongoKit, head over to the +`website <http://bytebucket.org/namlook/mongokit/>`_.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/packages.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,286 @@ +.. _larger-applications: + +Larger Applications +=================== + +For larger applications it's a good idea to use a package instead of a +module. That is quite simple. Imagine a small application looks like +this:: + + /yourapplication + /yourapplication.py + /static + /style.css + /templates + layout.html + index.html + login.html + ... + +Simple Packages +--------------- + +To convert that into a larger one, just create a new folder +`yourapplication` inside the existing one and move everything below it. +Then rename `yourapplication.py` to `__init__.py`. (Make sure to delete +all `.pyc` files first, otherwise things would most likely break) + +You should then end up with something like that:: + + /yourapplication + /yourapplication + /__init__.py + /static + /style.css + /templates + layout.html + index.html + login.html + ... + +But how do you run your application now? The naive ``python +yourapplication/__init__.py`` will not work. Let's just say that Python +does not want modules in packages to be the startup file. But that is not +a big problem, just add a new file called `runserver.py` next to the inner +`yourapplication` folder with the following contents:: + + from yourapplication import app + app.run(debug=True) + +What did we gain from this? Now we can restructure the application a bit +into multiple modules. The only thing you have to remember is the +following quick checklist: + +1. the `Flask` application object creation has to be in the + `__init__.py` file. That way each module can import it safely and the + `__name__` variable will resolve to the correct package. +2. all the view functions (the ones with a :meth:`~flask.Flask.route` + decorator on top) have to be imported when in the `__init__.py` file. + Not the object itself, but the module it is in. Do the importing at + the *bottom* of the file. + +Here's an example `__init__.py`:: + + from flask import Flask + app = Flask(__name__) + + import yourapplication.views + +And this is what `views.py` would look like:: + + from yourapplication import app + + @app.route('/') + def index(): + return 'Hello World!' + +You should then end up with something like that:: + + /yourapplication + /yourapplication + /__init__.py + /views.py + /static + /style.css + /templates + layout.html + index.html + login.html + ... + +.. admonition:: Circular Imports + + Every Python programmer hates them, and yet we just added some: + circular imports (That's when two modules depend on each other. In this + case `views.py` depends on `__init__.py`). Be advised that this is a + bad idea in general but here it is actually fine. The reason for this is + that we are not actually using the views in `__init__.py` and just + ensuring the module is imported and we are doing that at the bottom of + the file. + + There are still some problems with that approach but if you want to use + decorators there is no way around that. Check out the + :ref:`becomingbig` section for some inspiration how to deal with that. + + +.. _working-with-modules: + +Working with Modules +-------------------- + +For larger applications with more than a dozen views it makes sense to +split the views into modules. First let's look at the typical structure of +such an application:: + + /yourapplication + /yourapplication + /__init__.py + /views + __init__.py + admin.py + frontend.py + /static + /style.css + /templates + layout.html + index.html + login.html + ... + +The views are stored in the `yourapplication.views` package. Just make +sure to place an empty `__init__.py` file in there. Let's start with the +`admin.py` file in the view package. + +First we have to create a :class:`~flask.Module` object with the name of +the package. This works very similar to the :class:`~flask.Flask` object +you have already worked with, it just does not support all of the methods, +but most of them are the same. + +Long story short, here's a nice and concise example:: + + from flask import Module + + admin = Module(__name__) + + @admin.route('/') + def index(): + pass + + @admin.route('/login') + def login(): + pass + + @admin.route('/logout') + def logout(): + pass + +Do the same with the `frontend.py` and then make sure to register the +modules in the application (`__init__.py`) like this:: + + from flask import Flask + from yourapplication.views.admin import admin + from yourapplication.views.frontend import frontend + + app = Flask(__name__) + app.register_module(admin, url_prefix='/admin') + app.register_module(frontend) + +We register the modules with the app so that it can add them to the +URL map for our application. Note the prefix argument to the admin +module: by default when we register a module, that module's end-points +will be registered on `/` unless we specify this argument. + +So what is different when working with modules? It mainly affects URL +generation. Remember the :func:`~flask.url_for` function? When not +working with modules it accepts the name of the function as first +argument. This first argument is called the "endpoint". When you are +working with modules you can use the name of the function like you did +without, when generating modules from a function or template in the same +module. If you want to generate the URL to another module, prefix it with +the name of the module and a dot. + +Confused? Let's clear that up with some examples. Imagine you have a +method in one module (say `admin`) and you want to redirect to a +different module (say `frontend`). This would look like this:: + + @admin.route('/to_frontend') + def to_frontend(): + return redirect(url_for('frontend.index')) + + @frontend.route('/') + def index(): + return "I'm the frontend index" + +Now let's say we only want to redirect to a different function in the same +module. Then we can either use the full qualified endpoint name like we +did in the example above, or we just use the function name:: + + @frontend.route('/to_index') + def to_index(): + return redirect(url_for('index')) + + @frontend.route('/') + def index(): + return "I'm the index" + +.. _modules-and-resources: + +Modules and Resources +--------------------- + +.. versionadded:: 0.5 + +If a module is located inside an actual Python package it may contain +static files and templates. Imagine you have an application like this:: + + + /yourapplication + __init__.py + /apps + __init__.py + /frontend + __init__.py + views.py + /static + style.css + /templates + index.html + about.html + ... + /admin + __init__.py + views.py + /static + style.css + /templates + list_items.html + show_item.html + ... + +The static folders automatically become exposed as URLs. For example if +the `admin` module is exported with an URL prefix of ``/admin`` you can +access the style css from its static folder by going to +``/admin/static/style.css``. The URL endpoint for the static files of the +admin would be ``'admin.static'``, similar to how you refer to the regular +static folder of the whole application as ``'static'``. + +If you want to refer to the templates you just have to prefix it with the +name of the module. So for the admin it would be +``render_template('admin/list_items.html')`` and so on. It is not +possible to refer to templates without the prefixed module name. This is +explicit unlike URL rules. + +You also need to explicitly pass the ``url_prefix`` argument when +registering your modules this way:: + + # in yourapplication/__init__.py + from flask import Flask + from yourapplication.apps.admin.views import admin + from yourapplication.apps.frontend.views import frontend + + + app = Flask(__name__) + app.register_module(admin, url_prefix='/admin') + app.register_module(frontend, url_prefix='/frontend') + +This is because Flask cannot infer the prefix from the package names. + +.. admonition:: References to Static Folders + + Please keep in mind that if you are using unqualified endpoints by + default Flask will always assume the module's static folder, even if + there is no such folder. + + If you want to refer to the application's static folder, use a leading + dot:: + + # this refers to the application's static folder + url_for('.static', filename='static.css') + + # this refers to the current module's static folder + url_for('static', filename='static.css') + + This is the case for all endpoints, not just static folders, but for + static folders it's more common that you will stumble upon this because + most applications will have a static folder in the application and not + a specific module.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/sqlalchemy.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,216 @@ +.. _sqlalchemy-pattern: + +SQLAlchemy in Flask +=================== + +Many people prefer `SQLAlchemy`_ for database access. In this case it's +encouraged to use a package instead of a module for your flask application +and drop the models into a separate module (:ref:`larger-applications`). +While that is not necessary, it makes a lot of sense. + +There are four very common ways to use SQLAlchemy. I will outline each +of them here: + +Flask-SQLAlchemy Extension +-------------------------- + +Because SQLAlchemy is a common database abstraction layer and object +relational mapper that requires a little bit of configuration effort, +there is a Flask extension that handles that for you. This is recommended +if you want to get started quickly. + +You can download `Flask-SQLAlchemy`_ from `PyPI +<http://pypi.python.org/pypi/Flask-SQLAlchemy>`_. + +.. _Flask-SQLAlchemy: http://packages.python.org/Flask-SQLAlchemy/ + + +Declarative +----------- + +The declarative extension in SQLAlchemy is the most recent method of using +SQLAlchemy. It allows you to define tables and models in one go, similar +to how Django works. In addition to the following text I recommend the +official documentation on the `declarative`_ extension. + +Here the example `database.py` module for your application:: + + from sqlalchemy import create_engine + from sqlalchemy.orm import scoped_session, sessionmaker + from sqlalchemy.ext.declarative import declarative_base + + engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) + db_session = scoped_session(sessionmaker(autocommit=False, + autoflush=False, + bind=engine)) + Base = declarative_base() + Base.query = db_session.query_property() + + def init_db(): + # import all modules here that might define models so that + # they will be registered properly on the metadata. Otherwise + # you will have to import them first before calling init_db() + import yourapplication.models + Base.metadata.create_all(bind=engine) + +To define your models, just subclass the `Base` class that was created by +the code above. If you are wondering why we don't have to care about +threads here (like we did in the SQLite3 example above with the +:data:`~flask.g` object): that's because SQLAlchemy does that for us +already with the :class:`~sqlalchemy.orm.scoped_session`. + +To use SQLAlchemy in a declarative way with your application, you just +have to put the following code into your application module. Flask will +automatically remove database sessions at the end of the request for you:: + + from yourapplication.database import db_session + + @app.after_request + def shutdown_session(response): + db_session.remove() + return response + +Here is an example model (put this into `models.py`, e.g.):: + + from sqlalchemy import Column, Integer, String + from yourapplication.database import Base + + class User(Base): + __tablename__ = 'users' + id = Column(Integer, primary_key=True) + name = Column(String(50), unique=True) + email = Column(String(120), unique=True) + + def __init__(self, name=None, email=None): + self.name = name + self.email = email + + def __repr__(self): + return '<User %r>' % (self.name) + +To create the database you can use the `init_db` function: + +>>> from yourapplication.database import init_db +>>> init_db() + +You can insert entries into the database like this: + +>>> from yourapplication.database import db_session +>>> from yourapplication.models import User +>>> u = User('admin', 'admin@localhost') +>>> db_session.add(u) +>>> db_session.commit() + +Querying is simple as well: + +>>> User.query.all() +[<User u'admin'>] +>>> User.query.filter(User.name == 'admin').first() +<User u'admin'> + +.. _SQLAlchemy: http://www.sqlalchemy.org/ +.. _declarative: + http://www.sqlalchemy.org/docs/reference/ext/declarative.html + +Manual Object Relational Mapping +-------------------------------- + +Manual object relational mapping has a few upsides and a few downsides +versus the declarative approach from above. The main difference is that +you define tables and classes separately and map them together. It's more +flexible but a little more to type. In general it works like the +declarative approach, so make sure to also split up your application into +multiple modules in a package. + +Here is an example `database.py` module for your application:: + + from sqlalchemy import create_engine, MetaData + from sqlalchemy.orm import scoped_session, sessionmaker + + engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) + metadata = MetaData() + db_session = scoped_session(sessionmaker(autocommit=False, + autoflush=False, + bind=engine)) + def init_db(): + metadata.create_all(bind=engine) + +As for the declarative approach you need to close the session after +each request. Put this into your application module:: + + from yourapplication.database import db_session + + @app.after_request + def shutdown_session(response): + db_session.remove() + return response + +Here is an example table and model (put this into `models.py`):: + + from sqlalchemy import Table, Column, Integer, String + from sqlalchemy.orm import mapper + from yourapplication.database import metadata, db_session + + class User(object): + query = db_session.query_property() + + def __init__(self, name=None, email=None): + self.name = name + self.email = email + + def __repr__(self): + return '<User %r>' % (self.name, self.email) + + users = Table('users', metadata, + Column('id', Integer, primary_key=True), + Column('name', String(50), unique=True), + Column('email', String(120), unique=True) + ) + mapper(User, users) + +Querying and inserting works exactly the same as in the example above. + + +SQL Abstraction Layer +--------------------- + +If you just want to use the database system (and SQL) abstraction layer +you basically only need the engine:: + + from sqlalchemy import create_engine, MetaData + + engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) + metadata = MetaData(bind=engine) + +Then you can either declare the tables in your code like in the examples +above, or automatically load them:: + + users = Table('users', metadata, autoload=True) + +To insert data you can use the `insert` method. We have to get a +connection first so that we can use a transaction: + +>>> con = engine.connect() +>>> con.execute(users.insert(name='admin', email='admin@localhost')) + +SQLAlchemy will automatically commit for us. + +To query your database, you use the engine directly or use a connection: + +>>> users.select(users.c.id == 1).execute().first() +(1, u'admin', u'admin@localhost') + +These results are also dict-like tuples: + +>>> r = users.select(users.c.id == 1).execute().first() +>>> r['name'] +u'admin' + +You can also pass strings of SQL statements to the +:meth:`~sqlalchemy.engine.base.Connection.execute` method: + +>>> engine.execute('select * from users where id = :1', [1]).first() +(1, u'admin', u'admin@localhost') + +For more information about SQLAlchemy, head over to the +`website <http://sqlalchemy.org/>`_.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/sqlite3.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,87 @@ +.. _sqlite3: + +Using SQLite 3 with Flask +========================= + +In Flask you can implement the opening of database connections at the +beginning of the request and closing at the end with the +:meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request` +decorators in combination with the special :class:`~flask.g` object. + +So here is a simple example of how you can use SQLite 3 with Flask:: + + import sqlite3 + from flask import g + + DATABASE = '/path/to/database.db' + + def connect_db(): + return sqlite3.connect(DATABASE) + + @app.before_request + def before_request(): + g.db = connect_db() + + @app.after_request + def after_request(response): + g.db.close() + return response + +.. _easy-querying: + +Easy Querying +------------- + +Now in each request handling function you can access `g.db` to get the +current open database connection. To simplify working with SQLite, a +helper function can be useful:: + + def query_db(query, args=(), one=False): + cur = g.db.execute(query, args) + rv = [dict((cur.description[idx][0], value) + for idx, value in enumerate(row)) for row in cur.fetchall()] + return (rv[0] if rv else None) if one else rv + +This handy little function makes working with the database much more +pleasant than it is by just using the raw cursor and connection objects. + +Here is how you can use it:: + + for user in query_db('select * from users'): + print user['username'], 'has the id', user['user_id'] + +Or if you just want a single result:: + + user = query_db('select * from users where username = ?', + [the_username], one=True) + if user is None: + print 'No such user' + else: + print the_username, 'has the id', user['user_id'] + +To pass variable parts to the SQL statement, use a question mark in the +statement and pass in the arguments as a list. Never directly add them to +the SQL statement with string formatting because this makes it possible +to attack the application using `SQL Injections +<http://en.wikipedia.org/wiki/SQL_injection>`_. + +Initial Schemas +--------------- + +Relational databases need schemas, so applications often ship a +`schema.sql` file that creates the database. It's a good idea to provide +a function that creates the database based on that schema. This function +can do that for you:: + + from contextlib import closing + + def init_db(): + with closing(connect_db()) as db: + with app.open_resource('schema.sql') as f: + db.cursor().executescript(f.read()) + db.commit() + +You can then create such a database from the python shell: + +>>> from yourapplication import init_db +>>> init_db()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/templateinheritance.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,69 @@ +.. _template-inheritance: + +Template Inheritance +==================== + +The most powerful part of Jinja is template inheritance. Template inheritance +allows you to build a base "skeleton" template that contains all the common +elements of your site and defines **blocks** that child templates can override. + +Sounds complicated but is very basic. It's easiest to understand it by starting +with an example. + + +Base Template +------------- + +This template, which we'll call ``layout.html``, defines a simple HTML skeleton +document that you might use for a simple two-column page. It's the job of +"child" templates to fill the empty blocks with content: + +.. sourcecode:: html+jinja + + <!doctype html> + <html> + <head> + {% block head %} + <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> + <title>{% block title %}{% endblock %} - My Webpage</title> + {% endblock %} + </head> + <body> + <div id="content">{% block content %}{% endblock %}</div> + <div id="footer"> + {% block footer %} + © Copyright 2010 by <a href="http://domain.invalid/">you</a>. + {% endblock %} + </div> + </body> + +In this example, the ``{% block %}`` tags define four blocks that child templates +can fill in. All the `block` tag does is to tell the template engine that a +child template may override those portions of the template. + +Child Template +-------------- + +A child template might look like this: + +.. sourcecode:: html+jinja + + {% extends "layout.html" %} + {% block title %}Index{% endblock %} + {% block head %} + {{ super() }} + <style type="text/css"> + .important { color: #336699; } + </style> + {% endblock %} + {% block content %} + <h1>Index</h1> + <p class="important"> + Welcome on my awesome homepage. + {% endblock %} + +The ``{% extends %}`` tag is the key here. It tells the template engine that +this template "extends" another template. When the template system evaluates +this template, first it locates the parent. The extends tag must be the +first tag in the template. To render the contents of a block defined in +the parent template, use ``{{ super() }}``.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/viewdecorators.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,168 @@ +View Decorators +=============== + +Python has a really interesting feature called function decorators. This +allow some really neat things for web applications. Because each view in +Flask is a function decorators can be used to inject additional +functionality to one or more functions. The :meth:`~flask.Flask.route` +decorator is the one you probably used already. But there are use cases +for implementing your own decorator. For instance, imagine you have a +view that should only be used by people that are logged in to. If a user +goes to the site and is not logged in, he should be redirected to the +login page. This is a good example of a use case where a decorator is an +excellent solution. + +Login Required Decorator +------------------------ + +So let's implement such a decorator. A decorator is a function that +returns a function. Pretty simple actually. The only thing you have to +keep in mind when implementing something like this is to update the +`__name__`, `__module__` and some other attributes of a function. This is +often forgotten, but you don't have to do that by hand, there is a +function for that that is used like a decorator (:func:`functools.wraps`). + +This example assumes that the login page is called ``'login'`` and that +the current user is stored as `g.user` and `None` if there is no-one +logged in:: + + from functools import wraps + from flask import g, request, redirect, url_for + + def login_required(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if g.user is None: + return redirect(url_for('login', next=request.url)) + return f(*args, **kwargs) + return decorated_function + +So how would you use that decorator now? Apply it as innermost decorator +to a view function. When applying further decorators, always remember +that the :meth:`~flask.Flask.route` decorator is the outermost:: + + @app.route('/secret_page') + @login_required + def secret_page(): + pass + +Caching Decorator +----------------- + +Imagine you have a view function that does an expensive calculation and +because of that you would like to cache the generated results for a +certain amount of time. A decorator would be nice for that. We're +assuming you have set up a cache like mentioned in :ref:`caching-pattern`. + +Here an example cache function. It generates the cache key from a +specific prefix (actually a format string) and the current path of the +request. Notice that we are using a function that first creates the +decorator that then decorates the function. Sounds awful? Unfortunately +it is a little bit more complex, but the code should still be +straightforward to read. + +The decorated function will then work as follows + +1. get the unique cache key for the current request base on the current + path. +2. get the value for that key from the cache. If the cache returned + something we will return that value. +3. otherwise the original function is called and the return value is + stored in the cache for the timeout provided (by default 5 minutes). + +Here the code:: + + from functools import wraps + from flask import request + + def cached(timeout=5 * 60, key='view/%s'): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + cache_key = key % request.path + rv = cache.get(cache_key) + if rv is not None: + return rv + rv = f(*args, **kwargs) + cache.set(cache_key, rv, timeout=timeout) + return rv + return decorated_function + return decorator + +Notice that this assumes an instantiated `cache` object is available, see +:ref:`caching-pattern` for more information. + + +Templating Decorator +-------------------- + +A common pattern invented by the TurboGears guys a while back is a +templating decorator. The idea of that decorator is that you return a +dictionary with the values passed to the template from the view function +and the template is automatically rendered. With that, the following +three examples do exactly the same:: + + @app.route('/') + def index(): + return render_template('index.html', value=42) + + @app.route('/') + @templated('index.html') + def index(): + return dict(value=42) + + @app.route('/') + @templated() + def index(): + return dict(value=42) + +As you can see, if no template name is provided it will use the endpoint +of the URL map with dots converted to slashes + ``'.html'``. Otherwise +the provided template name is used. When the decorated function returns, +the dictionary returned is passed to the template rendering function. If +`None` is returned, an empty dictionary is assumed, if something else than +a dictionary is returned we return it from the function unchanged. That +way you can still use the redirect function or return simple strings. + +Here the code for that decorator:: + + from functools import wraps + from flask import request + + def templated(template=None): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + template_name = template + if template_name is None: + template_name = request.endpoint \ + .replace('.', '/') + '.html' + ctx = f(*args, **kwargs) + if ctx is None: + ctx = {} + elif not isinstance(ctx, dict): + return ctx + return render_template(template_name, **ctx) + return decorated_function + return decorator + + +Endpoint Decorator +------------------ + +When you want to use the werkzeug routing system for more flexibility you +need to map the endpoint as defined in the :class:`~werkzeug.routing.Rule` +to a view function. This is possible with this decorator. For example:: + + from flask import Flask + from werkzeug.routing import Rule + + app = Flask(__name__) + app.url_map.add(Rule('/', endpoint='index')) + + @app.endpoint('index') + def my_index(): + return "Hello world" + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/patterns/wtforms.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,124 @@ +Form Validation with WTForms +============================ + +When you have to work with form data submitted by a browser view code +quickly becomes very hard to read. There are libraries out there designed +to make this process easier to manage. One of them is `WTForms`_ which we +will handle here. If you find yourself in the situation of having many +forms, you might want to give it a try. + +When you are working with WTForms you have to define your forms as classes +first. I recommend breaking up the application into multiple modules +(:ref:`larger-applications`) for that and adding a separate module for the +forms. + +.. admonition:: Getting most of WTForms with an Extension + + The `Flask-WTF`_ extension expands on this pattern and adds a few + handful little helpers that make working with forms and Flask more + fun. You can get it from `PyPI + <http://pypi.python.org/pypi/Flask-WTF>`_. + +.. _Flask-WTF: http://packages.python.org/Flask-WTF/ + +The Forms +--------- + +This is an example form for a typical registration page:: + + from wtforms import Form, BooleanField, TextField, validators + + class RegistrationForm(Form): + username = TextField('Username', [validators.Length(min=4, max=25)]) + email = TextField('Email Address', [validators.Length(min=6, max=35)]) + password = PasswordField('New Password', [ + validators.Required(), + validators.EqualTo('confirm', message='Passwords must match') + ]) + confirm = PasswordField('Repeat Password') + accept_tos = BooleanField('I accept the TOS', [validators.Required()]) + +In the View +----------- + +In the view function, the usage of this form looks like this:: + + @app.route('/register', methods=['GET', 'POST']) + def register(): + form = RegistrationForm(request.form) + if request.method == 'POST' and form.validate(): + user = User(form.username.data, form.email.data, + form.password.data) + db_session.add(user) + flash('Thanks for registering') + return redirect(url_for('login')) + return render_template('register.html', form=form) + +Notice that we are implying that the view is using SQLAlchemy here +(:ref:`sqlalchemy-pattern`) but this is no requirement of course. Adapt +the code as necessary. + +Things to remember: + +1. create the form from the request :attr:`~flask.request.form` value if + the data is submitted via the HTTP `POST` method and + :attr:`~flask.request.args` if the data is submitted as `GET`. +2. to validate the data, call the :func:`~wtforms.form.Form.validate` + method which will return `True` if the data validates, `False` + otherwise. +3. to access individual values from the form, access `form.<NAME>.data`. + +Forms in Templates +------------------ + +Now to the template side. When you pass the form to the templates you can +easily render them there. Look at the following example template to see +how easy this is. WTForms does half the form generation for us already. +To make it even nicer, we can write a macro that renders a field with +label and a list of errors if there are any. + +Here's an example `_formhelpers.html` template with such a macro: + +.. sourcecode:: html+jinja + + {% macro render_field(field) %} + <dt>{{ field.label }} + <dd>{{ field(**kwargs)|safe }} + {% if field.errors %} + <ul class="errors"> + {% for error in field.errors %}<li>{{ error }}{% endfor %} + </ul> + {% endif %} + </dd> + {% endmacro %} + +This macro accepts a couple of keyword arguments that are forwarded to +WTForm's field function that renders the field for us. The keyword +arguments will be inserted as HTML attributes. So for example you can +call ``render_field(form.username, class='username')`` to add a class to +the input element. Note that WTForms returns standard Python unicode +strings, so we have to tell Jinja2 that this data is already HTML escaped +with the `|safe` filter. + +Here the `register.html` template for the function we used above which +takes advantage of the `_formhelpers.html` template: + +.. sourcecode:: html+jinja + + {% from "_formhelpers.html" import render_field %} + <form method="post" action="/register"> + <dl> + {{ render_field(form.username) }} + {{ render_field(form.email) }} + {{ render_field(form.password) }} + {{ render_field(form.confirm) }} + {{ render_field(form.accept_tos) }} + </dl> + <p><input type=submit value=Register> + </form> + +For more information about WTForms, head over to the `WTForms +website`_. + +.. _WTForms: http://wtforms.simplecodes.com/ +.. _WTForms website: http://wtforms.simplecodes.com/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bundled/flask/docs/quickstart.rst Mon Jul 18 13:22:12 2011 -0400 @@ -0,0 +1,745 @@ +.. _quickstart: + +Quickstart +========== + +Eager to get started? This page gives a good introduction in how to get +started with Flask. This assumes you already have Flask installed. If +you do not, head over to the :ref:`installation` section. + + +A Minimal Application +--------------------- + +A minimal Flask application looks something like that:: + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def hello_world(): + return "Hello World!" + + if __name__ == '__main__': + app.run() + +Just save it as `hello.py` or something similar and run it with your +Python interpreter. Make sure to not call your application `flask.py` +because this would conflict with Flask itself. + +:: + + $ python hello.py + * Running on http://127.0.0.1:5000/ + +Head over to `http://127.0.0.1:5000/ <http://127.0.0.1:5000/>`_, you should +see your hello world greeting. + +So what did that code do? + +1. First we imported the :class:`~flask.Flask` class. An instance of this + class will be our WSGI application. The first argument is the name of + the application's module. If you are using a single module (like here) + you should use `__name__` because depending on if it's started as + application or imported as module the name will be different + (``'__main__'`` versus the actual import name). For more information + on that, have a look at the :class:`~flask.Flask` documentation. +2. Next we create an instance of it. We pass it the name of the module / + package. This is needed so that Flask knows where it should look for + templates, static files and so on. +3. Then we use the :meth:`~flask.Flask.route` decorator to tell Flask + what URL should trigger our function. +4. The function then has a name which is also used to generate URLs to + that particular function, and returns the message we want to display in + the user's browser. +5. Finally we use the :meth:`~flask.Flask.run` function to run the + local server with our application. The ``if __name__ == '__main__':`` + makes sure the server only runs if the script is executed directly from + the Python interpreter and not used as imported module. + +To stop the server, hit control-C. + +.. _public-server: + +.. admonition:: Externally Visible Server + + If you run the server you will notice that the server is only available + from your own computer, not from any other in the network. This is the + default because in debugging mode a user of the application can execute + arbitrary Python code on your computer. If you have `debug` disabled + or trust the users on your network, you can make the server publicly + available. + + Just change the call of the :meth:`~flask.Flask.run` method to look + like this:: + + app.run(host='0.0.0.0') + + This tells your operating system to listen on a public IP. + + +Debug Mode +---------- + +The :meth:`~flask.Flask.run` method is nice to start a local +development server, but you would have to restart it manually after each +change you do to code. That is not very nice and Flask can do better. If +you enable the debug support the server will reload itself on code changes +and also provide you with a helpful debugger if things go wrong. + +There are two ways to enable debugging. Either set that flag on the +application object:: + + app.debug = True + app.run() + +Or pass it to run:: + + app.run(debug=True) + +Both will have exactly the same effect. + +.. admonition:: Attention + + Even though the interactive debugger does not work in forking environments + (which makes it nearly impossible to use on production servers), it still + allows the execution of arbitrary code. That makes it a major security + risk and therefore it **must never be used on production machines**. + +Screenshot of the debugger in action: + +.. image:: _static/debugger.png + :align: center + :class: screenshot + :alt: screenshot of debugger in action + + +Routing +------- + +Modern web applications have beautiful URLs. This helps people remember +the URLs which is especially handy for applications that are used from +mobile devices with slower network connections. If the user can directly +go to the desired page without having to hit the index page it is more +likely he will like the page and come back next time. + +As you have seen above, the :meth:`~flask.Flask.route` decorator is used +to bind a function to a URL. Here are some basic examples:: + + @app.route('/') + def index(): + return 'Index Page' + + @app.route('/hello') + def hello(): + return 'Hello World' + +But there is more to it! You can make certain parts of the URL dynamic +and attach multiple rules to a function. + +Variable Rules +`````````````` + +To add variable parts to a URL you can mark these special sections as +``<variable_name>``. Such a part is then passed as keyword argument to +your function. Optionally a converter can be specified by specifying a +rule with ``<converter:variable_name>``. Here are some nice examples:: + + @app.route('/user/<username>') + def show_user_profile(username): + # show the user profile for that user + pass + + @app.route('/post/<int:post_id>') + def show_post(post_id): + # show the post with the given id, the id is an integer + pass + +The following converters exist: + +=========== =========================================== +`int` accepts integers +`float` like `int` but for floating point values +`path` like the default but also accepts slashes +=========== =========================================== + +.. admonition:: Unique URLs / Redirection Behaviour + + Flask's URL rules are based on Werkzeug's routing module. The idea + behind that module is to ensure nice looking and also unique URLs based + on behaviour Apache and earlier servers coined. + + Take these two rules:: + + @app.route('/projects/') + def projects(): + pass + + @app.route('/about') + def about(): + pass + + They look rather similar, the difference is the trailing slash in the + URL *definition*. In the first case, the canonical URL for the + `projects` endpoint has a trailing slash. It's similar to a folder in + that sense. Accessing it without a trailing slash will cause Flask to + redirect to the canonical URL with the trailing slash. + + However in the second case the URL is defined without a slash so it + behaves similar to a file and accessing the URL with a trailing slash + will be a 404 error. + + Why is this? This allows relative URLs to continue working if users + access the page when they forget a trailing slash. This behaviour is + also consistent with how Apache and other servers work. Also, the URLs + will stay unique which helps search engines not indexing the same page + twice. + + +.. _url-building: + +URL Building +```````````` + +If it can match URLs, can it also generate them? Of course it can. To +build a URL to a specific function you can use the :func:`~flask.url_for` +function. It accepts the name of the function as first argument and a +number of keyword arguments, each corresponding to the variable part of +the URL rule. Unknown variable parts are appended to the URL as query +parameter. Here are some examples: + +>>> from flask import Flask, url_for +>>> app = Flask(__name__) +>>> @app.route('/') +... def index(): pass +... +>>> @app.route('/login') +... def login(): pass +... +>>> @app.route('/user/<username>') +... def profile(username): pass +... +>>> with app.test_request_context(): +... print url_for('index') +... print url_for('login') +... print url_for('login', next='/') +... print url_for('profile', username='John Doe') +... +/ +/login +/login?next=/ +/user/John%20Doe + +(This also uses the :meth:`~flask.Flask.test_request_context` method +explained below. It basically tells Flask to think we are handling a +request even though we are not, we are in an interactive Python shell. +Have a look at the explanation below. :ref:`context-locals`). + +Why would you want to build URLs instead of hardcoding them in your +templates? There are three good reasons for this: + +1. reversing is often more descriptive than hardcoding the URLs. Also and + more importantly you can change URLs in one go without having to change + the URLs all over the place. +2. URL building will handle escaping of special characters and Unicode + data transparently for you, you don't have to deal with that. +3. If your application is placed outside the URL root (so say in + ``/myapplication`` instead of ``/``), :func:`~flask.url_for` will + handle that properly for you. + + +HTTP Methods +```````````` + +HTTP (the protocol web applications are speaking) knows different methods +to access URLs. By default a route only answers to `GET` requests, but +that can be changed by providing the `methods` argument to the +:meth:`~flask.Flask.route` decorator. Here are some examples:: + + @app.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'POST': + do_the_login() + else: + show_the_login_form() + +If `GET` is present, `HEAD` will be added automatically for you. You +don't have to deal with that. It will also make sure that `HEAD` requests +are handled like the `HTTP RFC`_ (the document describing the HTTP +protocol) demands, so you can completely ignore that part of the HTTP +specification. Likewise as of Flask 0.6, `OPTIONS` is implemented for you +as well automatically. + +You have no idea what an HTTP method is? Worry not, here is a quick +introduction to HTTP methods and why they matter: + +The HTTP method (also often called "the verb") tells the server what the +clients wants to *do* with the requested page. The following methods are +very common: + +`GET` + The browser tells the server to just *get* the information stored on + that page and send it. This is probably the most common method. + +`HEAD` + The browser tells the server to get the information, but it is only + interested in the *headers*, not the content of the page. An + application is supposed to handle that as if a `GET` request was + received but to not deliver the actual content. In Flask you don't + have to deal with that at all, the underlying Werkzeug library handles + that for you. + +`POST` + The browser tells the server that it wants to *post* some new + information to that URL and that the server must ensure the data is + stored and only stored once. This is how HTML forms are usually + transmitting data to the server. + +`PUT` + Similar to `POST` but the server might trigger the store procedure + multiple times by overwriting the old values more than once. Now you + might be asking why is this useful, but there are some good reasons + to do it this way. Consider that the connection gets lost during + transmission: in this situation a system between the browser and the + server might receive the request safely a second time without breaking + things. With `POST` that would not be possible because it must only + be triggered once. + +`DELETE` + Remove the information at the given location. + +`OPTIONS` + Provides a quick way for a client to figure out which methods are + supported by this URL. Starting with Flask 0.6, this is implemented + for you automatically. + +Now the interesting part is that in HTML4 and XHTML1, the only methods a +form can submit to the server are `GET` and `POST`. But with JavaScript +and future HTML standards you can use the other methods as well. Furthermore +HTTP has become quite popular lately and browsers are no longer the only +clients that are using HTTP. For instance, many revision control system +use it. + +.. _HTTP RFC: http://www.ietf.org/rfc/rfc2068.txt + +Static Files +------------ + +Dynamic web applications need static files as well. That's usually where +the CSS and JavaScript files are coming from. Ideally your web server is +configured to serve them for you, but during development Flask can do that +as well. Just create a folder called `static` in your package or next to +your module and it will be available at `/static` on the application. + +To generate URLs to that part of the URL, use the special ``'static'`` URL +name:: + + url_for('static', filename='style.css') + +The file has to be stored on the filesystem as ``static/style.css``. + +Rendering Templates +------------------- + +Generating HTML from within Python is not fun, and actually pretty +cumbersome because you have to do the HTML escaping on your own to keep +the application secure. Because of that Flask configures the `Jinja2 +<http://jinja.pocoo.org/2/>`_ template engine for you automatically. + +To render a template you can use the :func:`~flask.render_template` +method. All you have to do is to provide the name of the template and the +variables you want to pass to the template engine as keyword arguments. +Here's a simple example of how to render a template:: + + from flask import render_template + + @app.route('/hello/') + @app.route('/hello/<name>') + def hello(name=None): + return render_template('hello.html', name=name) + +Flask will look for templates in the `templates` folder. So if your +application is a module, that folder is next to that module, if it's a +package it's actually inside your package: + +**Case 1**: a module:: + + /application.py + /templates + /hello.html + +**Case 2**: a package:: + + /application + /__init__.py + /templates + /hello.html + +For templates you can use the full power of Jinja2 templates. Head over +to the :ref:`templating` section of the documentation or the official +`Jinja2 Template Documentation +<http://jinja.pocoo.org/2/documentation/templates>`_ for more information. + +Here is an example template: + +.. sourcecode:: html+jinja + + <!doctype html> + <title>Hello from Flask</title> + {% if name %} + <h1>Hello {{ name }}!</h1> + {% else %} + <h1>Hello World!</h1> + {% endif %} + +Inside templates you also have access to the :class:`~flask.request`, +:class:`~flask.session` and :class:`~flask.g` [#]_ objects +as well as the :func:`~flask.get_flashed_messages` function. + +Templates are especially useful if inheritance is used. If you want to +know how that works, head over to the :ref:`template-inheritance` pattern +documentation. Basically template inheritance makes it possible to keep +certain elements on each page (like header, navigation and footer). + +Automatic escaping is enabled, so if name contains HTML it will be escaped +automatically. If you can trust a variable and you know that it will be +safe HTML (because for example it came from a module that converts wiki +markup to HTML) you can mark it as safe by using the +:class:`~jinja2.Markup` class or by using the ``|safe`` filter in the +template. Head over to the Jinja 2 documentation for more examples. + +Here is a basic introduction to how the :class:`~jinja2.Markup` class works: + +>>> from flask import Markup +>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' +Markup(u'<strong>Hello <blink>hacker</blink>!</strong>') +>>> Markup.escape('<blink>hacker</blink>') +Markup(u'<blink>hacker</blink>') +>>> Markup('<em>Marked up</em> » HTML').striptags() +u'Marked up \xbb HTML' + +.. versionchanged:: 0.5 + + Autoescaping is no longer enabled for all templates. The following + extensions for templates trigger autoescaping: ``.html``, ``.htm``, + ``.xml``, ``.xhtml``. Templates loaded from a string will have + autoescaping disabled. + +.. [#] Unsure what that :class:`~flask.g` object is? It's something in which + you can store information for your own needs, check the documentation of + that object (:class:`~flask.g`) and the :ref:`sqlite3` for more + information. + + +Accessing Request Data +---------------------- + +For web applications it's crucial to react to the data a client sent to +the server. In Flask this information is provided by the global +:class:`~flask.request` object. If you have some experience with Python +you might be wondering how that object can be global and how Flask +manages to still be threadsafe. The answer are context locals: + + +.. _context-locals: + +Context Locals +`````````````` + +.. admonition:: Insider Information + + If you want to understand how that works and how you can implement + tests with context locals, read this section, otherwise just skip it. + +Certain objects in Flask are global objects, but not of the usual kind. +These objects are actually proxies to objects that are local to a specific +context. What a mouthful. But that is actually quite easy to understand. + +Imagine the context being the handling thread. A request comes in and the +webserver decides to spawn a new thread (or something else, the +underlying object is capable of dealing with other concurrency systems +than threads as well). When Flask starts its internal request handling it +figures out that the current thread is the active context and binds the +current application and the WSGI environments to that context (thread). +It does that in an intelligent way that one application can invoke another