TODO: documentation
===================
Miscelaneous notes abotu things to be documented.

Unordered list of topics to be documented
-----------------------------------------
- routing

  - common regular expressions examples

- sessions

  - basic usage & configuration
  - using multiple sessions in the same request
  - using different backends
  - using flashes
  - updating session arguments (max_age etc)
  - purging db sessions

- i18n (increment existing tutorial)

  - basic usage & configuration
  - loading locale/timezone automatically for each request
  - formatting date/time/datetime
  - formatting currency
  - using i18n in templates

- jinja2 & mako

  - basic usage & configuration
  - setting global filters and variables (using config or factory)

- auth

  - basic usage & configuration
  - setting up 'own auth'
  - making user available automatically on each request
  - purging tokens

- config

  - configuration conventions ("namespaced" configuration for webapp2_extras
    modules)

- tricks

  - configuration in a separate file
  - routes in a separate file
  - reduce verbosity when defining routes (R = webapp2.Route)

Common errors
-------------
- "TypeError: 'unicode' object is not callable": one possible reason is that
  the ``RequestHandler`` returned a string. If the handler returns anything, it
  **must** be a :class:`webapp2.Response` object. Or it must not return
  anything and write to the response instead using ``self.response.write()``.

Secret keys
-----------
Add a note about how to generate strong session secret keys::

    $ openssl genrsa -out ${PWD}/private_rsa_key.pem 2048

Jinja2 factory
--------------
To create Jinja2 with custom filters and global variables::

    from webapp2_extras import jinja2

    def jinja2_factory(app):
        j = jinja2.Jinja2(app)
        j.environment.filters.update({
            'my_filter': my_filter,
        })
        j.environment.globals.update({
            'my_global': my_global,
        })
        return j

    # When you need jinja, get it passing the factory.
    j = jinja2.get_jinja2(factory=jinja2_factory)

Debugging Jinja2
----------------
http://stackoverflow.com/questions/3086091/debug-jinja2-in-google-app-engine/3694434#3694434

Configuration notes
-------------------
Notice that configuration is set primarily in the application. See:

    http://webapp-improved.appspot.com/guide/app.html#config

By convention, modules that are configurable in webapp2 use the module
name as key, to avoid name clashes. Their configuration is then set in
a nested dict. So, e.g., i18n, jinja2 and sessions are configured like this::

    config = {}
    config['webapp2_extras.i18n'] = {
        'default_locale': ...,
    }
    config['webapp2_extras.jinja2'] = {
        'template_path': ...,
    }
    config['webapp2_extras.sessions'] = {
        'secret_key': ...,
    }
    app = webapp2.WSGIApplication(..., config=config)

You only need to set the configuration keys that differ from the default
ones. For convenience, configurable modules have a 'default_config'
variable just for the purpose of documenting the default values, e.g.:

    http://webapp-improved.appspot.com/api/extras.i18n.html#webapp2_extras.i18n.default_config

Cookies, quoting & unicode
--------------------------
http://groups.google.com/group/webapp2/msg/985092351378c43e
http://stackoverflow.com/questions/6839922/unicodedecodeerror-is-raised-when-getting-a-cookie-in-google-app-engine

Marketplace integration
-----------------------

.. code-block:: xml

   <?xml version="1.0" encoding="UTF-8" ?>
   <ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">
     <!-- Name and description pulled from message bundles -->
     <Name>Tipfy</Name>
     <Description>A simple application for testing the marketplace.</Description>

     <!-- Support info to show in the marketplace & control panel -->
     <Support>
       <!-- URL for application setup as an optional redirect during the install -->
       <Link rel="setup" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/setup" />

       <!-- URL for application configuration, accessed from the app settings page in the control panel -->
       <Link rel="manage" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/manage" />

       <!-- URL explaining how customers get support. -->
       <Link rel="support" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/support" />

       <!-- URL that is displayed to admins during the deletion process, to specify policies such as data retention, how to claim accounts, etc. -->
       <Link rel="deletion-policy" href="https://app-id.appspot.com/a/${DOMAIN_NAME}/deletion-policy" />
     </Support>

     <!-- Show this link in Google's universal navigation for all users -->
     <Extension id="navLink" type="link">
       <Name>Tipfy</Name>
       <Url>https://app-id.appspot.com/a/${DOMAIN_NAME}/</Url>
       <!-- This app also uses the Calendar API -->
       <Scope ref="Users"/>
       <!--
       <Scope ref="Groups"/>
       <Scope ref="Nicknames"/>
       -->
     </Extension>

     <!-- Declare our OpenID realm so our app is white listed -->
     <Extension id="realm" type="openIdRealm">
       <Url>https://app-id.appspot.com</Url>
     </Extension>

     <!-- Special access to APIs -->
     <Scope id="Users">
       <Url>https://apps-apis.google.com/a/feeds/user/#readonly</Url>
       <Reason>Users can be selected to gain special permissions to access or modify content.</Reason>
     </Scope>
     <!--
       <Scope id="Groups">
       <Url>https://apps-apis.google.com/a/feeds/group/#readonly</Url>
       <Reason></Reason>
     </Scope>
     <Scope id="Nicknames">
       <Url>https://apps-apis.google.com/a/feeds/nickname/#readonly</Url>
       <Reason></Reason>
     </Scope>
     -->
   </ApplicationManifest>