[
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.egg-info\n*.egg\ntests/test_units/cache/\ntests/test_units/session/\n"
  },
  {
    "path": ".hgignore",
    "content": "\n# Automatically generated by `hgimportsvn`\nsyntax:glob\n*.DS_Store\n.svn\n.coverage\n*.pyc\n*.egg-info\n*.egg\nez_setup\npylons/docs/*/_build\ncontainer_file\ncontainer_dbm*\n*~\nbuild/\ndist/\ndocs/html/docs\noutput/ProjectName\ntests/html_coverage\nsyntax: glob\n"
  },
  {
    "path": ".hgtags",
    "content": "b7002f68d541940f32fa5d5fecb83483008fd489 v0.9.6\n88112f696d4aba81405753713ca06070a92ebcf9 v0.9.5\n1bc21f0b2820a39801278b322aab939da893ed4d v0.9.4.1\na8e89fafa6d836c5ec9de712db4afd68acd02b30 v0.9.4\n896da05e4c2679f39756194d65c3e87eb92bc2f1 v0.9.3\na71e37726e2909c358a6fb699f26a314643d1c89 v0.9.2\n37614170faa944723382bf885023085bc3ece616 v0.9.1\nf650ccf099785af6be11d3e91f66e4dc5178dc1b v0.9\n0da35cd7624a67c43948c00f60b35eb9202e2b8d v0.8.2\n0fa5a7b12de0795c95a425e89d802f09e8e709ab v0.8.1\n1880858f1fb30fbf4b1717ac49d172712dfc5b9d v0.8\n9e6916dca073e83deb25ed401a928e834bc0d262 v0.9.6rc2\nf2b68bd9f177d08f8caf7e5d33629190d097fbc0 v0.9.6rc1\nf04d465aa10861b96c1050a4c6347c4aa12247c1 v0.9.6rc3\na7749485525a8aade8dbe089abae9a539af24682 v0.9.7beta1\n46c5edc17b643e07158dc4c6b5e14a7d839fe066 v0.9.7beta1\n9cb761f0f0476dad15b370765919ae96a968fea4 v0.9.7beta2\n3819db8d2307f8f5725b2a27c6a34e8f5738d687 v0.9.7beta3\ne546c53613c2c0647ab94ee0d376a5bc8e28dcb4 v0.9.7beta5\nca3cbefec25e0e9ec7b579123cf97ed98934ccd8 v0.9.7rc1\na6f56791a83a53db7a7484fb8bd8821ffba740c4 v0.9.7rc2\n7ceef102aff2cce44634132d21638358b4129197 v0.9.7rc3\n4a94734906711e56f9d34a34527f4b8a6e9811a8 v0.9.7rc4\nfa5aad0d57deb99f8a25596e9c7d601b1ced1d5d v0.9.7rc5\ne7a19deba3f66b4e6dfc050f070295a0a622308a v0.9.7rc6\n2154554f4ffb458555023afd6e810ce88e58e64b v0.9.7\n165565778a3c518d6b5c383095fffdf6e154fa78 v0.10b1\n25eb46de0380e20799c419557a86c61f144101a2 v1.0b1\ncd08f0df626b89f3e6ee9df71539e009d9be1ba9 v0.10rc1\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: python\npython:\n  - \"2.6\"\n  - \"2.7\"\ninstall:\n  - python setup.py develop\nscript:\n  - python setup.py test\n"
  },
  {
    "path": "CHANGELOG",
    "content": "Pylons Changelog\n================\n\n1.0.2 (July 21, 2015)\n* In the event of a NilAccept for the language, request.languages() would\n  throw an AttributeError exception. Fixes #24.\n* Encode Location HTTP header in redirect responses in UTF-8. Per\n  RFC 3987. Refers to #15.\n* Remove \"Post Traceback\" as it was a possible XSS vector with prior versions\n  of WebError, and the PylonsHQ site is no longer in existence to support them.\n\n1.0.1 (August 13th, 2012)\n* No changes since RC1.\n\n1.0.1RC1 (December 12, 2011)\n* WARNING: pylons.lib.decorators has had two functions removed:\n  ``determine_response_charset`` and ``encode_formencode_errors``.\n* Updated dependencies to latest versions of Paste, PasteDeploy, and\n  compatibility for the latest WebOb 1.2 betas.\n* authenticate_form allows for GET. Patch by Domen Kožar.\n* jsonify now properly sets charset to utf-8.\n* Add ability for jsonify to handle objects with a __json__ attribute using\n  custom JSONEncoder class similar to TG2. Patch by Bob Farrell.\n* Added ability for __before__ to reference a callable function. Patch\n  contributed by mverdone.\n* Pulled in JSON-RPC support from agentultra's pylons fork.\n* Apply patch for proper pylons.__version__ under Windows. Contributed by\n  Christoph Zwerschke.\n* Utilize MarkupSafe for faster HTML escaping.\n* Fix signed cookies by using standard base64 alphabet, and prevent timing\n  attacks on signature comparison.\n* Added setup of app_globals and config to Pylons config.init_app to ensure\n  as long as the Pylons application is loaded, the app_globals and config\n  will be appropriately initialized.\n* Documentation updates.\n\n1.0 (May 27, 2010)\n* Minor tweak to allow proper importing of pylons.\n\n1.0RC1 (March 1, 2010)\n* Switched to using Routes 1.12 with support for no longer using the odd\n  routes singleton.\n* Removed pylons.middleware.StaticJavascripts, this is not used anymore.\n* Added more unit tests.\n\n1.0b1 (February 5, 2010)\n* Removed CacheMiddleware. cache object is now setup as an attribute on the\n  app_globals object for use where needed.\n* WARNING: config only supports dict access\n* WARNING: Method arguments no longer assigned to 'tmpl_context' by default.\n* WARNING: Changed default to strict_tmpl_context.\n* WARNING: Removed legacy pylons.c and pylons.g globals.\n* WARNING: Removed legacy pylons.database module.\n* WARNING: Removed legacy pylons.config module.\n* WARNING: Removed Buffet options, setup, and legacy render/render_response\n  function from pylons.templating. This also means config no longer accepts\n  the add_template_engine option.\n* WARNING: Removed legacy redirect_to function.\n* WARNING: @https decorator no longer accepts url_for-like arguments.\n* Add a \"paster routes\" command.  This prints the mapper, which from Routes\n  1.12 onwards gives sensibly formatted output.\n* Fix unit tests on Windows\n* Prepare for Routes 1.12, ensure tests don't assume implicit routing\n\n0.10 (May 27, 2010)\n* Fix legacy warning replacement.\n\n0.10RC1 (March 1, 2010)\n* No changes to Pylons core since b1.\n\n0.10b1 (February 5, 2010)\n* redirect_to is now deprecated, use redirect(url(*args, **kwargs)) instead.\n* url_for like args to the https decorator are now deprecated, pass it a url\n  or a callable returning a url instead.\n* Changed 1.0 deprecated pylons.c, pylons.g, pylons.buffet instances to\n  throw deprecation warnings.\n* Fixed etag_cache matching when the If-None-Match header contains a comma\n  separated list of etags. Fixes #557. Thanks magicbronson.\n* Added tests for restcontroller with sub-directory, and fixed generated unit\n  tests. Patches supplied by Michael van Tellingen, fixes #571.\n* Retain the original controller exception when thrown under\n  environ['pylons.controller.exception'] for use in the error controller.\n* Fixed bug with unit tests running the app load twice during testing.\n  Fixes #620.\n* Updated project templates to use actual config instance, rather than the\n  StackedObjectProxy classes.\n* Changed PylonsConfig to be dict subclass, rather than DispatchingConfig\n  subclass.\n\n\n0.9.7 (February 23, 2009)\n* WARNING: A new option is available to determine whether or not an actions\n  arguments should be automatically attached to 'c'. To turn off this implicit\n  behavior in environment.py:\n    config['pylons.c_attach_args'] = False\n  This is set to True by default.\n* WARNING: Fixed a minor security hole in the default Pylons error page that\n  could result in an XSS security hole.\n* WARNING: Fixed a security hole in the default project template to use the\n  StaticURLParser to ensure arbitrary files can't be sent.\n* WARNING: Refactored PylonsApp to remove legacy PylonsApp, moved\n  session/cache and routes middleware into the project template. This will\n  require projects to be updated to include those 3 middleware in the projects\n  middleware.py.\n* Added redirect, preferred over redirect_to. Takes an explicit url instead of\n  url_for like arguments\n* Changed to using WebTest instead of paste.fixture for app testing.\n* Added render_mako_def to render def blocks within a mako template.\n* Changes to cache_decorator and cached_template to support Beaker API\n  changes in version 1.1.  1.0.3 is still supported.\n* Fix HEAD requests causing an Exception as if no content was returned\n  by the controller. Fixes #507. Thanks mvtellingen, Petr Kobalicek.\n* Fix a crash when returning the result of ``etag_cache`` in a controller.\n  Fixes #508.\n* \"response\" flag has been removed from pylons.decorators.cache.beaker_cache,\n  as it sends all headers along unconditionally including cookies;\n  additionally, the flag was taking effect in all cases previously\n  so prior versions of beaker_cache are not secure.\n\n  In its place, a new option \"cache_headers\" is provided, which is a\n  tuple of specific header names to be cached.  It defaults\n  to ('content-type','content-length').\n* \"invalidate_on_startup\" flag added to beaker_cache, which provides a\n  \"starttime\" to the cache such that when the application is started\n  or restarted, the cache entry is invalidated.\n* Updating host to use 127.0.0.1 for development binding.\n* Added option to specify the controller name with a __controller__ variable\n  in the controller's module. This name will be used for the controller class\n  rather than the default naming scheme.\n* setup.py egg_info now restores projects' paster_plugins.txt,\n  allowing paster shell to work again after the egg-info directory was\n  lost. fixes #282. Thanks sevkin.\n* The paste_deploy_config.ini_tmpl template is now located at\n  package/config/deployment.ini_tmpl for new projects.\n* Project's default test fixtures no longer hardcode test.ini; the ini\n  file used can now be specified via the nosetests --with-pylons\n  argument (defaults to test.ini in setup.cfg). fixes #400.\n* @validate now defaults to translating FormEncode error messages via\n  Pylons' gettext catalog, then falls back to FormEncode's. fixes #296.\n  Thanks Max Ischenko.\n* Fixed SQLAlchemy logging not working in paster shell. Fixes #363. Thanks\n  Christoph Haas.\n* Added optionally engine initialization, to prevent Buffet from loading\n  if there's no 'buffet.template_engines' in the config.\n* Updated minimal template to work with Tempita and other new templating\n  changes.\n* Fixed websetup to parse location config file properly when the section\n  isn't 'main'. Fixes #399.\n* Added default Mako filter of escape for all template rendering.\n* Fixed template for Session.remove inclusion when using SA. Fixed\n  render_genshi to properly use fragment/format options. Thanks Antonin\n  Enfrun.\n* Remove template engine from load_environment call.\n* Removing template controller from projects. Fixes #383.\n* Added signed_cookie method to WebOb Request/Response sub-classes.\n* Updated project template to setup appropriate template loader and controller\n  template to doc how to import render.\n* Added documentation for render functions in pylons.templating.\n* Adding specific render functions that don't require Buffet.\n* Added forward controller.util function for forwarding the request to WSGI\n  apps. Fixes #355.\n* Added default input encoding for Mako to utf-8. Suggested in #348.\n* Fixed paster controller to raise an error if the controller for it already\n  exists. Fixes #279.\n* Added __init__.py to template dir in project template if the template engine\n  is genshi or kid. Fixes #353.\n* Fixed jsonify to use application/json as its the proper mime-type and now\n  used all over the net.\n* Fixed minimal template not replacing variables properly. Fixes #377.\n* Fixed @validate decorator to no longer catch exceptions should they be\n  raised in the action that is supposed to display a form. Fixes #374.\n* Fixed paster shell command to no longer search for egg_info dir. Allows\n  usage of paster shell with installed packages. Suggested by Gavin Carothers.\n* Added mimetype function and MIMETypes class for registering mimetypes.\n* WARNING: Usage of pylons.Response is now deprecated. Please use\n  pylons.response instead.\n* Removed use of WSGIRequest/WSGIResponse and replaced with WebOb subclasses\n  that implement methods to make it backwards compatible with the Paste\n  wsgiwrappers.\n* Fixed missing import in template controller.\n* Deprecated function uses string substitution to avoid Nonetype error when\n  Python optimization is on. Fixes #334.\n* E-tag cache no longer returns Content-Type in the headers. Fixes #323.\n* XMLRPCController now properly includes the Content-Length of the response.\n  Fixes #310, thanks Nicholas.\n* Added SQLAlchemy option to template, which adds SQLAlchemy setup to the\n  project template.\n* Switched project templating to use Tempita.\n* Updated abort/redirect_to to use appropriate Response object when WebOb is\n  used.\n* Updated so that 404's properly return as Response objects when WebOb is in\n  use instead of WSGIResponse.\n* Added beaker_cache option to avoid caching/restoring global Response values\n  that were present during the first cache operation.\n* Adding StatusCodeRedirect to handle internal redirects based on the status\n  code returned by the app. This replaces the use of ErrorDocuments in\n  projects.\n* Refactored error exceptions to use WebError.\n* WSGIController now uses the environ references to response, request, and\n  the c object for higher performance.\n* Added optional use of WebOb instead of paste.wsgiwrapper objects.\n* Fixed bug with beaker_cache defaulting to dbm rather than the beaker\n  cache app-wide default.\n* The --with-pylons nose plugin no longer requires a project to have been\n  registered with setuptools to work.\n* The config object is now included in the template namespace.\n* StaticJavascripts now accepts keyword arguments for StaticURLParser.\n  Suggested by Marcin Kasperski.\n* Fix pylons.database.AutoConnectHub's doInTransaction not automatically\n  connecting when necessary. Fixes #327.\n\n0.9.6.1 (September 27th, 2007)\n* Fixed validate decorator to resume pre-0.9.6 behavior of only validating\n  POST requests by default. Added option to validate during GET as well and\n  a recursion avoidance check to prevent validate from running more than once.\n* WARNING: Fixed a security hole allowing private controller methods (those\n  beginning with an underscore) to be accessed from the outside. Found by\n  Tomasz Nazar.\n* Added nose plugin '--with-pylons=test.ini' option to load the Pylons app\n  before scanning for unit tests. This enables Pylons apps to be unit tested\n  with doc tests.\n* PylonsBaseWSGIApp now caches controller lookup and the effective logging\n  level for a little better performance.\n\n0.9.6 (September 8th, 2007)\n* Updated requirements for newer WebHelpers for SQLAlchemy 0.4 compatibility.\n  Fixes #300.\n* Fixed pylons.templating to not pull session objects if there are none in use\n  for the request. Thanks Bob Ippolito.\n* Catch UnicodeEncodeErrors when finding the Controller action method and fail\n  gracefully. Thanks max. Fixes #298.\n* Allow passing of a state keyword to the validate decorator for the\n  to_python methods. Fixes #297.\n* paster shell now configures logging from the config file, like paster serve\n  and setup-app. This can be disabled via the -q option. Thanks Yannick\n  Gingras.\n\n0.9.6rc3 (August 18, 2007)\n* Fixed controllers.core to allow responses of None (empty bodies). Logs a\n  message indicating the response was empty.\n* pylons.helpers has been moved to pylons.controllers.util, to differentiate\n  between controller utility functions and projects' helpers modules.\n* Fixed non-basestring/generator/WSGIResponse objects returned from\n  Controllers not being set as the response content. Thanks Alex Conrad.\n* development.ini now configures the app's Logger level to DEBUG by default.\n  Thanks Christoph Haas\n\n0.9.6rc2 (August 2, 2007)\n* Projects now include a MANIFEST.in file: it directs distutils to recursively\n  include all files in the project's public/ and templates/ dir. This fixes\n  these dirs not being included in dists unless they were checked into an RCS\n  recognized by setuptools. This is at the expense of dists now globbing all\n  files in those dirs (even those not checked into your RCS). Thanks Christoph\n  Haas.\n* Fixed the validate decorator not setting c.form_errors in certain\n  circumstances. Thanks max. Fixes #286.\n* email_to lines commented out in development.ini and test.ini files to avoid\n  emails being sent to a non-existent address by mistake. If an error occurs\n  it is logged but no email is sent unless email_to is specified.\n* [paste.app_factory] entry points changed to point to the actual make_app()\n  function to make it simpler for someone to work out how Pylons works (tests\n  updated accordingly too).\n* All use of the ez_setup module is now tested by an ImportError to make\n  Pylons compatible with Buildout. Note: Tags and releases should be made\n  using an svn export and an svn add to ensure a real copy of the ez_setup\n  module is included and not just an svn:external so that the module is tied\n  to time of the release.\n* More full-featured README.txt included.\n* Updated beaker_cache to cache global response cookies/status/headers.\n  Fixes #280.\n* Fixed missing abort name import in restrict rest decorator. Fixes #281.\n* Added cheetah as a supported template language for template_engine option.\n* Fixed public/ and templates/ directories not being created with paster\n  create.\n\n0.9.6rc1 (July 15, 2007)\n* Fixed cookie header addition to use add instead of append. Thanks to\n  anonymous patcher. Fixes #268, again.\n* Added ability to pass _code option to specify the status code type for\n  redirect_to.\n* Fixed redirect_to to not copy all headers into redirect for old _response\n  usage. Fixes #268.\n* WARNING: By default, the Pylons request object now returns unicode\n  parameter (pylons.GET/POST/params) values (and assumes those parameters\n  were sent to Pylons as utf-8). Unicode parameters can cause major\n  problems if your application is not setup to handle unicode. To disable\n  unicode parameters (0.9.5 default behavior), add the following to your\n  load_environment function (0.9.6 syntax):\n\n  config['request_options']['charset'] = None\n\n  or, if still using the deprecated pre-0.9.6 pylons.config syntax, add:\n\n  request_settings = pylons.config.request_defaults.copy()\n  request_settings['charset'] = None\n  return pylons.config.Config(tmpl_options, map, paths,\n                              request_settings=request_settings)\n\n* WARNING: Template names beginning with a / (or the OS's path separator)\n  will now result in the name not having the separator's replaced with '.'s\n  for the template engine. This shouldn't affect most projects as they usually\n  assume a dot notation will be used with dot notation template engines (Kid,\n  Genshi, etc.). This change allows template engines that can take filename\n  paths to function properly. Fixes #233.\n* WARNING: The pylons.util.get_prefix(environ) function is deprecated. Please\n  use:\n      environ.get('SCRIPT_NAME', '')\n  instead (the get_prefix function is used in the default ErrorController).\n  Fixes #243.\n* WARNING: The paths dictionary's 'root_path' has moved to the less\n  redundant 'root'.\n* Fixed the Error Documents/EvalException css referencing non-existent images.\n  Thanks Shannon -jj Behrens. Fixes #238.\n* Added ability to pass _code option to specify the status code type for\n  redirect_to.\n* Fixed redirect_to to not copy all headers into redirect for old _response\n  usage. Fixes #268.\n* Added logging statements throughout Pylons code, added logging setup to\n  default template. Fixes #98.\n* Refactored global response to be setup in wsgiapp along with the other\n  globals. Updated WSGIController to copy in global response headers and\n  cookies into a WSGI app's output.\n* Added global pylons.response object. Thanks Shannon -jj Behrens and Damjan\n  Georgievski. Fixes #268 and #201.\n* Updated default project template files for new configuration layout. Options\n  to handle config now just in environment.py, and middleware.py handling just\n  middleware. Fixes #203.\n* Removing mako tests, as its now the default. Default test changed from\n  Myghty to Mako.\n* Changing default templating to mako.\n* Added the https decorator. It requires an action to be loaded via\n  https. Patch by ido. Fixes #241.\n* Added upgrade instructions, and posted a copy on the wiki. Fixes #230.\n* Added deprecation warnings for usage of the Pylons Controller class, all\n  controllers should inherit from WSGIController instead. Fixes #239.\n* Removed deprecated attach_locals function from Controller class.\n* Added an authenticate_form decorator for use with WebHelpers'\n  secure_form_tag functions for preventing CSRF attacks. Original patch\n  by David Turner. Fixes #157.\n* Fix Buffet's include_pylons_variables not being upheld. Thanks Jonathan\n  LaCour.\n* The validate decorator now accepts extra keyword arguments (**htmlfill_kwargs)\n  to pass along to formencode's htmlfill.render function.\n* Removed POST-only restriction on validate decorator, now handles GET\n  requests. No form arg required during a GET request, which will run the\n  current action with c.form_errors set to the errors. Fixes #246.\n* Added PylonsConfig, which gets accessed as pylons.config dict. Contains\n  all the merged ini options, in addition to the Config options such as\n  'routes.map', 'pylons.paths', 'buffet.template_options', etc. Check the\n  pylons.config docs on PylonsConfig for dict keys populated by it.\n* Split up resolution stages in wsgiapp, so that controller lookup is a\n  separate function making it easier to subclass. PylonsApp now takes a\n  base_wsgi_app argument which is then used for the BaseWSGIApp instead of the\n  one from wsgiapp.py.\n* Added mako template render tests.\n* Added storage of the action func used to handle a call, for later code that\n  might need a reference to the action that originally handled the request.\n  Fixes #253.\n* Updated config object to optionally take a single merged conf dict, updated\n  project templates to pass around the single merged conf dict.\n* Changed project template to use new Beaker session keys.\n* Changed default routing for raw template matching to not unicode decode the\n  route argument. Fixes #242.\n* Catch any exceptions raised by template engine entry points and emit a\n  warning instead of crashing. Thanks markbradley. Fixes #249\n* Fixed the validate decorator not working with formencode's\n  CompoundValidators when variable_decode=False. Fixes #209.\n* Fixed the validate decorator failing with a KeyError when no value is\n  specified to validate against for separate validators (as opposed to a\n  schema). Reported by Graham Stratton.\n* Fixed paster shell not merging app_conf and global_conf into the main CONFIG\n  dict namespace. Original patch by David Smith. Fixes #244.\n* Added logging to decorators. Refs #98.\n* Fixed paster restcontroller to test for lib.base and only add that import\n  statement when its present. This fixes the restcontroller template when used\n  with minimal Pylons project templates. Fixes #237.\n* Fixed the EvalException debugger showing broken links and buttons when the\n  app's ErrorController was broken (such as when BaseController's __before__\n  raises an exception). Suggested by Ian Bicking. Fixes #228.\n* paster create now accepts a 'template_engine' option to setup the new\n  project's default template engine. E.g. to create a new project that\n  uses Genshi by default, use:\n  paster create --template=pylons mygenshiproj template_engine=genshi\n  Suggested by Ian Bicking. Fixes #141.\n* Fixed the validate decorator triggering the following error with\n  FormEncode>=0.7 and non-ascii rendered form content:\n  UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 10:\n  ordinal not in range(128) the form was passed in as an encoded string, but\n  some data or error messages were unicode strings; the form should be passed\n  in as a unicode string\n  Reported by Christoph Haas.\n* HTTPExceptions are now converted to Response objects (for __after__),\n  making the httpexceptions middleware no longer required.\n* Added Warning to jsonify to warn about cross-site attacks when returning\n  a list as the outer-most element to jsonify. Fixes #232.\n* Fixed beaker_cache decorator to take optional keyword arguments intended\n  for the backend cache container (such as url for memcached).\n* Fixed paster controller assuming the minimal template was in use when\n  the lib.base module existed but raised an exception.\n* Fixed bug in XMLRPC Controller not setting proper Content-Type. Fixes #236.\n* Added the '-d' ('--disable-ipython') option to paster shell for\n  disabling IPython.\n* Allow creation of controllers named 'setup' via paster controller.\n  Reported by Matt Good.\n* Added support for generic arguments to SQLAlchemy's create_engine of\n  the form sqlalchemy.* from the PasteDeploy config file.\n\n0.9.5 (Apr 11th, 2007)\n* Fixed a Python 2.3 incompatibility with paster shell, causing the\n  Exception:\n  File \"Pylons-0.9.5-py2.3.egg/pylons/commands.py\", line 357, in command\n    locs.update([(name, getattr(base, name)) for name in base_public])\n  AttributeError: keys\n* Fixed paster shell breaking for projects where the base package was not\n  the first package listed in top_level.txt. Patch from Alberto Valverde.\n  Fixes #229.\n* Fixed doc references to config['app_conf']. Fixes #116.\n* Changed `get_engine_conf` to properly evaluate sqlalchemy echo statement\n  when its 'debug'. Fixes #226.\n* make_session and create_engine now accept keyword arguments to pass to\n  SQLAlchemy's create_engine.\n* make_session now accepts the keyword argument 'session_kwargs' to pass\n  to SQLAlchemy's create_session.\n* Fixed _inspect_call to call function with keyword arguments instead of list\n  args. Corrects issue with action defaults that caused the value for the\n  latter args to be in the wrong spots. Spotted by Topher. Fixes #223.\n* Added the allow_none option (passed to xmlrpc.dumps) to XMLRPCController.\n  Suggested by Jaroslaw Zabiello.\n* Updated XMLRPC Controller with patch for name lookup and additional unit\n  tests for the patch. Fixes #216.\n* Updated docs for validate decorator to more clearly illustrate what the\n  post_only args apply to. Fixes #221.\n* Added ability to return strings in the WSGIController. Fixes #218.\n* Added lazy i18n translation functions. Patch from David Smith. Fixes #181.\n* Added fix for XMLRPCController system.methodHelp function and unit test.\n  Patch and unit test submitted by Graham Higgins.\n* Fixed bug in validate decorator with new UnicodeMultiDict response content\n  not properly retaining form content as unicode for formencode's htmlfill.\n* Fixed bug in XMLRPC Controller with xmlrpclib Faults not being properly\n  transformed into a WSGI response within the controller.\n* WARNING: Pylons now requires the decorator module: it no longer packages\n  it as pylons.decorator. Code relying on the pylons.decorator.decorator\n  function will trigger a deprecation warning and should be changed to use\n  decorator.decorator.\n* WARNING: pylons.h was deprecated for using projects' lib.helpers module\n  directly in 0.9.3. pylons.h is now formally deprecated (emits\n  DeprecationWarnings). Projects still accessing pylons.h must change the\n  following import:\n      from pylons import h\n  to:\n      import MYPROJ.lib.helpers as h\n* pylons.jsonify and pylons.Controller references have been deprecated\n  (they are misplaced references). They continue to be available at\n  pylons.decorators.jsonify and pylons.controllers.Controller, as they always\n  have been.\n* Updated templating Buffet to recognize format parameter and properly pass it\n  to the template engine.\n* Updated LICENSE for new year and to indicate license covering templates\n  generated. Fixes #188.\n* Interactive debugger now supports Mako. After r1780 if you are using a\n  custom theme you will need to change '%(myghty_data)s' to\n  '%(template_data)s' in your template. If you are using JavaScript the tab\n  id is now \"template_data\".\n* Fixed bug in WSGIController with private function attempts not returning a\n  valid WSGI response.\n* Added full unit test coverage of cache decorator.\n* Adding messages binary file, enabling i18n unit tests. Updating pylons.i18n\n  to import LanguageError. Fixes #193.\n* Adding i18n tests, not active yet as they're waiting on a binary file from a\n  patch. Refs #193.\n* Updated tests so that they now work with nose, removing py.test requirement.\n* Switching config setup to load keys into main config dict with app_conf and\n  global_conf keys set for any code looking for those keys. Fixes #116.\n* PylonsInstaller is now the default paste.app_install entry point for new\n  projects: this makes Cheetah no longer required for the paster make-config\n  command. (Thanks Alexander Schremmer, Ian Bicking)\n* Added custom redirect_to function in pylons.helpers that will take an\n  optional _response arg to pull headers and cookies out for preservation\n  during a redirect. Fixes #136.\n* Changed config.Config.__init__ to take all options as keyword args so\n  unused args can be skipped. Fixes #162.\n* The request object can now automatically decode GET/POST/params vars to\n  unicode, when its charset attribute is set.\n* Added a new request_settings keyword arg to Config's constructor. Allows\n  setting the default charset and errors values of of the request object.\n* Deprecated Config constructor's default_charset keyword arg. Use Config's\n  response_settings keyword arg instead.\n* Fixed paster controller to test for lib.base and only add that import\n  statement when its present. This fixes the controller template when used with\n  minimal Pylons project templates. Fixes #140 and fixes #139.\n* Fixed the paster shell error: KeyError: 'pylons.routes_dict' when calling\n  app.get and app.post.\n* Fixed paster shell not working on projects with names containing hyphens.\n* Fixed the config directive 'sqlalchemy.echo' set to False being interpreted\n  as True. Patch by Alex Conrad.\n* Fixed paster shell not restoring CONFIG['global_conf'].\n\n0.9.4.1 (Jan. 5th, 2007)\n* Added restcontroller command that generates a RESTful controller template\n  and provides the appropriate map.resource command to add. Suggested by\n  Matthew Scott.\n* Fixed SQLObject pylons.database.PackageHub error:\n  exceptions.NameError: global name 'CONFIG' is not defined\n* Fixed pylons.database.session_context not working outside of requests\n  (such as in websetup.py).\n* Updated template options config to take template options for multiple\n  engines for less binding to Myghty.\n* Fixed paster shell incorrectly importing the the tuple (model,) as the\n  model object.\n\n0.9.4 (Dec. 29th, 2006)\n* WARNING: Removed the lang_extract and lang_compile commands. They used\n  pygettext.py and its associated msgfmt.py, which lacked the ability to\n  extract ngettext style function calls and had issues with unicode strings.\n  The new I18NToolBox project aims to provide this functionality (and more)\n  via the gettext command line utilities. http://i18ntoolbox.ufsoft.org\n* All Pylons special objects are now available within paster shell (not just\n  h and g).\n* WARNING: Myghty's allow_globals config var has changed, causing the\n  following when running pre-compiled templates:\n      Error(TypeError): do_run_component() takes exactly 13 non-keyword\n      arguments (5 given)\n  Delete the compiled Myghty templates directory (specified by cache_dir or\n  myghty_data_dir in the config file) to resolve the error.\n* Changed i18n functions in templates to use proxy objects so that using\n  set_lang in a template works right. Fixes #153.\n* Now allowing any template plugin to overwrite global PYLONS_VARS (such as c,\n  g), not just pylonsmyghty.\n* Adding SQLAlchemy support to the database.py file. Saves the session engine\n  to g to maintain it during the apps lifetime. Uses SessionContext plugin for\n  management of the current session.\n* Updated config object so that init_app can take an optional template engine\n  argument to declare the default template engine.\n* Updated Myghty plugin to use extra_vars_func when passed in.\n* Fixed Buffet to use extra_vars_func properly.\n* Fixed the validate decorator when there are validation errors and\n  variable_decode=True: now passing the original params to htmlfill.render\n  instead of the varable_decode'd version. Patch by FlimFlamMan.\n* Added ungettext function for use with pluralized i18n, and the N_ function\n  (gettext_noop) to mark global strings for translation. Added ungettext, N_\n  and translator objects to be globals for templates. Refs #126.\n* WARNING: The localization function '_' now uses ugettext (returns unicode\n  strings) instead of gettext. To preserve the old behavior, append the\n  following line to your project's lib.base and lib.helpers imports:\n  from pylons.helpers import gettext as _\n* Pylons special objects are now available within the interactive debugger\n  (deprecating _attach_locals).\n* Added setup-app run before unit tests run so that webapp has proper setup\n  tasks handled. Fixes #113.\n* Added paste.deploy.CONFIG setup to middleware.py, websetup.py and testing\n  files in the Pylons project templates. Closes #112.\n* Added security policy doc to index for use as Pylons security policy.\n  Closes #91.\n* Improved the repr() of the c context object to show attributes.\n* Set environ['paste.testing_variables'] whenever that key is available, not\n  just in testing mode.\n* Added capability to have an action be a generator function.\n* Added introspection capability to XMLRPCController and signature checking.\n* Updated Controller to use additional arg lookup scheme so that the source of\n  the function args for _inspect_call can be easily overridden.\n* Updated RPCController, renamed to XMLRPCController. XMLRPCController now\n  functions properly and will automatically return proper xmlrpc responses.\n* Added test configuration ini file to default template. Closes #114.\n* Fixed problem with pylons.database.PackageHub.__get__ raising errors\n  other than AttributeError when the database isn't configured.  Added\n  new UnconfiguredConnectionError exception, instead of just KeyError\n  or TypeError (depending on what part of the configuration failed).\n* Fixed default g init, since bare object has no init method. Reported by Ian\n  Bicking.\n* Fixed issue with SQLObject method override having wrong name. Reported by\n  climbus with patch. Fixes #133.\n* Moved log function to pylons.helpers and translation functions to\n  pylons.i18n. using pylons.util purely for Pylons internal util functions.\n* WARNING: Removed 0.8.x legacy code and backwards compatibility functions.\n* PylonsApp now has option to not use Routes middleware, default resolving\n  uses new wsgi.org routing_args spec.\n* Refactored routes dispatching to use new Routes middleware.\n* Fixed paster shell command to properly acquire mapper object without\n  relying on the template being configured in a specific manner.\n* Added keyword argument pool_connection to\n  pylons.database.PackageHub; if set to false then SQLObject connections\n  won't use pooled database connections (a new connection will be\n  opened for each request).\n\n0.9.3 (Nov 1st, 2006)\n* Updated project template to support full_stack option to make it easier to\n  use Pylons apps within larger WSGI stacks.\n* Added deprecation warnings to legacy objects and for 1.0 functionality that\n  will change.\n* Added cache decorator and Cheetah template functional tests. Patch and unit\n  tests provided by Climbus.\n* Fixed readline support in the stock interactive console paster shell.\n  Reported by Alex Conrad.\n* A controller's __after__ method will now be called after actions invoke\n  redirect_to (or raise any HTTPException). Reported by David Turner.\n* Fixed config to use myghty_data_dir instead of cache_dir setting if its\n  set as well. Reported by Shannon -jj Behrens.\n* Added traceback hiding so that more of the traceback relating to Pylons code\n  is removed from the default traceback making it easier to focus on the code\n  in an app that actually caused the problem. Closes #119.\n* Added ability to use '_' translation method directly from templates and in\n  the controller without having to use it under h._.\n* Added 's' and 'l' Myghty escaping flags to default project templates.\n  Suggested by Jamie Wilkinson. Closes #110.\n* Fixed SCGI bug with QUERY_STRING test when WSGI states it doesn't have to\n  exist. Reported by Riklaunim.\n* Added pylons_minimal template, prone to fine-tuning.\n* Added option for PylonsApp to take a globals object to avoid checking a\n  hardcoded path for a Globals object.\n* Removed old Helpers legacy object entirely, replaced pylons.h with proper\n  StackedObjectProxy. Cleaned up PylonsApp and PylonsBaseApp to accept a\n  helpers reference so that Pylons can be ignorant of where the helpers came\n  from.\n* Fixed bug with lang app_conf option being set improperly. Reported\n  by Laurent.\n* Fixed pylons.h to work proper with new and old-style helper imports.\n* Fixed render functions always passing disable_unicode=False to Myghty.\n\n0.9.2 (Sept. 7th, 2006)\n* Fixed problem with dashes in controller names, resolves #107.\n* Updated default ini file to use localhost from address. Refs #104.\n* Updated default development.ini to use a single cache_dir setting which\n  is the base dir that cache files, session files, and template caching will\n  be saved in. Config object now looks to cache_dir setting properly for\n  Myghty templates. Fixes #104.\n* Updated default template controller to provide better example of directly\n  serving Myghty templates.\n* Fixed legacy (0.8) controller methods' **ARGS (also m.request_args and\n  pylons.params) to be of the expected mixed dictionary instead of MultiDict.\n* Fixed _attach_locals not attaching g and cache objects.\n* Added g object to the shell. Works as long as the Pylons app can respond\n  to a path of '/'. The pylons.g variable will also be setup properly for\n  use in the shell.\n* Myghty template options are now passed properly to the template creation, and\n  allow_globals now works to add Myghty template globals.\n* Re-organized helpers, switched Helpers class to use static methods to reduce\n  code duplication.\n* Helpers cleanup:\n    - Old-style Helper object uses StackedObjectProxy just like the new\n      scheme, thus avoiding possible WSGI stack issues.\n    - New project templates use new-style Helpers scheme.\n    - Updated wsgiapp to utilize new Helpers cleanup style. The 'h' object\n      is now friendlier to use, and maps directly to a projects lib.helpers\n      file. No more wacky Helpers object proxying to it.\n    - Added translator global to __init__.py for use with new Helpers cleanup.\n    - Copied Helpers function methods directly into util so they can be used\n      stand-alone.\n    - Deprecated h.lang (for h.set_lang/h.get_lang)\n* Moved the 'default_charset' option from PylonsApp's constructor to\n  Config's.\n* Added 'error' controller route to the top of the Pylons template to avoid\n  the common issue people discover when removing the generic default route.\n* Changing validate decorator to have variable_decode option, which will\n  also run formencode's variable_decode function over the form input.\n* Switched to using Context obj classes instead of RequestLocal which is\n  being phased out.\n* Added an 'encode_variables' option to the validate decorator.\n* Switched all current_obj calls to _current_obj to avoid triggering\n  deprecation warnings.\n* Added is_xhr to Request object in Paste.\n* Bumping up dependency to latest Paste.\n* Switching back to prior controller import check, throwing a more detailed\n  error with a suggest fix should the user really want a URL with that name\n  in it. (refs #67)\n* Fixes bug with prior fix for #67. Wasn't properly testing the full package\n  name to include the current project which would incorrectly restrict\n  valid controller names (refs #67).\n* Fixed '_method_' checking to test in a more efficient manner.\n* Added deprecation warning for legacy mode activation. Not necessary to\n  update multiple files, as all of legacy mode is enabled via the Legacy\n  WSGI app. Fixes #89.\n* Fixed controller command to check controller name and refuse to create\n  controllers that have name clashes with existing modules that could be\n  imported. Reported (with patch) by Chuck Adams. Fixes #67.\n* Added capability for 'c' object to throw an exception when an attribute\n  is used that doesn't exist. Closes #84.\n* Fix for endless error document call when an error document controller\n  wants to throw a error that the error_mapper catches.\n\n0.9.1 (August 11th, 2006)\n* Fixed __all__ export typo in templating.py. Added example of render\n  with a template.\n* Fixed issue with set_lang not using proper CONFIG var.\n* Minor tweaks to update docs in pylons.helpers and move remaining legacy\n  code into legacy module. Updated wsgiapp to refer to new locations of\n  legacy compatibility objects.\n* The interactive debugger's 'full traceback' link is now only displayed\n  when the full traceback differs from the regular (includes hidden\n  frames).\n* Providing an optional text version of exception tracebacks and the\n  associated extra data within the interactive debugger.\n* The 'Debug at: http://hostname/_debug/view/XXXXX' URLs now display the\n  interactive debugger properly skinned.\n* Fixed issue in PasteScript with new controller sub-directories lacking a\n  __init__.py file. This fixes an import error when using the controller.\n  PasteScript dependency updated to fixed version. Reported by Artur Lew.\n* Removed lowercasing of the module name during resolver import.\n* Removed [full] recommendation from docs.\n\n0.9 (July 28th, 2006)\n* config file option 'debug' now defaults to false when undefined\n* Removed the components directory from the template\n* Updated paste.errordocuments support\n* Fix for multi-word controller names such that front_page /\n  FrontPageController can be used as a controller name. Patch contributed\n  by Timo Mihaljov.\n* Cleaned up imports in wsgiapp and new project to better reflect where\n  things really come from.\n* Removed unnecessary myghty usage from wsgiapp for url unescaping, now\n  uses urllib as the myghty function did.\n* Removing 'response' to import, sticking with Response as its more\n  consistent with the fact that Response is a class/factory and not an\n  instance like request, and the other lower-case objects.\n* Added redirect_to under pylons.helpers, and added import from helpers\n  directly into lib/base.py for use in controllers.\n* Consolidated legacy objects into legacy module.\n* Adding abort method that raises the appropriate exception for the status\n  code.\n* Removing form_fill, obsolete by the validate decorator.\n* Relocated 'params' object to only take effect in legacy mode.\n* Updated Pylons template to use WSGIController as the new default Controller.\n* Altered the wsgi dispatch to examine the controller, and instantiate it if\n  it's just a class. Otherwise, if the controller is a subclass of Controller\n  but not of WSGIController, it assumes its an older Controller class that\n  may return a WSGIResponse, and calls it appropriately.\n* Dispatch now fixes up environ to move 'path_info' Route var into the WSGI\n  PATH_INFO, and the rest is pushed into SCRIPT_NAME. This is for use with\n  other WSGI apps under controller mount points.\n* Added WSGIController which takes a normal WSGI interface call and returns\n  the appropriate WSGI response.\n* Added automatic copying of Route variables declared in an action's\n  function definition to the 'c' object.\n* WebHelpers' .js files are now automatically published under the\n  '/javascripts/' URL path. Individual WebHelpers' .js files can be\n  overridden by other .js files inside the project's 'public/javascripts'\n  directory\n* Added exception toss when a template engine doesn't exist.\n* Added alias option to Buffet to support aliasing more template engines\n  to other engine names\n* Buffet enhancements to support caching of any template with any template\n  engine\n* All render commands processed through Buffet\n* Backwards compatibility 'm' object for use with legacy projects\n* Added use of Beaker middleware for session and caching functionality\n* Fixed error traceback and updated template to use proper error images and\n  stylesheets.\n\n0.8.2 (**dev**)\n* Fixed default controller to allow for actions with - in them. The - will be\n  replaced with an underscore, while the original action name in the mapper\n  dict is unchanged. Patch by Thomas Sidwick.\n\n0.8.1 (May 10th, 2006)\n* Added REST decorators and re-arranged decorator layout to support more styles\n  of decorators for future expansion.\n* Fixed dependency requirement bug that had Pylons locked to simplejson 1.1\n  even though a newer version was out.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2005-2015 Ben Bangert, James Gardner, Philip Jenvey\n                        and contributors.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the author or contributors may not be used to endorse or\n   promote products derived from this software without specific prior\n   written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n\n\n-------------------------------------------------------------------------------\nALL TEMPLATES GENERATED ARE COVERED UNDER THE FOLLOWING LICENSE:\n\nCopyright (c) 2005-2015 Ben Bangert, James Gardner, Philip Jenvey\n                        and contributors.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following condition is\nmet:\n   The name of the author or contributors may not be used to endorse or\n   promote products derived from this software without specific prior\n   written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "recursive-include pylons/templates *\nrecursive-include pylons/media *\nrecursive-include tests *\nrecursive-include test_files *\ninclude CHANGELOG\ninclude LICENSE\ninclude UPGRADING\nrecursive-exclude tests/test_units/session *\nglobal-exclude .DS_Store *.hgignore *.hgtags\n"
  },
  {
    "path": "README.rst",
    "content": "Pylons\n++++++\n\n.. image:: https://secure.travis-ci.org/Pylons/pylons.png?branch=master\n   :alt: Build Status\n   :target: https://secure.travis-ci.org/Pylons/pylons\n\nPylons is a rapid web application development framework.\n\n.. note::\n\n    Pylons has merged with repoze.bfg, and is now in maintenance-only\n    mode. It's highly recommended that new projects start with the new\n    merged web framework, `pyramid <http://www.pylonsproject.org/>`_.\n\nInstall\n=======\n\n`Read the online Installation instructions\n<http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/gettingstarted.html#installing>`_.\n\nIf you want to install from source you can run the following command:\n\n.. code-block :: bash\n\n    $ python setup.py install\n\nThis will display a message and download setuptools if the module is not\nalready installed. It will then install Pylons and all its dependencies. You\nmay need root privileges to install setuptools.\n\nTesting\n=======\n\nTo test the source distribution run the following command:\n\n.. code-block :: bash\n\n    $ python setup.py test\n\nThis will install additional dependencies needed for the tests. As above, you\nmay need root privileges.\n\nDocumentation\n=============\n\n`Read the complete Pylons web framework documentation\n<http://docs.pylonsproject.org/projects/pylons-webframework/>`_.\n\n`Definitive Guide to Pylons <https://thejimmyg.github.io/pylonsbook/>`_ is a book about Pylons published by Apress, written by James Gardner, with free HTML rendering.\n\nGenerating documentation requires Sphinx:\n\n.. code-block :: bash\n\n    $ easy_install Sphinx\n\nThen to build the documentation use the commands:\n\n.. code-block :: bash\n\n    $ cd pylons/docs/<lang>\n    $ make html\n"
  },
  {
    "path": "UPGRADING",
    "content": "Upgrading your Pylons Project\n=============================\n\nPylons projects should be updated using the paster command create. In addition\nto creating new projects, paster create when run over an existing project will\nprovide several ways to update the project template to the latest version. \n\nUsing this tool properly can make upgrading a fairly minor task. For the \npurpose of this document, the project being upgraded will be called 'demoapp'\nand all commands will use that name.\n\nRunning paster create to upgrade\n--------------------------------\n\nYou'll first need to cd to the directory *above* your projects main directory.\nThe main directory is the one that contains your setup.py, setup.cfg, and\ndevelopment.ini files.\n\n.. code:: bash\n    /home/joe/demoapp $ cd ..\n    /home/joe $\n\nThen run paster create on the project directory:\n\n.. code:: bash\n    /home/joe $ paster create demoapp -t pylons\n\npaster will prompt you on how to handle conflicts and updates to the existing\nproject files. The options let you (hit the key in the parens to perform the\noperation):\n\n(d)iff them, and show you the changes between your projects file and the one\n   that has changed in Pylons\n(b)ackup the file, and copy the new version into its place. The old one will \n   end in .bak\n(y)es to overwrite the existing file with the new one. *Not recommended* since\n   you will then have no way to see your existing one, unless you have seen\n   the diff first and know there is no changes you're losing.\n(n)o to overwrite, and just keep your existing file. Also safe if you know \n   that nothing has changed.\n\nIt's recommended when upgrading your project that you always look at the diff\nfirst to see whats changed. Then either overwrite your existing one if you are\nnot going to lose changes you want, or backup yours and write the new one in.\nYou can then manually compare and add your changes back in.\n"
  },
  {
    "path": "ez_setup.py",
    "content": "#!python\n\"\"\"Bootstrap setuptools installation\n\nIf you want to use setuptools in your package's setup.py, just include this\nfile in the same directory with it, and add this to the top of your setup.py::\n\n    from ez_setup import use_setuptools\n    use_setuptools()\n\nIf you want to require a specific version of setuptools, set a download\nmirror, or use an alternate download directory, you can do so by supplying\nthe appropriate options to ``use_setuptools()``.\n\nThis file can also be run as a script to install or upgrade setuptools.\n\"\"\"\nimport sys\nDEFAULT_VERSION = \"0.6c9\"\nDEFAULT_URL     = \"http://pypi.python.org/packages/%s/s/setuptools/\" % sys.version[:3]\n\nmd5_data = {\n    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',\n    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',\n    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',\n    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',\n    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',\n    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',\n    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',\n    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',\n    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',\n    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',\n    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',\n    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',\n    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',\n    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',\n    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',\n    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',\n    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',\n    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',\n    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',\n    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',\n    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',\n    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',\n    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',\n    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',\n    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',\n    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',\n    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',\n    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',\n    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',\n    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',\n    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',\n    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',\n    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',\n    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',\n}\n\nimport sys, os\ntry: from hashlib import md5\nexcept ImportError: from md5 import md5\n\ndef _validate_md5(egg_name, data):\n    if egg_name in md5_data:\n        digest = md5(data).hexdigest()\n        if digest != md5_data[egg_name]:\n            print >>sys.stderr, (\n                \"md5 validation of %s failed!  (Possible download problem?)\"\n                % egg_name\n            )\n            sys.exit(2)\n    return data\n\ndef use_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    download_delay=15\n):\n    \"\"\"Automatically find/download setuptools and make it available on sys.path\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end with\n    a '/').  `to_dir` is the directory where setuptools will be downloaded, if\n    it is not already available.  If `download_delay` is specified, it should\n    be the number of seconds that will be paused before initiating a download,\n    should one be required.  If an older version of setuptools is installed,\n    this routine will print a message to ``sys.stderr`` and raise SystemExit in\n    an attempt to abort the calling script.\n    \"\"\"\n    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules\n    def do_download():\n        egg = download_setuptools(version, download_base, to_dir, download_delay)\n        sys.path.insert(0, egg)\n        import setuptools; setuptools.bootstrap_install_from = egg\n    try:\n        import pkg_resources\n    except ImportError:\n        return do_download()       \n    try:\n        pkg_resources.require(\"setuptools>=\"+version); return\n    except pkg_resources.VersionConflict, e:\n        if was_imported:\n            print >>sys.stderr, (\n            \"The required version of setuptools (>=%s) is not available, and\\n\"\n            \"can't be installed while this script is running. Please install\\n\"\n            \" a more recent version first, using 'easy_install -U setuptools'.\"\n            \"\\n\\n(Currently using %r)\"\n            ) % (version, e.args[0])\n            sys.exit(2)\n        else:\n            del pkg_resources, sys.modules['pkg_resources']    # reload ok\n            return do_download()\n    except pkg_resources.DistributionNotFound:\n        return do_download()\n\ndef download_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    delay = 15\n):\n    \"\"\"Download setuptools from a specified location and return its filename\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end\n    with a '/'). `to_dir` is the directory where the egg will be downloaded.\n    `delay` is the number of seconds to pause before an actual download attempt.\n    \"\"\"\n    import urllib2, shutil\n    egg_name = \"setuptools-%s-py%s.egg\" % (version,sys.version[:3])\n    url = download_base + egg_name\n    saveto = os.path.join(to_dir, egg_name)\n    src = dst = None\n    if not os.path.exists(saveto):  # Avoid repeated downloads\n        try:\n            from distutils import log\n            if delay:\n                log.warn(\"\"\"\n---------------------------------------------------------------------------\nThis script requires setuptools version %s to run (even to display\nhelp).  I will attempt to download it for you (from\n%s), but\nyou may need to enable firewall access for this script first.\nI will start the download in %d seconds.\n\n(Note: if this machine does not have network access, please obtain the file\n\n   %s\n\nand place it in this directory before rerunning this script.)\n---------------------------------------------------------------------------\"\"\",\n                    version, download_base, delay, url\n                ); from time import sleep; sleep(delay)\n            log.warn(\"Downloading %s\", url)\n            src = urllib2.urlopen(url)\n            # Read/write all in one block, so we don't create a corrupt file\n            # if the download is interrupted.\n            data = _validate_md5(egg_name, src.read())\n            dst = open(saveto,\"wb\"); dst.write(data)\n        finally:\n            if src: src.close()\n            if dst: dst.close()\n    return os.path.realpath(saveto)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndef main(argv, version=DEFAULT_VERSION):\n    \"\"\"Install or upgrade setuptools and EasyInstall\"\"\"\n    try:\n        import setuptools\n    except ImportError:\n        egg = None\n        try:\n            egg = download_setuptools(version, delay=0)\n            sys.path.insert(0,egg)\n            from setuptools.command.easy_install import main\n            return main(list(argv)+[egg])   # we're done here\n        finally:\n            if egg and os.path.exists(egg):\n                os.unlink(egg)\n    else:\n        if setuptools.__version__ == '0.0.1':\n            print >>sys.stderr, (\n            \"You have an obsolete version of setuptools installed.  Please\\n\"\n            \"remove it from your system entirely before rerunning this script.\"\n            )\n            sys.exit(2)\n\n    req = \"setuptools>=\"+version\n    import pkg_resources\n    try:\n        pkg_resources.require(req)\n    except pkg_resources.VersionConflict:\n        try:\n            from setuptools.command.easy_install import main\n        except ImportError:\n            from easy_install import main\n        main(list(argv)+[download_setuptools(delay=0)])\n        sys.exit(0) # try to force an exit\n    else:\n        if argv:\n            from setuptools.command.easy_install import main\n            main(argv)\n        else:\n            print \"Setuptools version\",version,\"or greater has been installed.\"\n            print '(Run \"ez_setup.py -U setuptools\" to reinstall or upgrade.)'\n\ndef update_md5(filenames):\n    \"\"\"Update our built-in md5 registry\"\"\"\n\n    import re\n\n    for name in filenames:\n        base = os.path.basename(name)\n        f = open(name,'rb')\n        md5_data[base] = md5(f.read()).hexdigest()\n        f.close()\n\n    data = [\"    %r: %r,\\n\" % it for it in md5_data.items()]\n    data.sort()\n    repl = \"\".join(data)\n\n    import inspect\n    srcfile = inspect.getsourcefile(sys.modules[__name__])\n    f = open(srcfile, 'rb'); src = f.read(); f.close()\n\n    match = re.search(\"\\nmd5_data = {\\n([^}]+)}\", src)\n    if not match:\n        print >>sys.stderr, \"Internal error!\"\n        sys.exit(2)\n\n    src = src[:match.start(1)] + repl + src[match.end(1):]\n    f = open(srcfile,'w')\n    f.write(src)\n    f.close()\n\n\nif __name__=='__main__':\n    if len(sys.argv)>2 and sys.argv[1]=='--md5update':\n        update_md5(sys.argv[2:])\n    else:\n        main(sys.argv[1:])\n\n\n\n\n\n\n"
  },
  {
    "path": "pylons/__init__.py",
    "content": "\"\"\"Base objects to be exported for use in Controllers\"\"\"\n# Import pkg_resources first so namespace handling is properly done so the\n# paste imports work\nimport pkg_resources\nfrom paste.registry import StackedObjectProxy\n\nfrom pylons.configuration import config\nfrom pylons.controllers.util import Request\nfrom pylons.controllers.util import Response\n\n__all__ = ['app_globals', 'cache', 'config', 'request', 'response',\n           'session', 'tmpl_context', 'url', 'Request', 'Response']\n\n\ndef __figure_version():\n    try:\n        from pkg_resources import require\n        import os\n        # NOTE: this only works when the package is either installed,\n        # or has an .egg-info directory present (i.e. wont work with raw\n        # SVN checkout)\n        info = require('pylons')[0]\n        if os.path.normcase(os.path.realpath(os.path.dirname(\n            os.path.dirname(__file__)))) == info.location:\n            return info.version\n        else:\n            return '(not installed)'\n    except:\n        return '(not installed)'\n\n__version__ = __figure_version()\n\napp_globals = StackedObjectProxy(name=\"app_globals\")\ncache = StackedObjectProxy(name=\"cache\")\nrequest = StackedObjectProxy(name=\"request\")\nresponse = StackedObjectProxy(name=\"response\")\nsession = StackedObjectProxy(name=\"session\")\ntmpl_context = StackedObjectProxy(name=\"tmpl_context or C\")\nurl = StackedObjectProxy(name=\"url\")\n\ntranslator = StackedObjectProxy(name=\"translator\")\n"
  },
  {
    "path": "pylons/commands.py",
    "content": "\"\"\"Paster Commands, for use with paster in your project\n\n.. highlight:: bash\n\nThe following commands are made available via paster utilizing\nsetuptools points discovery. These can be used from the command line\nwhen the directory is the Pylons project.\n\nCommands available:\n\n``controller``\n    Create a Controller and accompanying functional test\n``restcontroller``\n    Create a REST Controller and accompanying functional test\n``shell``\n    Open an interactive shell with the Pylons app loaded\n\nExample usage::\n\n    ~/sample$ paster controller account\n    Creating /Users/ben/sample/sample/controllers/account.py\n    Creating /Users/ben/sample/sample/tests/functional/test_account.py\n    ~/sample$\n\n.. admonition:: How it Works\n\n    :command:`paster` is a command line script (from the PasteScript\n    package) that allows the creation of context sensitive commands.\n    :command:`paster` looks in the current directory for a\n    ``.egg-info`` directory, then loads the ``paster_plugins.txt``\n    file.\n\n    Using setuptools entry points, :command:`paster` looks for\n    functions registered with setuptools as\n    :func:`paste.paster_command`. These are defined in the entry_points\n    block in each packages :file:`setup.py` module.\n\n    This same system is used when running :command:`paster create` to\n    determine what templates are available when creating new projects.\n\n\"\"\"\nimport os\nimport sys\n\nimport paste.fixture\nimport paste.registry\nfrom paste.deploy import loadapp\nfrom paste.script.command import Command, BadCommand\nfrom paste.script.filemaker import FileOp\nfrom tempita import paste_script_template_renderer\n\nimport pylons\nimport pylons.util as util\n\n__all__ = ['ControllerCommand', 'RestControllerCommand', 'ShellCommand']\n\n\ndef can_import(name):\n    \"\"\"Attempt to __import__ the specified package/module, returning\n    True when succeeding, otherwise False\"\"\"\n    try:\n        __import__(name)\n        return True\n    except ImportError:\n        return False\n\n\ndef is_minimal_template(package, fail_fast=False):\n    \"\"\"Determine if the specified Pylons project (package) uses the\n    Pylons Minimal Template.\n\n    fail_fast causes ImportErrors encountered during detection to be\n    raised.\n    \"\"\"\n    minimal_template = False\n    try:\n        # Check if PACKAGE.lib.base exists\n        __import__(package + '.lib.base')\n    except ImportError, ie:\n        if 'No module named lib.base' in str(ie):\n            minimal_template = True\n    except:\n        # PACKAGE.lib.base exists but throws an error\n        if fail_fast:\n            raise\n    return minimal_template\n\n\ndef defines_render(package):\n    \"\"\"Determine if the specified Pylons project (package) defines a\n    render callable in their base module\n    \"\"\"\n    base_module = (is_minimal_template(package) and package + '.controllers' or\n                   package + '.lib.base')\n    try:\n        base = __import__(base_module, globals(), locals(), ['__doc__'])\n    except:\n        return False\n    return callable(getattr(base, 'render', None))\n\n\ndef validate_name(name):\n    \"\"\"Validate that the name for the controller isn't present on the\n    path already\"\"\"\n    if not name:\n        # This happens when the name is an existing directory\n        raise BadCommand('Please give the name of a controller.')\n    # 'setup' is a valid controller name, but when paster controller is ran\n    # from the root directory of a project, importing setup will import the\n    # project's setup.py causing a sys.exit(). Blame relative imports\n    if name != 'setup' and can_import(name):\n        raise BadCommand(\n            \"\\n\\nA module named '%s' is already present in your \"\n            \"PYTHON_PATH.\\nChoosing a conflicting name will likely cause \"\n            \"import problems in\\nyour controller at some point. It's \"\n            \"suggested that you choose an\\nalternate name, and if you'd \"\n            \"like that name to be accessible as\\n'%s', add a route \"\n            \"to your projects config/routing.py file similar\\nto:\\n\"\n            \"    map.connect('%s', controller='my_%s')\" \\\n            % (name, name, name, name))\n    return True\n\n\ndef check_controller_existence(base_package, directory, name):\n    \"\"\"Check if given controller already exists in project.\"\"\"\n    filename = os.path.join(base_package, 'controllers', directory,\n                            name + '.py')\n    if os.path.exists(filename):\n        raise BadCommand('Controller %s already exists.' %\n                         os.path.join(directory, name))\n\n\nclass ControllerCommand(Command):\n    \"\"\"Create a Controller and accompanying functional test\n\n    The Controller command will create the standard controller template\n    file and associated functional test to speed creation of\n    controllers.\n\n    Example usage::\n\n        yourproj% paster controller comments\n        Creating yourproj/yourproj/controllers/comments.py\n        Creating yourproj/yourproj/tests/functional/test_comments.py\n\n    If you'd like to have controllers underneath a directory, just\n    include the path as the controller name and the necessary\n    directories will be created for you::\n\n        yourproj% paster controller admin/trackback\n        Creating yourproj/controllers/admin\n        Creating yourproj/yourproj/controllers/admin/trackback.py\n        Creating yourproj/yourproj/tests/functional/test_admin_trackback.py\n\n    \"\"\"\n    summary = __doc__.splitlines()[0]\n    usage = '\\n' + __doc__\n\n    min_args = 1\n    max_args = 1\n    group_name = 'pylons'\n\n    default_verbosity = 3\n\n    parser = Command.standard_parser(simulate=True)\n    parser.add_option('--no-test',\n                      action='store_true',\n                      dest='no_test',\n                      help=\"Don't create the test; just the controller\")\n\n    def command(self):\n        \"\"\"Main command to create controller\"\"\"\n        try:\n            file_op = FileOp(source_dir=('pylons', 'templates'))\n            try:\n                name, directory = file_op.parse_path_name_args(self.args[0])\n            except:\n                raise BadCommand('No egg_info directory was found')\n\n            # Check the name isn't the same as the package\n            base_package = file_op.find_dir('controllers', True)[0]\n            if base_package.lower() == name.lower():\n                raise BadCommand(\n                    'Your controller name should not be the same as '\n                    'the package name %r.' % base_package)\n            # Validate the name\n            name = name.replace('-', '_')\n            validate_name(name)\n\n            # Determine the module's import statement\n            if is_minimal_template(base_package):\n                importstatement = ('from %s.controllers import BaseController'\n                                   % base_package)\n            else:\n                importstatement = ('from %s.lib.base import BaseController' %\n                                   base_package)\n            if defines_render(base_package):\n                importstatement += ', render'\n\n            # Setup the controller\n            fullname = os.path.join(directory, name)\n            controller_name = util.class_name_from_module_name(\n                name.split('/')[-1])\n            if not fullname.startswith(os.sep):\n                fullname = os.sep + fullname\n            testname = fullname.replace(os.sep, '_')[1:]\n\n            module_dir = directory.replace('/', os.path.sep)\n            check_controller_existence(base_package, module_dir, name)\n\n            file_op.template_vars.update(\n                {'name': controller_name,\n                 'fname': os.path.join(directory, name).replace('\\\\', '/'),\n                 'tmpl_name': name,\n                 'package': base_package,\n                 'importstatement': importstatement})\n            file_op.copy_file(template='controller.py_tmpl',\n                              dest=os.path.join('controllers', directory),\n                              filename=name,\n                              template_renderer=paste_script_template_renderer)\n            if not self.options.no_test:\n                file_op.copy_file(\n                    template='test_controller.py_tmpl',\n                    dest=os.path.join('tests', 'functional'),\n                    filename='test_' + testname,\n                    template_renderer=paste_script_template_renderer)\n        except BadCommand, e:\n            raise BadCommand('An error occurred. %s' % e)\n        except:\n            msg = str(sys.exc_info()[1])\n            raise BadCommand('An unknown error occurred. %s' % msg)\n\n\nclass RestControllerCommand(Command):\n    \"\"\"Create a REST Controller and accompanying functional test\n\n    The RestController command will create a REST-based Controller file\n    for use with the :meth:`~routes.mapper.Mapper.resource`\n    REST-based dispatching. This template includes the methods that\n    :meth:`~routes.mapper.Mapper.resource` dispatches to in\n    addition to doc strings for clarification on when the methods will\n    be called.\n\n    The first argument should be the singular form of the REST\n    resource. The second argument is the plural form of the word. If\n    its a nested controller, put the directory information in front as\n    shown in the second example below.\n\n    Example usage::\n\n        yourproj% paster restcontroller comment comments\n        Creating yourproj/yourproj/controllers/comments.py\n        Creating yourproj/yourproj/tests/functional/test_comments.py\n\n    If you'd like to have controllers underneath a directory, just\n    include the path as the controller name and the necessary\n    directories will be created for you::\n\n        yourproj% paster restcontroller admin/tracback admin/trackbacks\n        Creating yourproj/controllers/admin\n        Creating yourproj/yourproj/controllers/admin/trackbacks.py\n        Creating yourproj/yourproj/tests/functional/test_admin_trackbacks.py\n\n    \"\"\"\n    summary = __doc__.splitlines()[0]\n    usage = '\\n' + __doc__\n\n    min_args = 2\n    max_args = 2\n    group_name = 'pylons'\n\n    default_verbosity = 3\n\n    parser = Command.standard_parser(simulate=True)\n    parser.add_option('--no-test',\n                      action='store_true',\n                      dest='no_test',\n                      help=\"Don't create the test; just the controller\")\n\n    def command(self):\n        \"\"\"Main command to create controller\"\"\"\n        try:\n            file_op = FileOp(source_dir=('pylons', 'templates'))\n            try:\n                singularname, singulardirectory = \\\n                    file_op.parse_path_name_args(self.args[0])\n                pluralname, pluraldirectory = \\\n                    file_op.parse_path_name_args(self.args[1])\n\n            except:\n                raise BadCommand('No egg_info directory was found')\n\n            # Check the name isn't the same as the package\n            base_package = file_op.find_dir('controllers', True)[0]\n            if base_package.lower() == pluralname.lower():\n                raise BadCommand(\n                    'Your controller name should not be the same as '\n                    'the package name %r.' % base_package)\n            # Validate the name\n            for name in [pluralname]:\n                name = name.replace('-', '_')\n                validate_name(name)\n\n            # Determine the module's import statement\n            if is_minimal_template(base_package):\n                importstatement = ('from %s.controllers import BaseController'\n                                   % base_package)\n            else:\n                importstatement = ('from %s.lib.base import BaseController' %\n                                   base_package)\n            if defines_render(base_package):\n                importstatement += ', render'\n\n            module_dir = pluraldirectory.replace('/', os.path.sep)\n            check_controller_existence(base_package, module_dir, name)\n\n            # Setup the controller\n            fullname = os.path.join(pluraldirectory, pluralname)\n            controller_name = util.class_name_from_module_name(\n                pluralname.split('/')[-1])\n            if not fullname.startswith(os.sep):\n                fullname = os.sep + fullname\n            testname = fullname.replace(os.sep, '_')[1:]\n\n            nameprefix = ''\n            path = ''\n            if pluraldirectory:\n                nameprefix = pluraldirectory.replace(os.path.sep, '_') + '_'\n                path = pluraldirectory + '/'\n\n            controller_c = ''\n            if nameprefix:\n                controller_c = \", controller='%s', \\n\\t\" % \\\n                    '/'.join([pluraldirectory, pluralname])\n                controller_c += \"path_prefix='/%s', name_prefix='%s'\" % \\\n                    (pluraldirectory, nameprefix)\n            command = \"map.resource('%s', '%s'%s)\\n\" % \\\n                (singularname, pluralname, controller_c)\n\n            file_op.template_vars.update(\n                {'classname': controller_name,\n                 'pluralname': pluralname,\n                 'singularname': singularname,\n                 'name': controller_name,\n                 'nameprefix': nameprefix,\n                 'package': base_package,\n                 'path': path,\n                 'resource_command': command.replace('\\n\\t', '\\n%s#%s' % \\\n                                                         (' ' * 4, ' ' * 9)),\n                 'fname': os.path.join(pluraldirectory, pluralname),\n                 'importstatement': importstatement})\n\n            resource_command = (\"\\nTo create the appropriate RESTful mapping, \"\n                                \"add a map statement to your\\n\")\n            resource_command += (\"config/routing.py file near the top like \"\n                                 \"this:\\n\\n\")\n            resource_command += command\n            file_op.copy_file(template='restcontroller.py_tmpl',\n                              dest=os.path.join('controllers', pluraldirectory),\n                              filename=pluralname,\n                              template_renderer=paste_script_template_renderer)\n            if not self.options.no_test:\n                file_op.copy_file(\n                    template='test_restcontroller.py_tmpl',\n                    dest=os.path.join('tests', 'functional'),\n                    filename='test_' + testname,\n                    template_renderer=paste_script_template_renderer)\n            print resource_command\n        except BadCommand, e:\n            raise BadCommand('An error occurred. %s' % e)\n        except:\n            msg = str(sys.exc_info()[1])\n            raise BadCommand('An unknown error occurred. %s' % msg)\n\n\nclass RoutesCommand(Command):\n    \"\"\"Print the applications routes\n\n    The optional CONFIG_FILE argument specifies the config file to use.\n    CONFIG_FILE defaults to 'development.ini'.\n\n    Example::\n\n        $ paster routes my-development.ini\n\n    \"\"\"\n    summary = __doc__.splitlines()[0]\n    usage = '\\n' + __doc__\n\n    min_args = 0\n    max_args = 1\n    group_name = 'pylons'\n\n    parser = Command.standard_parser(simulate=True)\n    parser.add_option('-q',\n                      action='count',\n                      dest='quiet',\n                      default=0,\n                      help=(\"Do not load logging configuration from the \"\n                            \"config file\"))\n\n    def command(self):\n        \"\"\"Main command to create a new shell\"\"\"\n        self.verbose = 3\n        if len(self.args) == 0:\n            # Assume the .ini file is ./development.ini\n            config_file = 'development.ini'\n            if not os.path.isfile(config_file):\n                raise BadCommand('%sError: CONFIG_FILE not found at: .%s%s\\n'\n                                 'Please specify a CONFIG_FILE' % \\\n                                 (self.parser.get_usage(), os.path.sep,\n                                  config_file))\n        else:\n            config_file = self.args[0]\n\n        config_name = 'config:%s' % config_file\n        here_dir = os.getcwd()\n\n        if not self.options.quiet:\n            # Configure logging from the config file\n            self.logging_file_config(config_file)\n\n        # Load the wsgi app first so that everything is initialized right\n        wsgiapp = loadapp(config_name, relative_to=here_dir)\n        test_app = paste.fixture.TestApp(wsgiapp)\n\n        # Query the test app to setup the environment and get the mapper\n        tresponse = test_app.get('/_test_vars')\n        mapper = tresponse.config.get('routes.map')\n        if mapper:\n            print mapper\n\n\nclass ShellCommand(Command):\n    \"\"\"Open an interactive shell with the Pylons app loaded\n\n    The optional CONFIG_FILE argument specifies the config file to use for\n    the interactive shell. CONFIG_FILE defaults to 'development.ini'.\n\n    This allows you to test your mapper, models, and simulate web requests\n    using ``paste.fixture``.\n\n    Example::\n\n        $ paster shell my-development.ini\n\n    \"\"\"\n    summary = __doc__.splitlines()[0]\n    usage = '\\n' + __doc__\n\n    min_args = 0\n    max_args = 1\n    group_name = 'pylons'\n\n    parser = Command.standard_parser(simulate=True)\n    parser.add_option('-d', '--disable-ipython',\n                      action='store_true',\n                      dest='disable_ipython',\n                      help=\"Don't use IPython if it is available\")\n\n    parser.add_option('-q',\n                      action='count',\n                      dest='quiet',\n                      default=0,\n                      help=(\"Do not load logging configuration from the \"\n                            \"config file\"))\n\n    def command(self):\n        \"\"\"Main command to create a new shell\"\"\"\n        self.verbose = 3\n        if len(self.args) == 0:\n            # Assume the .ini file is ./development.ini\n            config_file = 'development.ini'\n            if not os.path.isfile(config_file):\n                raise BadCommand('%sError: CONFIG_FILE not found at: .%s%s\\n'\n                                 'Please specify a CONFIG_FILE' % \\\n                                 (self.parser.get_usage(), os.path.sep,\n                                  config_file))\n        else:\n            config_file = self.args[0]\n\n        config_name = 'config:%s' % config_file\n        here_dir = os.getcwd()\n        locs = dict(__name__=\"pylons-admin\")\n\n        if not self.options.quiet:\n            # Configure logging from the config file\n            self.logging_file_config(config_file)\n\n        # Load locals and populate with objects for use in shell\n        sys.path.insert(0, here_dir)\n\n        # Load the wsgi app first so that everything is initialized right\n        wsgiapp = loadapp(config_name, relative_to=here_dir)\n        test_app = paste.fixture.TestApp(wsgiapp)\n\n        # Query the test app to setup the environment\n        tresponse = test_app.get('/_test_vars')\n        request_id = int(tresponse.body)\n\n        # Disable restoration during test_app requests\n        test_app.pre_request_hook = lambda self: \\\n            paste.registry.restorer.restoration_end()\n        test_app.post_request_hook = lambda self: \\\n            paste.registry.restorer.restoration_begin(request_id)\n\n        # Restore the state of the Pylons special objects\n        # (StackedObjectProxies)\n        paste.registry.restorer.restoration_begin(request_id)\n\n        # Determine the package name from the pylons.config object\n        pkg_name = pylons.config['pylons.package']\n\n        # Start the rest of our imports now that the app is loaded\n        if is_minimal_template(pkg_name, True):\n            model_module = None\n            helpers_module = pkg_name + '.helpers'\n            base_module = pkg_name + '.controllers'\n        else:\n            model_module = pkg_name + '.model'\n            helpers_module = pkg_name + '.lib.helpers'\n            base_module = pkg_name + '.lib.base'\n\n        if model_module and can_import(model_module):\n            locs['model'] = sys.modules[model_module]\n\n        if can_import(helpers_module):\n            locs['h'] = sys.modules[helpers_module]\n\n        exec ('from pylons import app_globals, config, request, response, '\n              'session, tmpl_context, url') in locs\n        exec ('from pylons.controllers.util import abort, redirect') in locs\n        exec 'from pylons.i18n import _, ungettext, N_' in locs\n        locs.pop('__builtins__', None)\n\n        # Import all objects from the base module\n        __import__(base_module)\n\n        base = sys.modules[base_module]\n        base_public = [__name for __name in dir(base) if not \\\n                       __name.startswith('_') or __name == '_']\n        locs.update((name, getattr(base, name)) for name in base_public)\n        locs.update(dict(wsgiapp=wsgiapp, app=test_app))\n\n        mapper = tresponse.config.get('routes.map')\n        if mapper:\n            locs['mapper'] = mapper\n\n        banner = \"  All objects from %s are available\\n\" % base_module\n        banner += \"  Additional Objects:\\n\"\n        if mapper:\n            banner += \"  %-10s -  %s\\n\" % ('mapper', 'Routes mapper object')\n        banner += \"  %-10s -  %s\\n\" % ('wsgiapp',\n            \"This project's WSGI App instance\")\n        banner += \"  %-10s -  %s\\n\" % ('app',\n            'paste.fixture wrapped around wsgiapp')\n\n        try:\n            if self.options.disable_ipython:\n                raise ImportError()\n\n            # try to use IPython if possible\n            try:\n                try:\n                    # 1.0 <= ipython\n                    from IPython.terminal.embed import InteractiveShellEmbed\n                except ImportError:\n                    # 0.11 <= ipython < 1.0\n                    from IPython.frontend.terminal.embed import InteractiveShellEmbed\n                shell = InteractiveShellEmbed(banner2=banner)\n            except ImportError:\n                # ipython < 0.11\n                from IPython.Shell import IPShellEmbed\n                shell = IPShellEmbed(argv=self.args)\n                shell.set_banner(shell.IP.BANNER + '\\n\\n' + banner)\n\n            try:\n                shell(local_ns=locs, global_ns={})\n            finally:\n                paste.registry.restorer.restoration_end()\n        except ImportError:\n            import code\n            py_prefix = sys.platform.startswith('java') and 'J' or 'P'\n            newbanner = \"Pylons Interactive Shell\\n%sython %s\\n\\n\" % \\\n                (py_prefix, sys.version)\n            banner = newbanner + banner\n            shell = code.InteractiveConsole(locals=locs)\n            try:\n                import readline\n            except ImportError:\n                pass\n            try:\n                shell.interact(banner)\n            finally:\n                paste.registry.restorer.restoration_end()\n"
  },
  {
    "path": "pylons/configuration.py",
    "content": "\"\"\"Configuration object and defaults setup\n\nThe PylonsConfig object is initialized in pylons projects inside the\n:file:`config/environment.py` module. Importing the :data:`config`\nobject from module causes the PylonsConfig object to be created, and\nsetup in  app-safe manner so that multiple apps being setup avoid\nconflicts.\n\nAfter importing :data:`config`, the project should then call\n:meth:`~PylonsConfig.init_app` with the appropriate options to setup\nthe configuration. In the config data passed with\n:meth:`~PylonsConfig.init_app`, various defaults are set use with Paste\nand Routes.\n\n\"\"\"\nimport copy\nimport logging\nimport os\n\nfrom paste.config import DispatchingConfig\nfrom paste.deploy.converters import asbool\nfrom webhelpers.mimehelper import MIMETypes\n\n\nrequest_defaults = dict(charset='utf-8', errors='replace',\n                        decode_param_names=False, language='en-us')\nresponse_defaults = dict(content_type='text/html',\n                         charset='utf-8', errors='strict',\n                         headers={'Cache-Control': 'no-cache',\n                                  'Pragma': 'no-cache'})\n\nlog = logging.getLogger(__name__)\n\n\nconfig = DispatchingConfig()\n\n\nclass PylonsConfig(dict):\n    \"\"\"Pylons configuration object\n\n    The Pylons configuration object is a per-application instance\n    object that retains the information regarding the global and app\n    conf's as well as per-application instance specific data such as\n    the mapper, and the paths for this instance.\n\n    The config object is available in your application as the Pylons\n    global :data:`pylons.config`. For example::\n\n        from pylons import config\n\n        template_paths = config['pylons.paths']['templates']\n\n    There's several useful keys of the config object most people will\n    be interested in:\n\n    ``pylons.paths``\n        A dict of absolute paths that were defined in the applications\n        ``config/environment.py`` module.\n    ``pylons.environ_config``\n        Dict of environ keys for where in the environ to pickup various\n        objects for registering with Pylons. If these are present then\n        PylonsApp will use them from environ rather than using default\n        middleware from Beaker. Valid keys are: ``session, cache``\n    ``pylons.strict_tmpl_context``\n        Whether or not the ``tmpl_context`` object should throw an\n        attribute error when access is attempted to an attribute that\n        doesn't exist. Defaults to True.\n    ``pylons.tmpl_context_attach_args``\n        Whethor or not Routes variables should automatically be\n        attached to the tmpl_context object when specified in a\n        controllers method.\n    ``pylons.request_options``\n        A dict of Content-Type related default settings for new\n        instances of :class:`~pylons.controllers.util.Request`. May\n        contain the values ``charset`` and ``errors`` and\n        ``decode_param_names``. Overrides the Pylons default values\n        specified by the ``request_defaults`` dict.\n    ``pylons.response_options``\n        A dict of Content-Type related default settings for new\n        instances of :class:`~pylons.controllers.util.Response`. May\n        contain the values ``content_type``, ``charset`` and\n        ``errors``. Overrides the Pylons default values specified by\n        the ``response_defaults`` dict.\n    ``routes.map``\n        Mapper object used for Routing. Yes, it is possible to add\n        routes after your application has started running.\n\n    \"\"\"\n    defaults = {\n        'debug': False,\n        'pylons.package': None,\n        'pylons.paths': {'root': None,\n                         'controllers': None,\n                         'templates': [],\n                         'static_files': None},\n        'pylons.environ_config': dict(session='beaker.session',\n                                      cache='beaker.cache'),\n        'pylons.app_globals': None,\n        'pylons.h': None,\n        'pylons.request_options': request_defaults.copy(),\n        'pylons.response_options': response_defaults.copy(),\n        'pylons.strict_tmpl_context': True,\n        'pylons.tmpl_context_attach_args': False,\n    }\n\n    def init_app(self, global_conf, app_conf, package=None, paths=None):\n        \"\"\"Initialize configuration for the application\n\n        .. note\n            This *must* be called at least once, as soon as possible\n            to setup all the configuration options.\n\n        ``global_conf``\n            Several options are expected to be set for a Pylons web\n            application. They will be loaded from the global_config\n            which has the main Paste options. If ``debug`` is not\n            enabled as a global config option, the following option\n            *must* be set:\n\n            * error_to - The email address to send the debug error to\n\n            The optional config options in this case are:\n\n            * smtp_server - The SMTP server to use, defaults to\n              'localhost'\n            * error_log - A logfile to write the error to\n            * error_subject_prefix - The prefix of the error email\n              subject\n            * from_address - Whom the error email should be from\n        ``app_conf``\n            Defaults supplied via the [app:main] section from the Paste\n            config file. ``load_config`` only cares about whether a\n            'prefix' option is set, if so it will update Routes to\n            ensure URL's take that into account.\n        ``package``\n            The name of the application package, to be stored in the\n            app_conf.\n\n        .. versionchanged:: 1.0\n            ``template_engine`` option is no longer supported.\n\n        \"\"\"\n        log.debug(\"Initializing configuration, package: '%s'\", package)\n\n        conf = global_conf.copy()\n        conf.update(app_conf)\n        conf.update(dict(app_conf=app_conf, global_conf=global_conf))\n        conf.update(self.pop('environment_load', {}))\n\n        if paths:\n            conf['pylons.paths'] = paths\n\n        conf['pylons.package'] = package\n\n        conf['debug'] = asbool(conf.get('debug'))\n\n        # Load the MIMETypes with its default types\n        MIMETypes.init()\n\n        # Ensure all the keys from defaults are present, load them if not\n        for key, val in copy.deepcopy(PylonsConfig.defaults).iteritems():\n            conf.setdefault(key, val)\n\n        # Load the errorware configuration from the Paste configuration file\n        # These all have defaults, and emails are only sent if configured and\n        # if this application is running in production mode\n        errorware = {}\n        errorware['debug'] = conf['debug']\n        if not errorware['debug']:\n            errorware['debug'] = False\n            errorware['error_email'] = conf.get('email_to')\n            errorware['error_log'] = conf.get('error_log', None)\n            errorware['smtp_server'] = conf.get('smtp_server',\n                'localhost')\n            errorware['error_subject_prefix'] = conf.get(\n                'error_subject_prefix', 'WebApp Error: ')\n            errorware['from_address'] = conf.get(\n                'from_address', conf.get('error_email_from',\n                                         'pylons@yourapp.com'))\n            errorware['error_message'] = conf.get('error_message',\n                'An internal server error occurred')\n\n        # Copy in some defaults\n        if 'cache_dir' in conf:\n            conf.setdefault('beaker.session.data_dir',\n                            os.path.join(conf['cache_dir'], 'sessions'))\n            conf.setdefault('beaker.cache.data_dir',\n                            os.path.join(conf['cache_dir'], 'cache'))\n\n        conf['pylons.cache_dir'] = conf.pop('cache_dir',\n                                            conf['app_conf'].get('cache_dir'))\n        # Save our errorware values\n        conf['pylons.errorware'] = errorware\n\n        # Load conf dict into self\n        self.update(conf)\n\n\npylons_config = PylonsConfig()\n\n\n# Push an empty config so all accesses to config at import time have something\n# to look at and modify. This config will be merged with the app's when it's\n# built in the paste.app_factory entry point.\npylons_config.update(copy.deepcopy(PylonsConfig.defaults))\nconfig.push_process_config(pylons_config)\n"
  },
  {
    "path": "pylons/controllers/__init__.py",
    "content": "\"\"\"Standard Controllers intended for subclassing by web developers\"\"\"\nfrom pylons.controllers.core import WSGIController\nfrom pylons.controllers.xmlrpc import XMLRPCController\nfrom pylons.controllers.jsonrpc import JSONRPCController, JSONRPCError\n"
  },
  {
    "path": "pylons/controllers/core.py",
    "content": "\"\"\"The core WSGIController\"\"\"\nimport inspect\nimport logging\nimport types\n\nfrom webob.exc import HTTPException, HTTPNotFound\n\nimport pylons\n\n__all__ = ['WSGIController']\n\nlog = logging.getLogger(__name__)\n\n\nclass WSGIController(object):\n    \"\"\"WSGI Controller that follows WSGI spec for calling and return\n    values\n\n    The Pylons WSGI Controller handles incoming web requests that are\n    dispatched from the PylonsBaseWSGIApp. These requests result in a\n    new instance of the WSGIController being created, which is then\n    called with the dict options from the Routes match. The standard\n    WSGI response is then returned with start_response called as per\n    the WSGI spec.\n\n    Special WSGIController methods you may define:\n\n    ``__before__``\n        This method is called before your action is, and should be used\n        for setting up variables/objects, restricting access to other\n        actions, or other tasks which should be executed before the\n        action is called.\n\n    ``__after__``\n        This method is called after the action is, unless an unexpected\n        exception was raised. Subclasses of\n        :class:`~webob.exc.HTTPException` (such as those raised by\n        ``redirect_to`` and ``abort``) are expected; e.g. ``__after__``\n        will be called on redirects.\n\n    Each action to be called is inspected with :meth:`_inspect_call` so\n    that it is only passed the arguments in the Routes match dict that\n    it asks for. The arguments passed into the action can be customized\n    by overriding the :meth:`_get_method_args` function which is\n    expected to return a dict.\n\n    In the event that an action is not found to handle the request, the\n    Controller will raise an \"Action Not Found\" error if in debug mode,\n    otherwise a ``404 Not Found`` error will be returned.\n\n    \"\"\"\n    _pylons_log_debug = False\n\n    def _perform_call(self, func, args):\n        \"\"\"Hide the traceback for everything above this method\"\"\"\n        __traceback_hide__ = 'before_and_this'\n        return func(**args)\n\n    def _inspect_call(self, func):\n        \"\"\"Calls a function with arguments from\n        :meth:`_get_method_args`\n\n        Given a function, inspect_call will inspect the function args\n        and call it with no further keyword args than it asked for.\n\n        If the function has been decorated, it is assumed that the\n        decorator preserved the function signature.\n\n        \"\"\"\n        # Check to see if the class has a cache of argspecs yet\n        try:\n            cached_argspecs = self.__class__._cached_argspecs\n        except AttributeError:\n            self.__class__._cached_argspecs = cached_argspecs = {}\n\n        # function could be callable\n        func_key = getattr(func, 'im_func', func.__call__)\n        try:\n            argspec = cached_argspecs[func_key]\n        except KeyError:\n            argspec = cached_argspecs[func_key] = inspect.getargspec(func_key)\n        kargs = self._get_method_args()\n\n        log_debug = self._pylons_log_debug\n        c = self._py_object.tmpl_context\n        environ = self._py_object.request.environ\n        args = None\n\n        if argspec[2]:\n            if self._py_object.config['pylons.tmpl_context_attach_args']:\n                for k, val in kargs.iteritems():\n                    setattr(c, k, val)\n            args = kargs\n        else:\n            args = {}\n            argnames = argspec[0][isinstance(func, types.MethodType)\n                                  and 1 or 0:]\n            for name in argnames:\n                if name in kargs:\n                    if self._py_object.config['pylons.tmpl_context_attach_args']:\n                        setattr(c, name, kargs[name])\n                    args[name] = kargs[name]\n        if log_debug:\n            log.debug(\"Calling %r method with keyword args: **%r\",\n                      func.__name__, args)\n        try:\n            result = self._perform_call(func, args)\n        except HTTPException, httpe:\n            if log_debug:\n                log.debug(\"%r method raised HTTPException: %s (code: %s)\",\n                          func.__name__, httpe.__class__.__name__,\n                          httpe.wsgi_response.code, exc_info=True)\n            result = httpe\n\n            # Store the exception in the environ\n            environ['pylons.controller.exception'] = httpe\n\n            # 304 Not Modified's shouldn't have a content-type set\n            if result.wsgi_response.status_int == 304:\n                result.wsgi_response.headers.pop('Content-Type', None)\n            result._exception = True\n\n        return result\n\n    def _get_method_args(self):\n        \"\"\"Retrieve the method arguments to use with inspect call\n\n        By default, this uses Routes to retrieve the arguments,\n        override this method to customize the arguments your controller\n        actions are called with.\n\n        This method should return a dict.\n\n        \"\"\"\n        req = self._py_object.request\n        kargs = req.environ['pylons.routes_dict'].copy()\n        kargs['environ'] = req.environ\n        kargs['start_response'] = self.start_response\n        kargs['pylons'] = self._py_object\n        return kargs\n\n    def _dispatch_call(self):\n        \"\"\"Handles dispatching the request to the function using\n        Routes\"\"\"\n        log_debug = self._pylons_log_debug\n        req = self._py_object.request\n        try:\n            action = req.environ['pylons.routes_dict']['action']\n        except KeyError:\n            raise Exception(\"No action matched from Routes, unable to\"\n                            \"determine action dispatch.\")\n        action_method = action.replace('-', '_')\n        if log_debug:\n            log.debug(\"Looking for %r method to handle the request\",\n                      action_method)\n        try:\n            func = getattr(self, action_method, None)\n        except UnicodeEncodeError:\n            func = None\n        if action_method != 'start_response' and callable(func):\n            # Store function used to handle request\n            req.environ['pylons.action_method'] = func\n\n            response = self._inspect_call(func)\n        else:\n            if log_debug:\n                log.debug(\"Couldn't find %r method to handle response\", action)\n            if pylons.config['debug']:\n                raise NotImplementedError('Action %r is not implemented' %\n                                          action)\n            else:\n                response = HTTPNotFound()\n        return response\n\n    def __call__(self, environ, start_response):\n        \"\"\"The main call handler that is called to return a response\"\"\"\n        log_debug = self._pylons_log_debug\n\n        # Keep a local reference to the req/response objects\n        self._py_object = environ['pylons.pylons']\n\n        # Keep private methods private\n        try:\n            if environ['pylons.routes_dict']['action'][:1] in ('_', '-'):\n                if log_debug:\n                    log.debug(\"Action starts with _, private action not \"\n                              \"allowed. Returning a 404 response\")\n                return HTTPNotFound()(environ, start_response)\n        except KeyError:\n            # The check later will notice that there's no action\n            pass\n\n        start_response_called = []\n\n        def repl_start_response(status, headers, exc_info=None):\n            response = self._py_object.response\n            start_response_called.append(None)\n\n            # Copy the headers from the global response\n            if log_debug:\n                log.debug(\"Merging pylons.response headers into \"\n                          \"start_response call, status: %s\", status)\n            headers.extend(header for header in response.headerlist\n                           if header[0] == 'Set-Cookie' or\n                           header[0].startswith('X-'))\n            return start_response(status, headers, exc_info)\n        self.start_response = repl_start_response\n\n        if hasattr(self, '__before__'):\n            response = self._inspect_call(self.__before__)\n            if hasattr(response, '_exception'):\n                return response(environ, self.start_response)\n\n        response = self._dispatch_call()\n        if not start_response_called:\n            self.start_response = start_response\n            py_response = self._py_object.response\n            # If its not a WSGI response, and we have content, it needs to\n            # be wrapped in the response object\n            if isinstance(response, str):\n                if log_debug:\n                    log.debug(\"Controller returned a string \"\n                              \", writing it to pylons.response\")\n                py_response.body = py_response.body + response\n            elif isinstance(response, unicode):\n                if log_debug:\n                    log.debug(\"Controller returned a unicode string \"\n                              \", writing it to pylons.response\")\n                py_response.unicode_body = py_response.unicode_body + \\\n                        response\n            elif hasattr(response, 'wsgi_response'):\n                # It's an exception that got tossed.\n                if log_debug:\n                    log.debug(\"Controller returned a Response object, merging \"\n                              \"it with pylons.response\")\n                for name, value in py_response.headers.items():\n                    if name.lower() == 'set-cookie':\n                        response.headers.add(name, value)\n                    else:\n                        response.headers.setdefault(name, value)\n                try:\n                    registry = environ['paste.registry']\n                    registry.replace(pylons.response, response)\n                except KeyError:\n                    # Ignore the case when someone removes the registry\n                    pass\n                py_response = response\n            elif response is None:\n                if log_debug:\n                    log.debug(\"Controller returned None\")\n            else:\n                if log_debug:\n                    log.debug(\"Assuming controller returned an iterable, \"\n                              \"setting it as pylons.response.app_iter\")\n                py_response.app_iter = response\n            response = py_response\n\n        if hasattr(self, '__after__'):\n            after = self._inspect_call(self.__after__)\n            if hasattr(after, '_exception'):\n                after.wsgi_response = True\n                response = after\n\n        if hasattr(response, 'wsgi_response'):\n            # Copy the response object into the testing vars if we're testing\n            if 'paste.testing_variables' in environ:\n                environ['paste.testing_variables']['response'] = response\n            if log_debug:\n                log.debug(\"Calling Response object to return WSGI data\")\n\n            return response(environ, self.start_response)\n\n        if log_debug:\n            log.debug(\"Response assumed to be WSGI content, returning \"\n                      \"un-touched\")\n        return response\n"
  },
  {
    "path": "pylons/controllers/jsonrpc.py",
    "content": "\"\"\"The base WSGI JSONRPCController\"\"\"\nimport inspect\nimport json\nimport logging\nimport types\nimport urllib\n\nfrom paste.response import replace_header\nfrom pylons.controllers import WSGIController\nfrom pylons.controllers.util import abort, Response\n\n__all__ = ['JSONRPCController', 'JSONRPCError',\n           'JSONRPC_PARSE_ERROR',\n           'JSONRPC_INVALID_REQUEST',\n           'JSONRPC_METHOD_NOT_FOUND',\n           'JSONRPC_INVALID_PARAMS',\n           'JSONRPC_INTERNAL_ERROR']\n\nlog = logging.getLogger(__name__)\n\nJSONRPC_VERSION = '2.0'\n\n\nclass JSONRPCError(BaseException):\n\n    def __init__(self, code, message):\n        self.code = code\n        self.message = message\n        self.data = None\n\n    def __str__(self):\n        return str(self.code) + ': ' + self.message\n\n    def as_dict(self):\n        \"\"\"Return a dictionary representation of this object for\n        serialization in a JSON-RPC response.\"\"\"\n        error = dict(code=self.code,\n                     message=self.message)\n        if self.data:\n            error['data'] = self.data\n\n        return error\n\n\nJSONRPC_PARSE_ERROR = JSONRPCError(-32700, \"Parse error\")\nJSONRPC_INVALID_REQUEST = JSONRPCError(-32600, \"Invalid Request\")\nJSONRPC_METHOD_NOT_FOUND = JSONRPCError(-32601, \"Method not found\")\nJSONRPC_INVALID_PARAMS = JSONRPCError(-32602, \"Invalid params\")\nJSONRPC_INTERNAL_ERROR = JSONRPCError(-32603, \"Internal error\")\n_reserved_errors = dict(parse_error=JSONRPC_PARSE_ERROR,\n                        invalid_request=JSONRPC_INVALID_REQUEST,\n                        method_not_found=JSONRPC_METHOD_NOT_FOUND,\n                        invalid_params=JSONRPC_INVALID_PARAMS,\n                        internal_error=JSONRPC_INTERNAL_ERROR)\n\n\ndef jsonrpc_error(req_id, error):\n    \"\"\"Generate a Response object with a JSON-RPC error body. Used to\n    raise top-level pre-defined errors that happen outside the\n    controller.\"\"\"\n    if error in _reserved_errors:\n        err = _reserved_errors[error]\n        return Response(body=json.dumps(dict(jsonrpc=JSONRPC_VERSION,\n                                             id=req_id,\n                                             error=err.as_dict())))\n\n\nclass JSONRPCController(WSGIController):\n    \"\"\"\n    A WSGI-speaking JSON-RPC 2.0 controller class\n\n    See the specification:\n    `<http://groups.google.com/group/json-rpc/web/json-rpc-2-0>`.\n\n    Many parts of this controller are modelled after XMLRPCController\n    from Pylons 0.9.7\n\n    Valid controller return values should be json-serializable objects.\n\n    Sub-classes should catch their exceptions and raise JSONRPCError\n    if they want to pass meaningful errors to the client. Unhandled\n    errors should be caught and return JSONRPC_INTERNAL_ERROR to the\n    client.\n\n    Parts of the specification not supported (yet):\n     - Notifications\n     - Batch\n    \"\"\"\n\n    def _get_method_args(self):\n        \"\"\"Return `self._rpc_args` to dispatched controller method\n        chosen by __call__\"\"\"\n        return self._rpc_args\n\n    def __call__(self, environ, start_response):\n        \"\"\"Parse the request body as JSON, look up the method on the\n        controller and if it exists, dispatch to it.\n        \"\"\"\n        length = 0\n        if 'CONTENT_LENGTH' not in environ:\n            log.debug(\"No Content-Length\")\n            abort(411)\n        else:\n            if environ['CONTENT_LENGTH'] == '':\n                abort(411)\n            length = int(environ['CONTENT_LENGTH'])\n            log.debug('Content-Length: %s', length)\n        if length == 0:\n            log.debug(\"Content-Length is 0\")\n            abort(411)\n\n        raw_body = environ['wsgi.input'].read(length)\n        json_body = json.loads(urllib.unquote_plus(raw_body))\n\n        self._req_id = json_body['id']\n        self._req_method = json_body['method']\n        self._req_params = json_body['params']\n        log.debug('id: %s, method: %s, params: %s',\n                  self._req_id,\n                  self._req_method,\n                  self._req_params)\n\n        self._error = None\n        try:\n            self._func = self._find_method()\n        except AttributeError:\n            err = jsonrpc_error(self._req_id, 'method_not_found')\n            return err(environ, start_response)\n\n        # now that we have a method, make sure we have enough\n        # parameters and pass off control to the controller.\n        if not isinstance(self._req_params, dict):\n            # JSON-RPC version 1 request.\n            arglist = inspect.getargspec(self._func)[0][1:]\n            if len(self._req_params) < len(arglist):\n                err = jsonrpc_error(self._req_id, 'invalid_params')\n                return err(environ, start_response)\n            else:\n                kargs = dict(zip(arglist, self._req_params))\n        else:\n            # JSON-RPC version 2 request.  Params may be default, and\n            # are already a dict, so skip the parameter length check here.\n            kargs = self._req_params\n\n        # XX Fix this namespace clash. One cannot use names below as\n        # method argument names as this stands!\n        kargs['action'], kargs['environ'] = self._req_method, environ\n        kargs['start_response'] = start_response\n        self._rpc_args = kargs\n\n        status = []\n        headers = []\n        exc_info = []\n\n        def change_content(new_status, new_headers, new_exc_info=None):\n            status.append(new_status)\n            headers.extend(new_headers)\n            exc_info.append(new_exc_info)\n\n        output = WSGIController.__call__(self, environ, change_content)\n        output = list(output)\n        headers.append(('Content-Length', str(len(output[0]))))\n        replace_header(headers, 'Content-Type', 'application/json')\n        start_response(status[0], headers, exc_info[0])\n\n        return output\n\n    def _dispatch_call(self):\n        \"\"\"Implement dispatch interface specified by WSGIController\"\"\"\n        try:\n            raw_response = self._inspect_call(self._func)\n        except JSONRPCError, e:\n            self._error = e.as_dict()\n        except TypeError, e:\n            # Insufficient args in an arguments dict v2 call.\n            if 'takes at least' in str(e):\n                err = _reserved_errors['invalid_params']\n                self._error = err.as_dict()\n            else:\n                raise\n        except Exception, e:\n            log.debug('Encountered unhandled exception: %s', repr(e))\n            err = _reserved_errors['internal_error']\n            self._error = err.as_dict()\n\n        response = dict(jsonrpc=JSONRPC_VERSION,\n                        id=self._req_id)\n        if self._error is not None:\n            response['error'] = self._error\n        else:\n            response['result'] = raw_response\n\n        try:\n            return json.dumps(response)\n        except TypeError, e:\n            log.debug('Error encoding response: %s', e)\n            err = _reserved_errors['internal_error']\n            return json.dumps(dict(\n                    jsonrpc=JSONRPC_VERSION,\n                    id=self._req_id,\n                    error=err.as_dict()))\n\n    def _find_method(self):\n        \"\"\"Return method named by `self._req_method` in controller if able\"\"\"\n        log.debug('Trying to find JSON-RPC method: %s', self._req_method)\n        if self._req_method.startswith('_'):\n            raise AttributeError(\"Method not allowed\")\n\n        try:\n            func = getattr(self, self._req_method, None)\n        except UnicodeEncodeError:\n            # XMLRPCController catches this, not sure why.\n            raise AttributeError(\"Problem decoding unicode in requested \"\n                                 \"method name.\")\n\n        if isinstance(func, types.MethodType):\n            return func\n        else:\n            raise AttributeError(\"No such method: %s\" % self._req_method)\n"
  },
  {
    "path": "pylons/controllers/util.py",
    "content": "\"\"\"Utility functions and classes available for use by Controllers\n\nPylons subclasses the `WebOb <http://pythonpaste.org/webob/>`_\n:class:`webob.Request` and :class:`webob.Response` classes to provide\nbackwards compatible functions for earlier versions of Pylons as well\nas add a few helper functions to assist with signed cookies.\n\nFor reference use, refer to the :class:`Request` and :class:`Response`\nbelow.\n\nFunctions available:\n\n:func:`abort`, :func:`forward`, :func:`etag_cache`,\n:func:`mimetype` and :func:`redirect`\n\"\"\"\nimport base64\nimport binascii\nimport hmac\nimport logging\nimport re\ntry:\n    import cPickle as pickle\nexcept ImportError:\n    import pickle\ntry:\n    from hashlib import sha1\nexcept ImportError:\n    import sha as sha1\n\nfrom webob import BaseRequest as WebObRequest\nfrom webob import Response as WebObResponse\nfrom webob.exc import status_map\n\nimport pylons\n\n__all__ = ['abort', 'etag_cache', 'redirect', 'Request', 'Response']\n\nlog = logging.getLogger(__name__)\n\nIF_NONE_MATCH = re.compile('(?:W/)?(?:\"([^\"]*)\",?\\s*)')\n\n\nclass Request(WebObRequest):\n    \"\"\"WebOb Request subclass\n\n    The WebOb :class:`webob.Request` has no charset, or other defaults. This subclass\n    adds defaults, along with several methods for backwards\n    compatibility with paste.wsgiwrappers.WSGIRequest.\n\n    \"\"\"\n    def determine_browser_charset(self):\n        \"\"\"Legacy method to return the\n        :attr:`webob.Request.accept_charset`\"\"\"\n        return self.accept_charset\n\n    def languages(self):\n        # And we now have the old best_matches code that webob ditched!\n        al = self.accept_language\n        try:\n            items = [i for i, q in sorted(al._parsed, key=lambda iq: -iq[1])]\n            for index, item in enumerate(items):\n                if al._match(item, self.language):\n                    items[index:] = [self.language]\n                    break\n            else:\n                items.append(self.language)\n            return items\n        except AttributeError:\n            # If its a NilAccept, there won't be a _parsed attribute\n            # Return the best match instead\n            return [self.accept_language.best_match(self.language)]\n    languages = property(languages)\n\n    def match_accept(self, mimetypes):\n        return self.accept.first_match(mimetypes)\n\n    def signed_cookie(self, name, secret):\n        \"\"\"Extract a signed cookie of ``name`` from the request\n\n        The cookie is expected to have been created with\n        ``Response.signed_cookie``, and the ``secret`` should be the\n        same as the one used to sign it.\n\n        Any failure in the signature of the data will result in None\n        being returned.\n\n        \"\"\"\n        cookie = self.str_cookies.get(name)\n        if not cookie:\n            return None\n        try:\n            input_sig, pickled = cookie[:40], base64.standard_b64decode(cookie[40:])\n        except binascii.Error:\n            # Badly formed data can make base64 die\n            return None\n        sig = hmac.new(secret, pickled, sha1).hexdigest()\n\n        # Avoid timing attacks\n        invalid_bits = 0\n        if len(sig) != len(input_sig):\n            return None\n\n        for a, b in zip(sig, input_sig):\n            invalid_bits += a != b\n\n        if invalid_bits:\n            return None\n        else:\n            return pickle.loads(pickled)\n\n\nclass Response(WebObResponse):\n    \"\"\"WebOb Response subclass\n\n    The WebOb Response has no default content type, or error defaults.\n    This subclass adds defaults, along with several methods for\n    backwards compatibility with paste.wsgiwrappers.WSGIResponse.\n\n    \"\"\"\n    content = WebObResponse.body\n\n    def determine_charset(self):\n        return self.charset\n\n    def has_header(self, header):\n        return header in self.headers\n\n    def get_content(self):\n        return self.body\n\n    def wsgi_response(self):\n        return self.status, self.headers, self.body\n\n    def signed_cookie(self, name, data, secret=None, **kwargs):\n        \"\"\"Save a signed cookie with ``secret`` signature\n\n        Saves a signed cookie of the pickled data. All other keyword\n        arguments that ``WebOb.set_cookie`` accepts are usable and\n        passed to the WebOb set_cookie method after creating the signed\n        cookie value.\n\n        \"\"\"\n        pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)\n        sig = hmac.new(secret, pickled, sha1).hexdigest()\n        self.set_cookie(name, sig + base64.standard_b64encode(pickled), **kwargs)\n\n\ndef etag_cache(key=None):\n    \"\"\"Use the HTTP Entity Tag cache for Browser side caching\n\n    If a \"If-None-Match\" header is found, and equivilant to ``key``,\n    then a ``304`` HTTP message will be returned with the ETag to tell\n    the browser that it should use its current cache of the page.\n\n    Otherwise, the ETag header will be added to the response headers.\n\n    Suggested use is within a Controller Action like so:\n\n    .. code-block:: python\n\n        import pylons\n\n        class YourController(BaseController):\n            def index(self):\n                etag_cache(key=1)\n                return render('/splash.mako')\n\n    .. note::\n        This works because etag_cache will raise an HTTPNotModified\n        exception if the ETag received matches the key provided.\n\n    \"\"\"\n    if_none_matches = IF_NONE_MATCH.findall(\n        pylons.request.environ.get('HTTP_IF_NONE_MATCH', ''))\n    response = pylons.response._current_obj()\n    response.headers['ETag'] = '\"%s\"' % key\n    if str(key) in if_none_matches:\n        log.debug(\"ETag match, returning 304 HTTP Not Modified Response\")\n        response.headers.pop('Content-Type', None)\n        response.headers.pop('Cache-Control', None)\n        response.headers.pop('Pragma', None)\n        raise status_map[304]()\n    else:\n        log.debug(\"ETag didn't match, returning response object\")\n\n\ndef forward(wsgi_app):\n    \"\"\"Forward the request to a WSGI application. Returns its response.\n\n    .. code-block:: python\n\n        return forward(FileApp('filename'))\n\n    \"\"\"\n    environ = pylons.request.environ\n    controller = environ.get('pylons.controller')\n    if not controller or not hasattr(controller, 'start_response'):\n        raise RuntimeError(\"Unable to forward: environ['pylons.controller'] \"\n                           \"is not a valid Pylons controller\")\n    return wsgi_app(environ, controller.start_response)\n\n\ndef abort(status_code=None, detail=\"\", headers=None, comment=None):\n    \"\"\"Aborts the request immediately by returning an HTTP exception\n\n    In the event that the status_code is a 300 series error, the detail\n    attribute will be used as the Location header should one not be\n    specified in the headers attribute.\n\n    \"\"\"\n    exc = status_map[status_code](detail=detail, headers=headers,\n                                  comment=comment)\n    log.debug(\"Aborting request, status: %s, detail: %r, headers: %r, \"\n              \"comment: %r\", status_code, detail, headers, comment)\n    raise exc\n\n\ndef redirect(url, code=302):\n    \"\"\"Raises a redirect exception to the specified URL\n\n    Optionally, a code variable may be passed with the status code of\n    the redirect, ie::\n\n        redirect(url(controller='home', action='index'), code=303)\n\n    \"\"\"\n    log.debug(\"Generating %s redirect\" % code)\n    exc = status_map[code]\n    raise exc(location=url.encode('utf-8'))\n"
  },
  {
    "path": "pylons/controllers/xmlrpc.py",
    "content": "\"\"\"The base WSGI XMLRPCController\"\"\"\nimport inspect\nimport logging\nimport types\nimport xmlrpclib\n\nfrom paste.response import replace_header\n\nfrom pylons.controllers import WSGIController\nfrom pylons.controllers.util import abort, Response\n\n__all__ = ['XMLRPCController']\n\nlog = logging.getLogger(__name__)\n\nXMLRPC_MAPPING = ((basestring, 'string'), (list, 'array'), (bool, 'boolean'),\n                  (int, 'int'), (float, 'double'), (dict, 'struct'),\n                  (xmlrpclib.DateTime, 'dateTime.iso8601'),\n                  (xmlrpclib.Binary, 'base64'))\n\n\ndef xmlrpc_sig(args):\n    \"\"\"Returns a list of the function signature in string format based on a\n    tuple provided by xmlrpclib.\"\"\"\n    signature = []\n    for param in args:\n        for type, xml_name in XMLRPC_MAPPING:\n            if isinstance(param, type):\n                signature.append(xml_name)\n                break\n    return signature\n\n\ndef xmlrpc_fault(code, message):\n    \"\"\"Convienence method to return a Pylons response XMLRPC Fault\"\"\"\n    fault = xmlrpclib.Fault(code, message)\n    return Response(body=xmlrpclib.dumps(fault, methodresponse=True))\n\n\nclass XMLRPCController(WSGIController):\n    \"\"\"XML-RPC Controller that speaks WSGI\n\n    This controller handles XML-RPC responses and complies with the\n    `XML-RPC Specification <http://www.xmlrpc.com/spec>`_ as well as\n    the `XML-RPC Introspection\n    <http://scripts.incutio.com/xmlrpc/introspection.html>`_\n    specification.\n\n    By default, methods with names containing a dot are translated to\n    use an underscore. For example, the `system.methodHelp` is handled\n    by the method :meth:`system_methodHelp`.\n\n    Methods in the XML-RPC controller will be called with the method\n    given in the XMLRPC body. Methods may be annotated with a signature\n    attribute to declare the valid arguments and return types.\n\n    For example::\n\n        class MyXML(XMLRPCController):\n            def userstatus(self):\n                return 'basic string'\n            userstatus.signature = [ ['string'] ]\n\n            def userinfo(self, username, age=None):\n                user = LookUpUser(username)\n                response = {'username':user.name}\n                if age and age > 10:\n                    response['age'] = age\n                return response\n            userinfo.signature = [['struct', 'string'],\n                                  ['struct', 'string', 'int']]\n\n    Since XML-RPC methods can take different sets of data, each set of\n    valid arguments is its own list. The first value in the list is the\n    type of the return argument. The rest of the arguments are the\n    types of the data that must be passed in.\n\n    In the last method in the example above, since the method can\n    optionally take an integer value both sets of valid parameter lists\n    should be provided.\n\n    Valid types that can be checked in the signature and their\n    corresponding Python types::\n\n        'string' - str\n        'array' - list\n        'boolean' - bool\n        'int' - int\n        'double' - float\n        'struct' - dict\n        'dateTime.iso8601' - xmlrpclib.DateTime\n        'base64' - xmlrpclib.Binary\n\n    The class variable ``allow_none`` is passed to xmlrpclib.dumps;\n    enabling it allows translating ``None`` to XML (an extension to the\n    XML-RPC specification)\n\n    .. note::\n\n        Requiring a signature is optional.\n\n    \"\"\"\n    allow_none = False\n    max_body_length = 4194304\n\n    def _get_method_args(self):\n        return self.rpc_kargs\n\n    def __call__(self, environ, start_response):\n        \"\"\"Parse an XMLRPC body for the method, and call it with the\n        appropriate arguments\"\"\"\n        # Pull out the length, return an error if there is no valid\n        # length or if the length is larger than the max_body_length.\n        log_debug = self._pylons_log_debug\n        length = environ.get('CONTENT_LENGTH')\n        if length:\n            length = int(length)\n        else:\n            # No valid Content-Length header found\n            if log_debug:\n                log.debug(\"No Content-Length found, returning 411 error\")\n            abort(411)\n        if length > self.max_body_length or length == 0:\n            if log_debug:\n                log.debug(\"Content-Length larger than max body length. Max: \"\n                          \"%s, Sent: %s. Returning 413 error\",\n                          self.max_body_length, length)\n            abort(413, \"XML body too large\")\n\n        body = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))\n        rpc_args, orig_method = xmlrpclib.loads(body)\n\n        method = self._find_method_name(orig_method)\n        func = self._find_method(method)\n        if not func:\n            if log_debug:\n                log.debug(\"Method: %r not found, returning xmlrpc fault\",\n                          method)\n            return xmlrpc_fault(0, \"No such method name %r\" %\n                                method)(environ, start_response)\n\n        # Signature checking for params\n        if hasattr(func, 'signature'):\n            if log_debug:\n                log.debug(\"Checking XMLRPC argument signature\")\n            valid_args = False\n            params = xmlrpc_sig(rpc_args)\n            for sig in func.signature:\n                # Next sig if we don't have the same amount of args\n                if len(sig) - 1 != len(rpc_args):\n                    continue\n\n                # If the params match, we're valid\n                if params == sig[1:]:\n                    valid_args = True\n                    break\n\n            if not valid_args:\n                if log_debug:\n                    log.debug(\"Bad argument signature recieved, returning \"\n                              \"xmlrpc fault\")\n                msg = (\"Incorrect argument signature. %r recieved does not \"\n                       \"match %r signature for method %r\" % \\\n                           (params, func.signature, orig_method))\n                return xmlrpc_fault(0, msg)(environ, start_response)\n\n        # Change the arg list into a keyword dict based off the arg\n        # names in the functions definition\n        arglist = inspect.getargspec(func)[0][1:]\n        kargs = dict(zip(arglist, rpc_args))\n        kargs['action'], kargs['environ'] = method, environ\n        kargs['start_response'] = start_response\n        self.rpc_kargs = kargs\n        self._func = func\n\n        # Now that we know the method is valid, and the args are valid,\n        # we can dispatch control to the default WSGIController\n        status = []\n        headers = []\n        exc_info = []\n\n        def change_content(new_status, new_headers, new_exc_info=None):\n            status.append(new_status)\n            headers.extend(new_headers)\n            exc_info.append(new_exc_info)\n        output = WSGIController.__call__(self, environ, change_content)\n        output = list(output)\n        headers.append(('Content-Length', str(len(output[0]))))\n        replace_header(headers, 'Content-Type', 'text/xml')\n        start_response(status[0], headers, exc_info[0])\n        return output\n\n    def _dispatch_call(self):\n        \"\"\"Dispatch the call to the function chosen by __call__\"\"\"\n        raw_response = self._inspect_call(self._func)\n        if not isinstance(raw_response, xmlrpclib.Fault):\n            raw_response = (raw_response,)\n\n        response = xmlrpclib.dumps(raw_response, methodresponse=True,\n                                   allow_none=self.allow_none)\n        return response\n\n    def _find_method(self, name):\n        \"\"\"Locate a method in the controller by the specified name and\n        return it\"\"\"\n        # Keep private methods private\n        if name.startswith('_'):\n            if self._pylons_log_debug:\n                log.debug(\"Action starts with _, private action not allowed\")\n            return\n\n        if self._pylons_log_debug:\n            log.debug(\"Looking for XMLRPC method: %r\", name)\n        try:\n            func = getattr(self, name, None)\n        except UnicodeEncodeError:\n            return\n        if isinstance(func, types.MethodType):\n            return func\n\n    def _find_method_name(self, name):\n        \"\"\"Locate a method in the controller by the appropriate name\n\n        By default, this translates method names like\n        'system.methodHelp' into 'system_methodHelp'.\n\n        \"\"\"\n        return name.replace('.', '_')\n\n    def _publish_method_name(self, name):\n        \"\"\"Translate an internal method name to a publicly viewable one\n\n        By default, this translates internal method names like\n        'blog_view' into 'blog.view'.\n\n        \"\"\"\n        return name.replace('_', '.')\n\n    def system_listMethods(self):\n        \"\"\"Returns a list of XML-RPC methods for this XML-RPC resource\"\"\"\n        methods = []\n        for method in dir(self):\n            meth = getattr(self, method)\n\n            if not method.startswith('_') and isinstance(meth,\n                                                         types.MethodType):\n                methods.append(self._publish_method_name(method))\n        return methods\n    system_listMethods.signature = [['array']]\n\n    def system_methodSignature(self, name):\n        \"\"\"Returns an array of array's for the valid signatures for a\n        method.\n\n        The first value of each array is the return value of the\n        method. The result is an array to indicate multiple signatures\n        a method may be capable of.\n\n        \"\"\"\n        method = self._find_method(self._find_method_name(name))\n        if method:\n            return getattr(method, 'signature', '')\n        else:\n            return xmlrpclib.Fault(0, 'No such method name')\n    system_methodSignature.signature = [['array', 'string'],\n                                        ['string', 'string']]\n\n    def system_methodHelp(self, name):\n        \"\"\"Returns the documentation for a method\"\"\"\n        method = self._find_method(self._find_method_name(name))\n        if method:\n            help = MethodHelp.getdoc(method)\n            sig = getattr(method, 'signature', None)\n            if sig:\n                help += \"\\n\\nMethod signature: %s\" % sig\n            return help\n        return xmlrpclib.Fault(0, \"No such method name\")\n    system_methodHelp.signature = [['string', 'string']]\n\n\nclass MethodHelp(object):\n    \"\"\"Wrapper for formatting doc strings from XMLRPCController\n    methods\"\"\"\n    def __init__(self, doc):\n        self.__doc__ = doc\n\n    def getdoc(method):\n        \"\"\"Return a formatted doc string, via inspect.getdoc, from the\n        specified XMLRPCController method\n\n        The method's help attribute is used if it exists, otherwise the\n        method's doc string is used.\n        \"\"\"\n        help = getattr(method, 'help', None)\n        if help is None:\n            help = method.__doc__\n        doc = inspect.getdoc(MethodHelp(help))\n        if doc is None:\n            return ''\n        return doc\n    getdoc = staticmethod(getdoc)\n"
  },
  {
    "path": "pylons/decorators/__init__.py",
    "content": "\"\"\"Pylons Decorators\n\nCommon decorators intended for use in controllers. Additional\ndecorators for use with controllers are in the\n:mod:`~pylons.decorators.cache`, :mod:`~pylons.decorators.rest` and\n:mod:`~pylons.decorators.secure` modules.\n\n\"\"\"\nimport logging\nimport warnings\n\nimport formencode\nimport simplejson\nfrom decorator import decorator\nfrom formencode import api, htmlfill, variabledecode\n\nfrom pylons.decorators.util import get_pylons\nfrom pylons.i18n import _ as pylons_gettext\n\n__all__ = ['jsonify', 'validate']\n\nlog = logging.getLogger(__name__)\n\n\nclass JSONEncoder(simplejson.JSONEncoder):\n    def default(self, obj):\n        encoder = getattr(obj, '__json__', None)\n        if encoder is not None:\n            return encoder()\n        return super(JSONEncoder, self).default(obj)\n\n\n@decorator\ndef jsonify(func, *args, **kwargs):\n    \"\"\"Action decorator that formats output for JSON\n\n    Given a function that will return content, this decorator will turn\n    the result into JSON, with a content-type of 'application/json' and\n    output it.\n\n    \"\"\"\n    pylons = get_pylons(args)\n    pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'\n    data = func(*args, **kwargs)\n    if isinstance(data, (list, tuple)):\n        msg = \"JSON responses with Array envelopes are susceptible to \" \\\n              \"cross-site data leak attacks, see \" \\\n              \"http://wiki.pylonshq.com/display/pylonsfaq/Warnings\"\n        warnings.warn(msg, Warning, 2)\n        log.warning(msg)\n    log.debug(\"Returning JSON wrapped action output\")\n    return simplejson.dumps(data, cls=JSONEncoder, encoding='utf-8')\n\n\ndef validate(schema=None, validators=None, form=None, variable_decode=False,\n             dict_char='.', list_char='-', post_only=True, state=None,\n             on_get=False, **htmlfill_kwargs):\n    \"\"\"Validate input either for a FormEncode schema, or individual\n    validators\n\n    Given a form schema or dict of validators, validate will attempt to\n    validate the schema or validator list.\n\n    If validation was successful, the valid result dict will be saved\n    as ``self.form_result``. Otherwise, the action will be re-run as if\n    it was a GET, and the output will be filled by FormEncode's\n    htmlfill to fill in the form field errors.\n\n    ``schema``\n        Refers to a FormEncode Schema object to use during validation.\n    ``form``\n        Method used to display the form, which will be used to get the\n        HTML representation of the form for error filling.\n    ``variable_decode``\n        Boolean to indicate whether FormEncode's variable decode\n        function should be run on the form input before validation.\n    ``dict_char``\n        Passed through to FormEncode. Toggles the form field naming\n        scheme used to determine what is used to represent a dict. This\n        option is only applicable when used with variable_decode=True.\n    ``list_char``\n        Passed through to FormEncode. Toggles the form field naming\n        scheme used to determine what is used to represent a list. This\n        option is only applicable when used with variable_decode=True.\n    ``post_only``\n        Boolean that indicates whether or not GET (query) variables\n        should be included during validation.\n\n        .. warning::\n            ``post_only`` applies to *where* the arguments to be\n            validated come from. It does *not* restrict the form to\n            only working with post, merely only checking POST vars.\n    ``state``\n        Passed through to FormEncode for use in validators that utilize\n        a state object.\n    ``on_get``\n        Whether to validate on GET requests. By default only POST\n        requests are validated.\n\n    Example::\n\n        class SomeController(BaseController):\n\n            def create(self, id):\n                return render('/myform.mako')\n\n            @validate(schema=model.forms.myshema(), form='create')\n            def update(self, id):\n                # Do something with self.form_result\n                pass\n\n    \"\"\"\n    if state is None:\n        state = PylonsFormEncodeState\n\n    def wrapper(func, self, *args, **kwargs):\n        \"\"\"Decorator Wrapper function\"\"\"\n        request = self._py_object.request\n        errors = {}\n\n        # Skip the validation if on_get is False and its a GET\n        if not on_get and request.environ['REQUEST_METHOD'] == 'GET':\n            return func(self, *args, **kwargs)\n\n        # If they want post args only, use just the post args\n        if post_only:\n            params = request.POST\n        else:\n            params = request.params\n\n        params = params.mixed()\n        if variable_decode:\n            log.debug(\"Running variable_decode on params\")\n            decoded = variabledecode.variable_decode(params, dict_char,\n                                                     list_char)\n        else:\n            decoded = params\n\n        if schema:\n            log.debug(\"Validating against a schema\")\n            try:\n                self.form_result = schema.to_python(decoded, state)\n            except formencode.Invalid, e:\n                errors = e.unpack_errors(variable_decode, dict_char, list_char)\n        if validators:\n            log.debug(\"Validating against provided validators\")\n            if isinstance(validators, dict):\n                if not hasattr(self, 'form_result'):\n                    self.form_result = {}\n                for field, validator in validators.iteritems():\n                    try:\n                        self.form_result[field] = \\\n                            validator.to_python(decoded.get(field), state)\n                    except formencode.Invalid, error:\n                        errors[field] = error\n        if errors:\n            log.debug(\"Errors found in validation, parsing form with htmlfill \"\n                      \"for errors\")\n            request.environ['REQUEST_METHOD'] = 'GET'\n            self._py_object.tmpl_context.form_errors = errors\n\n            # If there's no form supplied, just continue with the current\n            # function call.\n            if not form:\n                return func(self, *args, **kwargs)\n\n            request.environ['pylons.routes_dict']['action'] = form\n            response = self._dispatch_call()\n\n            # If the form_content is an exception response, return it\n            if hasattr(response, '_exception'):\n                return response\n\n            htmlfill_kwargs2 = htmlfill_kwargs.copy()\n            htmlfill_kwargs2.setdefault('encoding', request.charset)\n            return htmlfill.render(response, defaults=params, errors=errors,\n                                   **htmlfill_kwargs2)\n        return func(self, *args, **kwargs)\n    return decorator(wrapper)\n\n\ndef pylons_formencode_gettext(value):\n    \"\"\"Translates a string ``value`` using pylons gettext first and if\n    that fails, formencode gettext.\n\n    This allows to \"merge\" localized error messages from built-in\n    FormEncode's validators with application-specific validators.\n\n    \"\"\"\n    trans = pylons_gettext(value)\n    if trans == value:\n        # translation failed, try formencode\n        trans = api._stdtrans(value)\n    return trans\n\n\nclass PylonsFormEncodeState(object):\n    \"\"\"A ``state`` for FormEncode validate API that includes smart\n    ``_`` hook.\n\n    The FormEncode library used by validate() decorator has some\n    provision for localizing error messages. In particular, it looks\n    for attribute ``_`` in the application-specific state object that\n    gets passed to every ``.to_python()`` call. If it is found, the\n    ``_`` is assumed to be a gettext-like function and is called to\n    localize error messages.\n\n    One complication is that FormEncode ships with localized error\n    messages for standard validators so the user may want to re-use\n    them instead of gathering and translating everything from scratch.\n    To allow this, we pass as ``_`` a function which looks up\n    translation both in application and formencode message catalogs.\n\n    \"\"\"\n    _ = staticmethod(pylons_formencode_gettext)\n"
  },
  {
    "path": "pylons/decorators/cache.py",
    "content": "\"\"\"Caching decorator\"\"\"\nimport inspect\nimport logging\nimport time\n\nfrom decorator import decorator\nfrom paste.deploy.converters import asbool\n\nfrom pylons.decorators.util import get_pylons\n\nlog = logging.getLogger(__name__)\n\n\ndef beaker_cache(key=\"cache_default\", expire=\"never\", type=None,\n                 query_args=False,\n                 cache_headers=('content-type', 'content-length'),\n                 invalidate_on_startup=False,\n                 cache_response=True, **b_kwargs):\n    \"\"\"Cache decorator utilizing Beaker. Caches action or other\n    function that returns a pickle-able object as a result.\n\n    Optional arguments:\n\n    ``key``\n        None - No variable key, uses function name as key\n        \"cache_default\" - Uses all function arguments as the key\n        string - Use kwargs[key] as key\n        list - Use [kwargs[k] for k in list] as key\n    ``expire``\n        Time in seconds before cache expires, or the string \"never\".\n        Defaults to \"never\"\n    ``type``\n        Type of cache to use: dbm, memory, file, memcached, or None for\n        Beaker's default\n    ``query_args``\n        Uses the query arguments as the key, defaults to False\n    ``cache_headers``\n        A tuple of header names indicating response headers that\n        will also be cached.\n    ``invalidate_on_startup``\n        If True, the cache will be invalidated each time the application\n        starts or is restarted.\n    ``cache_response``\n        Determines whether the response at the time beaker_cache is used\n        should be cached or not, defaults to True.\n\n        .. note::\n            When cache_response is set to False, the cache_headers\n            argument is ignored as none of the response is cached.\n\n    If cache_enabled is set to False in the .ini file, then cache is\n    disabled globally.\n\n    \"\"\"\n    if invalidate_on_startup:\n        starttime = time.time()\n    else:\n        starttime = None\n    cache_headers = set(cache_headers)\n\n    def wrapper(func, *args, **kwargs):\n        \"\"\"Decorator wrapper\"\"\"\n        pylons = get_pylons(args)\n        log.debug(\"Wrapped with key: %s, expire: %s, type: %s, query_args: %s\",\n                  key, expire, type, query_args)\n        enabled = pylons.config.get(\"cache_enabled\", \"True\")\n        if not asbool(enabled):\n            log.debug(\"Caching disabled, skipping cache lookup\")\n            return func(*args, **kwargs)\n\n        if key:\n            key_dict = kwargs.copy()\n            key_dict.update(_make_dict_from_args(func, args))\n            if query_args:\n                key_dict.update(pylons.request.GET.mixed())\n\n            if key != \"cache_default\":\n                if isinstance(key, list):\n                    key_dict = dict((k, key_dict[k]) for k in key)\n                else:\n                    key_dict = {key: key_dict[key]}\n        else:\n            key_dict = None\n\n        self = None\n        if args:\n            self = args[0]\n        namespace, cache_key = create_cache_key(func, key_dict, self)\n\n        if type:\n            b_kwargs['type'] = type\n\n        cache_obj = getattr(pylons.app_globals, 'cache', None)\n        if not cache_obj:\n            cache_obj = getattr(pylons, 'cache', None)\n        if not cache_obj:\n            raise Exception('No CacheMiddleware or cache object on '\n                            ' app_globals was found')\n\n        my_cache = cache_obj.get_cache(namespace, **b_kwargs)\n\n        if expire == \"never\":\n            cache_expire = None\n        else:\n            cache_expire = expire\n\n        def create_func():\n            log.debug(\"Creating new cache copy with key: %s, type: %s\",\n                      cache_key, type)\n            result = func(*args, **kwargs)\n            glob_response = pylons.response\n            headers = glob_response.headerlist\n            status = glob_response.status\n            full_response = dict(headers=headers, status=status,\n                                 cookies=None, content=result)\n            return full_response\n\n        response = my_cache.get_value(cache_key, createfunc=create_func,\n                                      expiretime=cache_expire,\n                                      starttime=starttime)\n        if cache_response:\n            glob_response = pylons.response\n            glob_response.headerlist = [header for header in response['headers']\n                                        if header[0].lower() in cache_headers]\n            glob_response.status = response['status']\n\n        return response['content']\n    return decorator(wrapper)\n\n\ndef create_cache_key(func, key_dict=None, self=None):\n    \"\"\"Get a cache namespace and key used by the beaker_cache decorator.\n\n    Example::\n        from pylons import cache\n        from pylons.decorators.cache import create_cache_key\n        namespace, key = create_cache_key(MyController.some_method)\n        cache.get_cache(namespace).remove(key)\n\n    \"\"\"\n    kls = None\n    if hasattr(func, 'im_func'):\n        kls = func.im_class\n        func = func.im_func\n        cache_key = func.__name__\n    else:\n        cache_key = func.__name__\n    if key_dict:\n        cache_key += \" \" + \" \".join(\"%s=%s\" % (k, v)\n                                    for k, v in key_dict.iteritems())\n\n    if not kls and self:\n        kls = getattr(self, '__class__', None)\n\n    if kls:\n        return '%s.%s' % (kls.__module__, kls.__name__), cache_key\n    else:\n        return func.__module__, cache_key\n\n\ndef _make_dict_from_args(func, args):\n    \"\"\"Inspects function for name of args\"\"\"\n    args_keys = {}\n    for i, arg in enumerate(inspect.getargspec(func)[0]):\n        if arg != \"self\":\n            args_keys[arg] = args[i]\n    return args_keys\n"
  },
  {
    "path": "pylons/decorators/rest.py",
    "content": "\"\"\"REST decorators\"\"\"\nimport logging\n\nfrom decorator import decorator\n\nfrom pylons.controllers.util import abort\nfrom pylons.decorators.util import get_pylons\n\n__all__ = ['dispatch_on', 'restrict']\n\nlog = logging.getLogger(__name__)\n\n\ndef restrict(*methods):\n    \"\"\"Restricts access to the function depending on HTTP method\n\n    Example:\n\n    .. code-block:: python\n\n        from pylons.decorators import rest\n\n        class SomeController(BaseController):\n\n            @rest.restrict('GET')\n            def comment(self, id):\n\n    \"\"\"\n    def check_methods(func, *args, **kwargs):\n        \"\"\"Wrapper for restrict\"\"\"\n        if get_pylons(args).request.method not in methods:\n            log.debug(\"Method not allowed by restrict\")\n            abort(405, headers=[('Allow', ','.join(methods))])\n        return func(*args, **kwargs)\n    return decorator(check_methods)\n\n\ndef dispatch_on(**method_map):\n    \"\"\"Dispatches to alternate controller methods based on HTTP method\n\n    Multiple keyword arguments should be passed, with the keyword\n    corresponding to the HTTP method to dispatch on (DELETE, POST, GET,\n    etc.) and the value being the function to call. The value should be\n    a string indicating the name of the function to dispatch to.\n\n    Example:\n\n    .. code-block:: python\n\n        from pylons.decorators import rest\n\n        class SomeController(BaseController):\n\n            @rest.dispatch_on(POST='create_comment')\n            def comment(self):\n                # Do something with the comment\n\n            def create_comment(self, id):\n                # Do something if its a post to comment\n\n    \"\"\"\n    def dispatcher(func, self, *args, **kwargs):\n        \"\"\"Wrapper for dispatch_on\"\"\"\n        alt_method = method_map.get(get_pylons(args).request.method)\n        if alt_method:\n            alt_method = getattr(self, alt_method)\n            log.debug(\"Dispatching to %s instead\", alt_method)\n            return self._inspect_call(alt_method, **kwargs)\n        return func(self, *args, **kwargs)\n    return decorator(dispatcher)\n"
  },
  {
    "path": "pylons/decorators/secure.py",
    "content": "\"\"\"Security related decorators\"\"\"\nimport logging\nimport urlparse\n\nfrom decorator import decorator\ntry:\n    import webhelpers.html.secure_form as secure_form\nexcept ImportError:\n    import webhelpers.pylonslib.secure_form as secure_form\n\nfrom pylons.controllers.util import abort, redirect\nfrom pylons.decorators.util import get_pylons\n\n__all__ = ['authenticate_form', 'https']\n\nlog = logging.getLogger(__name__)\n\ncsrf_detected_message = (\n    \"Cross-site request forgery detected, request denied. See \"\n    \"http://en.wikipedia.org/wiki/Cross-site_request_forgery for more \"\n    \"information.\")\n\n\ndef authenticated_form(params):\n    submitted_token = params.get(secure_form.token_key)\n    return submitted_token is not None and \\\n        submitted_token == secure_form.authentication_token()\n\n\n@decorator\ndef authenticate_form(func, *args, **kwargs):\n    \"\"\"Decorator for authenticating a form\n\n    This decorator uses an authorization token stored in the client's\n    session for prevention of certain Cross-site request forgery (CSRF)\n    attacks (See\n    http://en.wikipedia.org/wiki/Cross-site_request_forgery for more\n    information).\n\n    For use with the ``webhelpers.html.secure_form`` helper functions.\n\n    \"\"\"\n    request = get_pylons(args).request\n    if authenticated_form(request.params):\n        try:\n            del request.POST[secure_form.token_key]\n        except KeyError:\n            del request.GET[secure_form.token_key]\n        return func(*args, **kwargs)\n    else:\n        log.warn('Cross-site request forgery detected, request denied: %r '\n                 'REMOTE_ADDR: %s' % (request, request.remote_addr))\n        abort(403, detail=csrf_detected_message)\n\n\ndef https(url_or_callable=None):\n    \"\"\"Decorator to redirect to the SSL version of a page if not\n    currently using HTTPS. Apply this decorator to controller methods\n    (actions).\n\n    Takes a url argument: either a string url, or a callable returning a\n    string url. The callable will be called with no arguments when the\n    decorated method is called. The url's scheme will be rewritten to\n    https if necessary.\n\n    Non-HTTPS POST requests are aborted (405 response code) by this\n    decorator.\n\n    Example:\n\n    .. code-block:: python\n\n        # redirect to HTTPS /pylons\n        @https('/pylons')\n        def index(self):\n            do_secure()\n\n        # redirect to HTTPS /auth/login, delaying the url() call until\n        # later (as the url object may not be functional when the\n        # decorator/method are defined)\n        @https(lambda: url(controller='auth', action='login'))\n        def login(self):\n            do_secure()\n\n        # redirect to HTTPS version of myself\n        @https()\n        def get(self):\n            do_secure()\n\n    \"\"\"\n    def wrapper(func, *args, **kwargs):\n        \"\"\"Decorator Wrapper function\"\"\"\n        request = get_pylons(args).request\n        if request.scheme.lower() == 'https':\n            return func(*args, **kwargs)\n        if request.method.upper() == 'POST':\n            # don't allow POSTs (raises an exception)\n            abort(405, headers=[('Allow', 'GET')])\n\n        if url_or_callable is None:\n            url = request.url\n        elif callable(url_or_callable):\n            url = url_or_callable()\n        else:\n            url = url_or_callable\n        # Ensure an https scheme, which also needs a host\n        parts = urlparse.urlparse(url)\n        url = urlparse.urlunparse(('https', parts[1] or request.host) +\n                                  parts[2:])\n\n        log.debug('Redirecting non-https request: %s to: %s',\n                  request.path_info, url)\n        redirect(url)\n    return decorator(wrapper)\n"
  },
  {
    "path": "pylons/decorators/util.py",
    "content": "\"\"\"Decorator internal utilities\"\"\"\nimport pylons\nfrom pylons.controllers import WSGIController\n\n\ndef get_pylons(decorator_args):\n    \"\"\"Return the `pylons` object: either the :mod`~pylons` module or\n    the :attr:`~WSGIController._py_object` equivalent, searching a\n    decorator's *args for the latter\n\n    :attr:`~WSGIController._py_object` is more efficient as it provides\n    direct access to the Pylons global variables.\n    \"\"\"\n    if decorator_args:\n        controller = decorator_args[0]\n        if isinstance(controller, WSGIController):\n            return controller._py_object\n    return pylons\n"
  },
  {
    "path": "pylons/docs/en/.gitignore",
    "content": "_build\n_themes\n"
  },
  {
    "path": "pylons/docs/en/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nPAPER         =\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n\n.PHONY: help clean html web htmlhelp latex changes linkcheck\n\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html      to make standalone HTML files\"\n\t@echo \"  web       to make files usable by Sphinx.web\"\n\t@echo \"  htmlhelp  to make HTML files and a HTML help project\"\n\t@echo \"  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  changes   to make an overview over all changed/added/deprecated items\"\n\t@echo \"  linkcheck to check all external links for integrity\"\n\nclean:\n\t-rm -rf _build/*\n\nhtml:\n\tmkdir -p _build/html _build/doctrees\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in _build/html.\"\n\nweb:\n\tmkdir -p _build/web _build/doctrees\n\t$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) _build/web\n\t@echo\n\t@echo \"Build finished; now you can run\"\n\t@echo \"  python -m sphinx.web _build/web\"\n\t@echo \"to start the server.\"\n\nhtmlhelp:\n\tmkdir -p _build/htmlhelp _build/doctrees\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in _build/htmlhelp.\"\n\nlatex:\n\tmkdir -p _build/latex _build/doctrees\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in _build/latex.\"\n\t@echo \"Run \\`make all-pdf' or \\`make all-ps' in that directory to\" \\\n\t      \"run these through (pdf)latex.\"\n\nchanges:\n\tmkdir -p _build/changes _build/doctrees\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes\n\t@echo\n\t@echo \"The overview file is in _build/changes.\"\n\nlinkcheck:\n\tmkdir -p _build/linkcheck _build/doctrees\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in _build/linkcheck/output.txt.\"\n\n"
  },
  {
    "path": "pylons/docs/en/_oldstatic/akhet.css",
    "content": "div.body h2 { font-size: 160%;  background: url(akhettransaqua.png) 10px 3px no-repeat; padding-left: 2.66em;}\npre { background: #efc url(background.png) 0 0 repeat; }\n"
  },
  {
    "path": "pylons/docs/en/_oldstatic/default.css",
    "content": "/**\n * Sphinx Doc Design\n */\n\nbody {\n    font-family: sans-serif;\n    font-size: 100%;\n    background-color: #11303d;\n    color: #000;\n    margin: 0;\n    padding: 0;\n}\n\n/* :::: LAYOUT :::: */\n\ndiv.document {\n    background-color: #1c4e63;\n}\n\ndiv.documentwrapper {\n    float: left;\n    width: 100%;\n}\n\ndiv.bodywrapper {\n    margin: 0 0 0 230px;\n}\n\ndiv.body {\n    background-color: white;\n    padding: 0 20px 30px 20px;\n}\n\ndiv.sphinxsidebarwrapper {\n    padding: 10px 5px 0 10px;\n}\n\ndiv.sphinxsidebar {\n    float: left;\n    width: 230px;\n    margin-left: -100%;\n    font-size: 90%;\n}\n\ndiv.clearer {\n    clear: both;\n}\n\ndiv.footer {\n    color: #fff;\n    width: 100%;\n    padding: 9px 0 9px 0;\n    text-align: center;\n    font-size: 75%;\n}\n\ndiv.footer a {\n    color: #fff;\n    text-decoration: underline;\n}\n\ndiv.related {\n    background-color: #133f52;\n    color: #fff;\n    width: 100%;\n    height: 30px;\n    line-height: 30px;\n    font-size: 90%;\n}\n\ndiv.related h3 {\n    display: none;\n}\n\ndiv.related ul {\n    margin: 0;\n    padding: 0 0 0 10px;\n    list-style: none;\n}\n\ndiv.related li {\n    display: inline;\n}\n\ndiv.related li.right {\n    float: right;\n    margin-right: 5px;\n}\n\ndiv.related a {\n    color: white;\n}\n\n/* ::: TOC :::: */\ndiv.sphinxsidebar h3 {\n    font-family: 'Trebuchet MS', sans-serif;\n    color: white;\n    font-size: 1.4em;\n    font-weight: normal;\n    margin: 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar h4 {\n    font-family: 'Trebuchet MS', sans-serif;\n    color: white;\n    font-size: 1.3em;\n    font-weight: normal;\n    margin: 5px 0 0 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar p {\n    color: white;\n}\n\ndiv.sphinxsidebar p.topless {\n    margin: 5px 10px 10px 10px;\n}\n\ndiv.sphinxsidebar ul {\n    margin: 10px;\n    padding: 0;\n    list-style: none;\n    color: white;\n}\n\ndiv.sphinxsidebar ul ul,\ndiv.sphinxsidebar ul.want-points {\n    margin-left: 20px;\n    list-style: square;\n}\n\ndiv.sphinxsidebar ul ul {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\ndiv.sphinxsidebar a {\n    color: #98dbcc;\n}\n\ndiv.sphinxsidebar form {\n    margin-top: 10px;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #98dbcc;\n    font-family: sans-serif;\n    font-size: 1em;\n}\n\n/* :::: MODULE CLOUD :::: */\ndiv.modulecloud {\n    margin: -5px 10px 5px 10px;\n    padding: 10px;\n    line-height: 160%;\n    border: 1px solid #cbe7e5;\n    background-color: #f2fbfd;\n}\n\ndiv.modulecloud a {\n    padding: 0 5px 0 5px;\n}\n\n/* :::: SEARCH :::: */\nul.search {\n    margin: 10px 0 0 20px;\n    padding: 0;\n}\n\nul.search li {\n    padding: 5px 0 5px 20px;\n    background-image: url(file.png);\n    background-repeat: no-repeat;\n    background-position: 0 7px;\n}\n\nul.search li a {\n    font-weight: bold;\n}\n\nul.search li div.context {\n    color: #888;\n    margin: 2px 0 0 30px;\n    text-align: left;\n}\n\nul.keywordmatches li.goodmatch a {\n    font-weight: bold;\n}\n\n/* :::: COMMON FORM STYLES :::: */\n\ndiv.actions {\n    padding: 5px 10px 5px 10px;\n    border-top: 1px solid #cbe7e5;\n    border-bottom: 1px solid #cbe7e5;\n    background-color: #e0f6f4;\n}\n\nform dl {\n    color: #333;\n}\n\nform dt {\n    clear: both;\n    float: left;\n    min-width: 110px;\n    margin-right: 10px;\n    padding-top: 2px;\n}\n\ninput#homepage {\n    display: none;\n}\n\ndiv.error {\n    margin: 5px 20px 0 0;\n    padding: 5px;\n    border: 1px solid #d00;\n    font-weight: bold;\n}\n\n/* :::: INLINE COMMENTS :::: */\n\ndiv.inlinecomments {\n    position: absolute;\n    right: 20px;\n}\n\ndiv.inlinecomments a.bubble {\n    display: block;\n    float: right;\n    background-image: url(style/comment.png);\n    background-repeat: no-repeat;\n    width: 25px;\n    height: 25px;\n    text-align: center;\n    padding-top: 3px;\n    font-size: 0.9em;\n    line-height: 14px;\n    font-weight: bold;\n    color: black;\n}\n\ndiv.inlinecomments a.bubble span {\n    display: none;\n}\n\ndiv.inlinecomments a.emptybubble {\n    background-image: url(style/nocomment.png);\n}\n\ndiv.inlinecomments a.bubble:hover {\n    background-image: url(style/hovercomment.png);\n    text-decoration: none;\n    color: #3ca0a4;\n}\n\ndiv.inlinecomments div.comments {\n    float: right;\n    margin: 25px 5px 0 0;\n    max-width: 50em;\n    min-width: 30em;\n    border: 1px solid #2eabb0;\n    background-color: #f2fbfd;\n    z-index: 150;\n}\n\ndiv#comments {\n    border: 1px solid #2eabb0;\n    margin-top: 20px;\n}\n\ndiv#comments div.nocomments {\n    padding: 10px;\n    font-weight: bold;\n}\n\ndiv.inlinecomments div.comments h3,\ndiv#comments h3 {\n    margin: 0;\n    padding: 0;\n    background-color: #2eabb0;\n    color: white;\n    border: none;\n    padding: 3px;\n}\n\ndiv.inlinecomments div.comments div.actions {\n    padding: 4px;\n    margin: 0;\n    border-top: none;\n}\n\ndiv#comments div.comment {\n    margin: 10px;\n    border: 1px solid #2eabb0;\n}\n\ndiv.inlinecomments div.comment h4,\ndiv.commentwindow div.comment h4,\ndiv#comments div.comment h4 {\n    margin: 10px 0 0 0;\n    background-color: #2eabb0;\n    color: white;\n    border: none;\n    padding: 1px 4px 1px 4px;\n}\n\ndiv#comments div.comment h4 {\n    margin: 0;\n}\n\ndiv#comments div.comment h4 a {\n    color: #d5f4f4;\n}\n\ndiv.inlinecomments div.comment div.text,\ndiv.commentwindow div.comment div.text,\ndiv#comments div.comment div.text {\n    margin: -5px 0 -5px 0;\n    padding: 0 10px 0 10px;\n}\n\ndiv.inlinecomments div.comment div.meta,\ndiv.commentwindow div.comment div.meta,\ndiv#comments div.comment div.meta {\n    text-align: right;\n    padding: 2px 10px 2px 0;\n    font-size: 95%;\n    color: #538893;\n    border-top: 1px solid #cbe7e5;\n    background-color: #e0f6f4;\n}\n\ndiv.commentwindow {\n    position: absolute;\n    width: 500px;\n    border: 1px solid #cbe7e5;\n    background-color: #f2fbfd;\n    display: none;\n    z-index: 130;\n}\n\ndiv.commentwindow h3 {\n    margin: 0;\n    background-color: #2eabb0;\n    color: white;\n    border: none;\n    padding: 5px;\n    font-size: 1.5em;\n    cursor: pointer;\n}\n\ndiv.commentwindow div.actions {\n    margin: 10px -10px 0 -10px;\n    padding: 4px 10px 4px 10px;\n    color: #538893;\n}\n\ndiv.commentwindow div.actions input {\n    border: 1px solid #2eabb0;\n    background-color: white;\n    color: #135355;\n    cursor: pointer;\n}\n\ndiv.commentwindow div.form {\n    padding: 0 10px 0 10px;\n}\n\ndiv.commentwindow div.form input,\ndiv.commentwindow div.form textarea {\n    border: 1px solid #3c9ea2;\n    background-color: white;\n    color: black;\n}\n\ndiv.commentwindow div.error {\n    margin: 10px 5px 10px 5px;\n    background-color: #fbe5dc;\n    display: none;\n}\n\ndiv.commentwindow div.form textarea {\n    width: 99%;\n}\n\ndiv.commentwindow div.preview {\n    margin: 10px 0 10px 0;\n    background-color: #70d0d4;\n    padding: 0 1px 1px 25px;\n}\n\ndiv.commentwindow div.preview h4 {\n    margin: 0 0 -5px -20px;\n    padding: 4px 0 0 4px;\n    color: white;\n    font-size: 1.3em;\n}\n\ndiv.commentwindow div.preview div.comment {\n    background-color: #f2fbfd;\n}\n\ndiv.commentwindow div.preview div.comment h4 {\n    margin: 10px 0 0 0!important;\n    padding: 1px 4px 1px 4px!important;\n    font-size: 1.2em;\n}\n\n/* :::: SUGGEST CHANGES :::: */\ndiv#suggest-changes-box input, div#suggest-changes-box textarea {\n    border: 1px solid #ccc;\n    background-color: white;\n    color: black;\n}\n\ndiv#suggest-changes-box textarea {\n    width: 99%;\n    height: 400px;\n}\n\n\n/* :::: PREVIEW :::: */\ndiv.preview {\n    background-image: url(style/preview.png);\n    padding: 0 20px 20px 20px;\n    margin-bottom: 30px;\n}\n\n\n/* :::: INDEX PAGE :::: */\n\ntable.contentstable {\n    width: 90%;\n}\n\ntable.contentstable p.biglink {\n    line-height: 150%;\n}\n\na.biglink {\n    font-size: 1.3em;\n}\n\nspan.linkdescr {\n    font-style: italic;\n    padding-top: 5px;\n    font-size: 90%;\n}\n\n/* :::: INDEX STYLES :::: */\n\ntable.indextable td {\n    text-align: left;\n    vertical-align: top;\n}\n\ntable.indextable dl, table.indextable dd {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\ntable.indextable tr.pcap {\n    height: 10px;\n}\n\ntable.indextable tr.cap {\n    margin-top: 10px;\n    background-color: #f2f2f2;\n}\n\nimg.toggler {\n    margin-right: 3px;\n    margin-top: 3px;\n    cursor: pointer;\n}\n\nform.pfform {\n    margin: 10px 0 20px 0;\n}\n\n/* :::: GLOBAL STYLES :::: */\n\n.docwarning {\n    background-color: #ffe4e4;\n    padding: 10px;\n    margin: 0 -20px 0 -20px;\n    border-bottom: 1px solid #f66;\n}\n\np.subhead {\n    font-weight: bold;\n    margin-top: 20px;\n}\n\na {\n    color: #355f7c;\n    text-decoration: none;\n}\n\na:hover {\n    text-decoration: underline;\n}\n\ndiv.body h1,\ndiv.body h2,\ndiv.body h3,\ndiv.body h4,\ndiv.body h5,\ndiv.body h6 {\n    font-family: 'Trebuchet MS', sans-serif;\n    background-color: #f2f2f2;\n    font-weight: normal;\n    color: #20435c;\n    border-bottom: 1px solid #ccc;\n    margin: 20px -20px 10px -20px;\n    padding: 3px 0 3px 10px;\n}\n\ndiv.body h1 { margin-top: 0; font-size: 200%; }\ndiv.body h2 { font-size: 160%; }\ndiv.body h3 { font-size: 140%; }\ndiv.body h4 { font-size: 120%; }\ndiv.body h5 { font-size: 110%; }\ndiv.body h6 { font-size: 100%; }\n\na.headerlink {\n    color: #c60f0f;\n    font-size: 0.8em;\n    padding: 0 4px 0 4px;\n    text-decoration: none;\n    visibility: hidden;\n}\n\nh1:hover > a.headerlink,\nh2:hover > a.headerlink,\nh3:hover > a.headerlink,\nh4:hover > a.headerlink,\nh5:hover > a.headerlink,\nh6:hover > a.headerlink,\ndt:hover > a.headerlink {\n    visibility: visible;\n}\n\na.headerlink:hover {\n    background-color: #c60f0f;\n    color: white;\n}\n\ndiv.body p, div.body dd, div.body li {\n    text-align: justify;\n    line-height: 130%;\n}\n\ndiv.body p.caption {\n    text-align: inherit;\n}\n\ndiv.body td {\n    text-align: left;\n}\n\nul.fakelist {\n    list-style: none;\n    margin: 10px 0 10px 20px;\n    padding: 0;\n}\n\n.field-list ul {\n    padding-left: 1em;\n}\n\n.first {\n    margin-top: 0 !important;\n}\n\n/* \"Footnotes\" heading */\np.rubric {\n    margin-top: 30px;\n    font-weight: bold;\n}\n\n/* \"Topics\" */\n\ndiv.topic {\n    background-color: #eee;\n    border: 1px solid #ccc;\n    padding: 0 7px 0 7px;\n    margin: 10px 0 10px 0;\n}\n\np.topic-title {\n    font-size: 1.1em;\n    font-weight: bold;\n    margin-top: 10px;\n}\n\n/* Admonitions */\n\ndiv.admonition {\n    margin-top: 10px;\n    margin-bottom: 10px;\n    padding: 7px;\n}\n\ndiv.admonition dt {\n    font-weight: bold;\n}\n\ndiv.admonition dl {\n    margin-bottom: 0;\n}\n\ndiv.admonition p {\n    display: inline;\n}\n\ndiv.seealso {\n    background-color: #ffc;\n    border: 1px solid #ff6;\n}\n\ndiv.warning {\n    background-color: #ffe4e4;\n    border: 1px solid #f66;\n}\n\ndiv.note {\n    background-color: #eee;\n    border: 1px solid #ccc;\n}\n\np.admonition-title {\n    margin: 0px 10px 5px 0px;\n    font-weight: bold;\n    display: inline;\n}\n\np.admonition-title:after {\n    content: \":\";\n}\n\ndiv.body p.centered {\n    text-align: center;\n    margin-top: 25px;\n}\n\ntable.docutils {\n    border: 0;\n}\n\ntable.docutils td, table.docutils th {\n    padding: 1px 8px 1px 0;\n    border-top: 0;\n    border-left: 0;\n    border-right: 0;\n    border-bottom: 1px solid #aaa;\n}\n\ntable.field-list td, table.field-list th {\n    border: 0 !important;\n}\n\ntable.footnote td, table.footnote th {\n    border: 0 !important;\n}\n\n.field-list ul {\n    margin: 0;\n    padding-left: 1em;\n}\n\n.field-list p {\n    margin: 0;\n}\n\ndl {\n    margin-bottom: 15px;\n    clear: both;\n}\n\ndd p {\n    margin-top: 0px;\n}\n\ndd ul, dd table {\n    margin-bottom: 10px;\n}\n\ndd {\n    margin-top: 3px;\n    margin-bottom: 10px;\n    margin-left: 30px;\n}\n\n.refcount {\n    color: #060;\n}\n\ndt:target,\n.highlight {\n    background-color: #fbe54e;\n}\n\ndl.glossary dt {\n    font-weight: bold;\n    font-size: 1.1em;\n}\n\nth {\n    text-align: left;\n    padding-right: 5px;\n}\n\npre {\n    padding: 5px;\n    background-color: #efc;\n    color: #333;\n    border: 1px solid #ac9;\n    border-left: none;\n    border-right: none;\n    overflow: auto;\n}\n\ntd.linenos pre {\n    padding: 5px 0px;\n    border: 0;\n    background-color: transparent;\n    color: #aaa;\n}\n\ntable.highlighttable {\n    margin-left: 0.5em;\n}\n\ntable.highlighttable td {\n    padding: 0 0.5em 0 0.5em;\n}\n\ntt {\n    background-color: #ecf0f3;\n    padding: 0 1px 0 1px;\n    font-size: 0.95em;\n}\n\ntt.descname {\n    background-color: transparent;\n    font-weight: bold;\n    font-size: 1.2em;\n}\n\ntt.descclassname {\n    background-color: transparent;\n}\n\ntt.xref, a tt {\n    background-color: transparent;\n    font-weight: bold;\n}\n\n.footnote:target  { background-color: #ffa }\n\nh1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {\n    background-color: transparent;\n}\n\n.optional {\n    font-size: 1.3em;\n}\n\n.versionmodified {\n    font-style: italic;\n}\n\nform.comment {\n    margin: 0;\n    padding: 10px 30px 10px 30px;\n    background-color: #eee;\n}\n\nform.comment h3 {\n    background-color: #326591;\n    color: white;\n    margin: -10px -30px 10px -30px;\n    padding: 5px;\n    font-size: 1.4em;\n}\n\nform.comment input,\nform.comment textarea {\n    border: 1px solid #ccc;\n    padding: 2px;\n    font-family: sans-serif;\n    font-size: 100%;\n}\n\nform.comment input[type=\"text\"] {\n    width: 240px;\n}\n\nform.comment textarea {\n    width: 100%;\n    height: 200px;\n    margin-bottom: 10px;\n}\n\n.system-message {\n    background-color: #fda;\n    padding: 5px;\n    border: 3px solid red;\n}\n\n/* :::: PRINT :::: */\n@media print {\n    div.document,\n    div.documentwrapper,\n    div.bodywrapper {\n        margin: 0;\n        width : 100%;\n    }\n\n    div.sphinxsidebar,\n    div.related,\n    div.footer,\n    div#comments div.new-comment-box,\n    #top-link {\n        display: none;\n    }\n}\n"
  },
  {
    "path": "pylons/docs/en/_oldstatic/pygments.css",
    "content": ".c { color: #60a0b0; font-style: italic } /* Comment */\n.err { border: 1px solid #FF0000 } /* Error */\n.k { color: #007020; font-weight: bold } /* Keyword */\n.o { color: #666666 } /* Operator */\n.cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */\n.cp { color: #007020 } /* Comment.Preproc */\n.c1 { color: #60a0b0; font-style: italic } /* Comment.Single */\n.cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */\n.gd { color: #A00000 } /* Generic.Deleted */\n.ge { font-style: italic } /* Generic.Emph */\n.gr { color: #FF0000 } /* Generic.Error */\n.gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.gi { color: #00A000 } /* Generic.Inserted */\n.go { color: #808080 } /* Generic.Output */\n.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */\n.gs { font-weight: bold } /* Generic.Strong */\n.gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.gt { color: #0040D0 } /* Generic.Traceback */\n.kc { color: #007020; font-weight: bold } /* Keyword.Constant */\n.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */\n.kp { color: #007020 } /* Keyword.Pseudo */\n.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */\n.kt { color: #902000 } /* Keyword.Type */\n.m { color: #40a070 } /* Literal.Number */\n.s { color: #4070a0 } /* Literal.String */\n.na { color: #4070a0 } /* Name.Attribute */\n.nb { color: #007020 } /* Name.Builtin */\n.nc { color: #0e84b5; font-weight: bold } /* Name.Class */\n.no { color: #60add5 } /* Name.Constant */\n.nd { color: #555555; font-weight: bold } /* Name.Decorator */\n.ni { color: #d55537; font-weight: bold } /* Name.Entity */\n.ne { color: #007020 } /* Name.Exception */\n.nf { color: #06287e } /* Name.Function */\n.nl { color: #002070; font-weight: bold } /* Name.Label */\n.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */\n.nt { color: #062873; font-weight: bold } /* Name.Tag */\n.nv { color: #bb60d5 } /* Name.Variable */\n.ow { color: #007020; font-weight: bold } /* Operator.Word */\n.w { color: #bbbbbb } /* Text.Whitespace */\n.mf { color: #40a070 } /* Literal.Number.Float */\n.mh { color: #40a070 } /* Literal.Number.Hex */\n.mi { color: #40a070 } /* Literal.Number.Integer */\n.mo { color: #40a070 } /* Literal.Number.Oct */\n.sb { color: #4070a0 } /* Literal.String.Backtick */\n.sc { color: #4070a0 } /* Literal.String.Char */\n.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */\n.s2 { color: #4070a0 } /* Literal.String.Double */\n.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */\n.sh { color: #4070a0 } /* Literal.String.Heredoc */\n.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */\n.sx { color: #c65d09 } /* Literal.String.Other */\n.sr { color: #235388 } /* Literal.String.Regex */\n.s1 { color: #4070a0 } /* Literal.String.Single */\n.ss { color: #517918 } /* Literal.String.Symbol */\n.bp { color: #007020 } /* Name.Builtin.Pseudo */\n.vc { color: #bb60d5 } /* Name.Variable.Class */\n.vg { color: #bb60d5 } /* Name.Variable.Global */\n.vi { color: #bb60d5 } /* Name.Variable.Instance */\n.il { color: #40a070 } /* Literal.Number.Integer.Long */"
  },
  {
    "path": "pylons/docs/en/_oldstatic/pylons_as_onion.ai",
    "content": "%PDF-1.5\r%\r\n1 0 obj\r<</Metadata 788 0 R/Pages 2 0 R/OCProperties<</D<</RBGroups[]/ON[24 0 R 28 0 R 32 0 R 36 0 R 40 0 R 44 0 R 48 0 R 52 0 R 56 0 R 60 0 R 68 0 R 126 0 R 161 0 R 165 0 R 169 0 R 173 0 R 177 0 R 181 0 R 185 0 R 189 0 R 193 0 R 197 0 R 205 0 R 263 0 R 298 0 R 302 0 R 306 0 R 310 0 R 314 0 R 318 0 R 322 0 R 326 0 R 330 0 R 334 0 R 342 0 R 400 0 R 425 0 R 429 0 R 433 0 R 437 0 R 441 0 R 445 0 R 449 0 R 453 0 R 457 0 R 461 0 R 469 0 R 580 0 R 611 0 R 615 0 R 619 0 R 623 0 R 627 0 R 631 0 R 635 0 R 639 0 R 643 0 R 647 0 R 655 0 R 766 0 R]/OFF[15 0 R 64 0 R 152 0 R 201 0 R 289 0 R 338 0 R 465 0 R 651 0 R]/Order 610 0 R>>/OCGs[15 0 R 24 0 R 28 0 R 32 0 R 36 0 R 40 0 R 44 0 R 48 0 R 52 0 R 56 0 R 60 0 R 64 0 R 68 0 R 126 0 R 152 0 R 161 0 R 165 0 R 169 0 R 173 0 R 177 0 R 181 0 R 185 0 R 189 0 R 193 0 R 197 0 R 201 0 R 205 0 R 263 0 R 289 0 R 298 0 R 302 0 R 306 0 R 310 0 R 314 0 R 318 0 R 322 0 R 326 0 R 330 0 R 334 0 R 338 0 R 342 0 R 400 0 R 425 0 R 429 0 R 433 0 R 437 0 R 441 0 R 445 0 R 449 0 R 453 0 R 457 0 R 461 0 R 465 0 R 469 0 R 580 0 R 611 0 R 615 0 R 619 0 R 623 0 R 627 0 R 631 0 R 635 0 R 639 0 R 643 0 R 647 0 R 651 0 R 655 0 R 766 0 R]>>/Type/Catalog>>\rendobj\r788 0 obj\r<</Subtype/XML/Length 45242/Type/Metadata>>stream\r\n<?xpacket begin=\"﻿\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 4.1-c036 46.277092, Fri Feb 23 2007 14:16:18        \">\n   <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n      <rdf:Description rdf:about=\"\"\n            xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n         <dc:format>application/pdf</dc:format>\n         <dc:title>\n            <rdf:Alt>\n               <rdf:li xml:lang=\"x-default\">Web</rdf:li>\n            </rdf:Alt>\n         </dc:title>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xap=\"http://ns.adobe.com/xap/1.0/\"\n            xmlns:xapGImg=\"http://ns.adobe.com/xap/1.0/g/img/\">\n         <xap:CreatorTool>Adobe Illustrator CS3</xap:CreatorTool>\n         <xap:CreateDate>2008-06-01T12:30:09-07:00</xap:CreateDate>\n         <xap:ModifyDate>2008-07-18T18:27:25-07:00</xap:ModifyDate>\n         <xap:MetadataDate>2008-07-18T18:27:25-07:00</xap:MetadataDate>\n         <xap:Thumbnails>\n            <rdf:Alt>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xapGImg:width>256</xapGImg:width>\n                  <xapGImg:height>180</xapGImg:height>\n                  <xapGImg:format>JPEG</xapGImg:format>\n                  <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAtAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FWK+avzR8jeU7+Kw8wag9jdToJIFNtdSK6kkfC8UToTtuAajFUnf8A5yA/KVBV&#xA;9bZR4tZXw/XBiqKsfzv/ACmvZRFB5nslc0NJmaACtOpmVAOvfFUt1f8AMbzqlxNeeWNF0zzdoMZP&#xA;GbStTElyqjassYjfevaLmcVQnl7/AJyH8pXl0bHX7a48u30bCO4+tDlbxOTQLLJRJYfnPFGPfFXq&#xA;cUsU0SSxOskUih45EIZWVhUEEbEEYquxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KsL8/8Am/zr5akiudJ8rf4h0lo/9Ilt7h1uIZeX7VukE7tGV/aQMa9QBvirz2T/&#xA;AJyauI+aS6DZ28oDUWXVGDKwH7SNaRtt3xVBy/nn501kta6dpOnXaSD4rKO2utTYigO6wvHUV/yM&#xA;VYpffmV5p0qeSSOOz0eZH4yRWWn2MLROvQTRSrcXMVCdi6jFUm1XV/zP88QmGa0v9at2qxKtcS21&#xA;SCfsWEPp916j9WKpHL5a13y+iSXlg1kUYMJL+G9t2jpUj0J7niRuNqMMVRE3nXUr6S10/X1/SCSh&#xA;k06e/driRSSNrfVE/wBJiZuyNJLH4oemKs3/ACV/MfWPKWqR6LrIdPKt5ci1jWZlIs5piPSniKfC&#xA;IZHfhKtFVW+MKnxLir6jxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2KtOxVGYKXIBIRaVNOwqQPvOKvPtV84fmy5ki0byC8QJKxXd/qFgaU/aa3hnNQfaYHFUok/Ln8z&#xA;vNRB85+ZxY2D/wB5pOkAhCrblCxCLt4SrMPfFWW+WPyr8ieWxE2n6VFJdRcSl7dD6xOCvdHk5el8&#xA;owq+2KssxVgvnv8ALjWPMFydR0bzZquhagqKsdtDcSfUDx7tbxtE3I/zB/mrdMVeDeZ7K9sb6TSP&#xA;PGlx6X5hUGfT/NWnwBoboo1ed5bW6Il3HVgGliiWePb4O5VSCGSHWdGYOvBbmN4pU2biwqjUI2NG&#xA;Gx+nFX1j+Xmuza95F0HV5253V5YwSXbD/f8A6YE3/JQNirIcVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVdirsVdirsVYb5r/NHSvLWsXGm3OmajeLYaemr6ne2ccMkNrZvJLH6soeaOZuJgcsI42o&#xA;N8VZEPMWgfpC2006larqV7F9YtLFpo1uJYqV9RISRIy0HUDFVFfN3lNtRk0xdasDqUTtHLZC6hM6&#xA;uiNKytHy5grHGzEU6AnoMVRVtrejXT2yW1/bTveW3120WOVHM1r8I9eMKTzi/eJ8Y+H4hvviqB/x&#xA;t5M/Rcmrfp7Tv0VFL9Xl1D63B9XWb/fbS8+Af/JrXFVDTvzB8m6j5muvLNlq1tNrVpFFO9qsqFmS&#xA;ZWcenv8AvCqJyfj9kFa9RirIcVdirsVdirA/zu8uW+sfl3qtzxH6Q0SGTVdNmH2lltEMjID4Sxho&#xA;29mxV87o6uiuv2WAI+R3xV7z/wA49Xvrfl6bP/q26jfW/Wu0k5ul+5bgYq9LxV2KuxV2KuxV2Kux&#xA;V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV5F+Z35Z6/5k8za9qtlHLt5ctrbSQt16Vvc39td3Nx9Vur&#xA;f1FSaJ1dFYTqUo3jWiqgfy+81T/mJLqd9HqP6MvtT0/WontJNKEFu9pbxR/V7ozKb34GiZKW7lGR&#xA;uxLVVSGz8r65pmt/l15W1XR0tJ7O41u0bzCJIJFvWuNMuyZowhM49SvOQSqp5fzdcVRdl+Xv5ial&#xA;plvpFzpn6FNh5HuvK0eovdQSpLelrVUdVhd5FilSBjyK8hvUA05KrR+XPmb9HTamdK15vMqy2zae&#xA;5uPL8f1aa1tZrdJUigEVrJAyT+nJ6i+oVAoopirOPKGhea9N89Xmp6xp8cq6zo2kxXWo2jxCCC9s&#xA;EnW4i9JmWbi7Tj0yikUG5GKvQcVdirsVdirAfzy12LTPy51O0DgXmuIdJs03qxu1KSsKf77g9R6+&#xA;2KvnoAKAAKAbADoBir2//nHVG/wlq8vDjHLrExjPZgltbxMR/s42GKvVMVdirsVdirsVdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVUJ7CxuLi2uZ7eKW4s2aS0mdFZ4XdDGzRsRVCyOykjsSM&#xA;VV8VdirsVdirsVUL7ULCwt2ub65itLdftTTusaD5sxAxVhevfnT5E0xHW0vP0zdD7EOnATISR3uK&#xA;i3FO/wAdfY4q8M80+Z9a82a4NV1UqGiVotPsIiWhtomILBCQC7vxHOQgVoKBQAMVSsgg0IofA4q+&#xA;j/yas7a1/K3yz6H2rmwivLkk1rc3Y+sXBr/xmkanh0xVmeKuxVhfmL81NL0PV9U0+bSdSu4dDtYb&#xA;7WtRtY4Ht7W3uBIVkkVpknYBYHZvTiagGKsii8z+W5dTi0mPVbRtVmiFxFp3rx/WWiK8hIIOXqce&#xA;O9eOKoYeePJRhknHmDTTDDMbaaUXkHFJ1RpDEzc6BwkbtxO9FJ7YqqP5w8pR6KmuvrdgmiSHimqN&#xA;dQi1Y1IoJy3pk1FOuKtX/nLyhp8ME9/rmn2kF1GJraWe6giSWMkKHjZ2AZSXAqNtxiqJuvMGgWl/&#xA;a6ddala2+oX29jZyzxpNOP8AiqNmDP8A7EYqusNd0TUbm7tdP1C2vLmwf0r6C3mjlkgk3+CVUJKN&#xA;sdmxVG4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXiX/OVHmTzN5f8r6Ne6Fqlxpkkl80M7W0jRs6tCzA&#xA;EqRsOGKQy78htd1LXfyo0LU9TuXu7+UXK3FxKxeRjFdSxqWY714qMUFn+Kqdzc21rbyXNzKkFvCp&#xA;eaaVgiIqipZmagAHicVeZeZfz88vWbNb+XrZ9buAafWam3sgQaGkzKzyeIMcbKf5hirEINY/Obz0&#xA;5+qXMtpYMQG/R6/UbdSux/0klrgtvuFl/wBjiqY6Z+SGjvKb3WtQk1O7FXmezX1DyG7Fr65qpI78&#xA;qHFWTWPkTyZbxg2ujR3dKn6zPNLcdNzz48bTYdR6oH04qnFgq21W0+G0sIT8Pq2kUdtH8nkSK9h6&#xA;0p+8HyxVD+bvLUPmbTLzTryCMa/bRGWwukA5MUoePLaqtyCkmg3qBVSAqlP/ADj5rS3PkybQ5DS6&#xA;0C7mtypPxG3nY3Nu3yCymP8A2BxV6firsVePeffyt17X9c87anbLOktzpmmjQI0uzHa3l1Zm5kkt&#xA;7u2EixTRsxjT/SE40Y0/axVLrT8t/OEnma6fV7bUprC51s6/CbSXRltV5EOlvPJIg1ENGn+jsI3Z&#xA;Sg+FgDiqTahoHmfQ7fytYXOhzTaHaeZ9OHlzQ9QmsJL3jBp1+ZImnty0DIhCGD1X5bfEw64qyK08&#xA;k+cLTzOnnX/D/qWz6neXn+DY57T1YRc2NvaJdK7SLaGcvbOzgS9JDRia4q7y3+VfmC01KKbUNOgN&#xA;rJouvxpah4pIbK41XUY7m3s4+VDRIWdS6jj9oVoRVV2m+R/PFjN5Qk0+wubHWItJ0jTfMuoyT2U9&#xA;iYLSEidGjZ3ufrMLu/pSQ/CT1YjFUf8Ak35A8xeXb6F9cS/W50zS/wBEpLI+mGwmUTLJztxaJHdt&#xA;8SFg118Q5NWpJOKvWsVdirsVdirsVdirsVdirsVdirsVdirxn/nLHTWu/wAqfrCio07ULa4Y+AYP&#xA;b/rnGKQs/wCcTNUW7/K57Tl8enahPDx7hZFSYH6TIcVLKvzD/N3SvK8j6Xp8a6p5hCgtaK/GK3DC&#xA;qtcyANxqNxGBzbbop5YoeLalqnm/zxqkMOoTSancu9bXT4VKW0bAkgxwAlQVqfjcswH7VMVeo+U/&#xA;yh0zTDFPrqjU9VYB005P95469DKx+1077dQA2Ks6nMXp+nJ6cyRkRCIAi0iI2EaxLvO4pslOo24Y&#xA;qo+neXstET1XjanOXgRGynoBxeGIqRQcVlehoxXFXGwspJSLieTUbmNqGCCrcGU13kdnMLct9pEB&#xA;p0xVEyxWEdjcXlvai2urL45gVX1TwAlaN3Uty9SM7nketeuKoVw1s9nPv/oTyW8i9WZYeQi5DrX6&#xA;s8jinUkeOKvMtRcflr+bMWsE8fLPmMeheSA0ijSWTlHIei/6PM/0RyE4q9xxV2KuxV2KqFzYWN09&#xA;u91bxTvaSie1aVFcxTBWQSRlgeL8HZeQ3oSO+KoVNdsJNfl0KNud9b2yXdwBSkccrlIg29auUYj2&#xA;HyxVMcVdirsVdirsVdirsVdirsVdirsVdirsVdirsVYt+afl1vMf5d+YNHRec1xZyNbJ4zw/voR/&#xA;yMjXFXyP+Sv5l635WtNd0bSeK3esrC1tdyUZbVoeYklWM7O5R6KDtWhNQCCpLLvLPlnU9b1NdP09&#xA;XuLu4dpbm5lYsSWNZJ55DUkkmrMdyffFD6H8peTNM8r2v1LTQJtTlUfXdRdfiAO/TsP5U+k4qmsk&#xA;kaxmKAkxOSXkqA87gUcl/wBlAPtP26L2xVSSFSEkmJMbD07eGIcXkH++4l/3XF471OxZgopiqOSw&#xA;eVFW64rAoCpYxbRADYBiAC+3b7P+TtXFUaiJGioihEQBVVRQADYAAYqgwqrq0yOBwubdCq9QxiZh&#xA;JUfKVB/tYqlsEDgNZl+Lv+5Ejb8bq1o0EhH7TSRBXI6fDTFUi84eWIPNXk+80cwg3MCevp8bbkbM&#xA;jW5O3Qh4j7cTiqB/Ivzjcaz5bk0PUpGk1ny8UtpZJDV5rVgfqs7E9WKoY3PUuhPfFXpWKuxV2KsY&#xA;/MX8wNE8i+Wp9b1RgzKOFlZhgJLicj4Y0r97HsN8VeZf84wXWseYT5v88aw3qXmt30UAalAq20Zb&#xA;hHXcIonVR/q4pL3TFDsVdirsVdirsVdirsVdirsVdirsVdirsVdiqXeY9esPL+hX+tX7EWmnwvPK&#xA;FpybiNkQHqzmiqO5OKvgDWZLvSPNzaiYEtjNKbxbaH+6RZiS8KE/spUoPbFk+1/IGn6DoXk6wutM&#xA;nhnk1eKO4bUW2R/UUMGYkgiOMGgXbfbZmxYsknaONGtIyzqCBdOCPVmldQREDt8TChZtgq+A3VVS&#xA;jVSPVmAkQsI1RP8Ad0grSOMGn7qP8aFjsKlVMI0W3Rrq7cGYgeo4qQo7Ig60r9JOKrfQnu97qsdu&#xA;elqCPjH/ABcf+NBt48gcVa09VgnurNQEjjZZII16LFIvbw/eJJt/CmKt6h+7ltLnoIplSQj7RSYG&#xA;IL8vUZGI9q9QMVQWp/uLi4m+yFijvEp1LWr/AL/5F4mVK9xt0xV0/wDouoSSDZYnSfwAiuf3Uy+A&#xA;VHQTO33064q8k1eM+R/z00/Uovg03XXFpdAdPT1Bwq16AcL1EPshPjir3TFXYq89/M787/J3kK3k&#xA;huJhqGucf3Oj27AyVIqDM24hXfq29OgOK0+NfPfn/wA0eftf/SWsSmWUn07KyhB9KFGbaOJNzuep&#xA;NWbviyfb/wCVHk7/AAf+X+j6E4AuoYfVviN63ExMkoqOvFm4j2AxYstxV2KuxV2KuxV2KuxV2Kux&#xA;V2KuxV2KuxV2KuxV5F/zkXq7JpOiaAjEfpO8a6uVHRrfT1D8T/0cywN9GKvJT+Ut7568r6xfaca6&#xA;poyq1hAKVndqtJDXsSi/D/lU7VxSHnen/mlr+n/l3qXkeQyenPLCbS45FZLaOOYzTQqOoEkgVvvr&#xA;Wuyl9P8A5M/mVa+e/LdurzLDrtino6lAGo6j7U98OlPXLcR/Kxam1cWJen6fEsnG6KBE48LOICgj&#xA;h2pt2L0r7Cg7YqtWWOdjfTNxtISfq1ejdjL716J7b78hRVs310JYZHhEVpK4jq/94OQPByBsoLUU&#xA;L1+LelKYquuv3eo2Uo6ymS3YexQyg/QYqD5nFXav/vLH/wAxNr/1ER4qtukRtTthKoaGSC4hIYVV&#xA;mcxtwIPisbfdiqChQXFrpLXJMiXdo1tLUnkWmiWQsT8oW+k4q82/PrS59S8labqatw1CEtbvIo4s&#xA;kzpWtR0Mc0P0HFUL5r/5yXOgaNpl+3lLUJBqlpDc293O0cNm5miElI5ozcV413VgrDuBimniPnL/&#xA;AJyY/M3zEklvbXSaHYvUelpwKSlT05XDFpK/6hX5Ypp5VJI8jtJIxeRyWd2NSSdyST3xV7f/AM4v&#xA;fldJ5g8zDzXqUP8AuG0SQNa8x8M16N0A9odnP+Vx98UF9hYodirsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVdirwD/nIG4kfz1o1s393Bpc8kfX7U1wgf2/3SuKoeD8l9N80/lomvWty2l+ZYvrM1pqUB&#xA;ZS8cTFfRn40JXlCeJBqta+IxS+d/PHkDzf5P1R7TzFZvDKxLJdg+pDMCT8aSjY8qHrv4jFKB8rea&#xA;tc8r6vHquj3BguVBSRescsTfbilX9pG7j+O+Kvsv8tfzv8vfmHYxafEw03zFJ8N5p7tQ8ApaSS3c&#xA;05ggUFPiWtSKCpUU9EtkW5cTAAWkJ4WkYHwnjt6ny7J7b9xRQrajA89jNFHT1ipMJOwEi/FG30OA&#xA;cVQ95PHPYWl3FUB5baSJjswEsiKfvRyD88VVNW/3lj/5iLX/AKiI8VdcfHqlnEfsok048eacIx9H&#xA;GZsVSo6hYWGk6BcX1zFawKELTTusaAfU5OrMQMVeVfmn+cX5ZDyfqOixavFqOqNctLbR2INwm9z6&#xA;3ITJ+5/u2I+3imnisv8AzkD5li8hw+TNNs7WKxiE0cl3dRrdSPDJO8iRiOUNCoRHCbq3SoIxWnlr&#xA;K9AxBAatDSgNOtMUs0/Kr8rdb/MHzCmn2YaDTYCr6nqRWqQRHsK7NI1KIv09ATir7t8ueXtJ8uaJ&#xA;Z6JpEAt9PsYxHBGOviWY92ZiWY9ycWKY4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXgP8A&#xA;zkFAyeedEnP2Z9MuIwfeG4jJ/wCTwxVnv5bTRv8AlIqKatDDfJIN9mMkrgf8C4OKsi8wWlpeW+t2&#xA;93DHcW76cnOGVQ6GhuCKqwIOKvLtU/5xo/LXzDd3Rtop9FnQysWsnHpsWuZY0/dSiRVVVh6Jxr+t&#xA;TbANR/5xN8wWd+X8veZIZJ4LhI7VriOS1kEvATcg8RmpwU8uWx2NBWlVbevfl7F+eOgLBpPmq1sN&#xA;e02ICOPUrO5EdzGi7DkkiRLKKDavE+JOKsu/MnU7nS/y98yahayPDd22mXb200Zo6SiFvTdT4q1D&#xA;ih8TRfnZ+asccUa+ZLv04eHpo3BlHpkFNmUjYqMWVL7n88vzZuTWbzNdHdWovpotUIZTRVA2Irit&#xA;ICX8x/zQ1aYIfMWr3MtCBHFcz1ozAkcY2G3IL+GKusvy8/M3zBLC8Oh6ndmeiQXE0Uqxt8PIASzc&#xA;U+yK/a6YqyuL/nGz8w4tJv8AVNX+q6XBpwrPDJKJpiSqsAoh5x9HHV8UWzn/AJx+/J/yPq+oa0df&#xA;tTqtzpLWrW6SsVg4XCOatEp+I8om2Yke2K2r+Zvym1n80vzRuns4V0XyJoQTS7W8SIRo6WzH1ktI&#xA;gFVv37SDkPgHv0Kr6E8peUNA8p6JBo2h2q2tnCKmm7yPQBpJW/adqbn+GKE5xV2KuxV2KuxV2Kux&#xA;V2KuxV2KuxV2KuxV2KuxV2KuxV41/wA5H6Y/1by3ri1KWl1NYTU/ZS/jDqx9vVtY1+bDFUb+SF2l&#xA;95X1jRC3CRJGYP1olzHw+zt9loyevfFWeStJewzMiUl1TTAYYwQaMgaqljx73K0+npirtAmie9ui&#xA;rVEih0qCOSvNNOCK9f3dxGT4chXfFV//AEtf+3j/AN27FU5xV51Bput6b+Ynmlr3Xbq9sdfsLebQ&#xA;9Km4/V4JEf6rMqLQ09N5ITVeNRJ8YZgGxVjNovn9tI82xXWgaRq3mfy7dznQrFIUWNraSKJrRSSA&#xA;ZE9KaUqKhmZOLMDviqYXnm+x0nRPK3mQeUI72TWjp1ldRaakIW3l1VElYlnUcgv7tUrRSWoXGKp2&#xA;35heWB5u1vyfbPLBrcFj60TJE0dukQb0lHqiiqwuJjVjRdx8VcVR+kfmH5E13T7DWNL1e1/QcM0s&#xA;Qu3b6vGs8ZW2WAiUR8S31kFQRvtTriqzz9IF8k+Z5RukjBVbsaLDE1Pk6kfMYqwD/nHP/lI/No7f&#xA;U9INPf1dQ/pir3MAAAAUA2AGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KpB5+8r&#xA;J5q8napoJYRy3kP+izHpHcxES28hp/JMit9GKvB/yZ80vpnmi1N4pthectP1GB9jDcB+BRqnYxzp&#xA;xb2rir36X/RJ3Y7LaytdA9C1vPX16t34SMZCKdl74qg7P/cfriwttHVoVHYK/ARkHrQKkEQr1bl4&#xA;Yqj7yGVb9zCP3jiO6t1FBykhPCYVOwLwsqCvzxVFfprSBs17Cjd0eRUcHwZWIZSO4IxVjPmyX6vq&#xA;vl/zPIjRWmm3n1OXkh9VodTX6rXh9sD6y1vtSux26Yq7lcaV53W5dKz+ZbFo/RJ+FbjT5OUMfIVG&#xA;8N1IXP8AxWT4DFUv0/SXbydrnkqNwb+1ubqzsZSAvD6zS+tp1A2C263C07ckoN8VU5L2xuofKHmy&#xA;2t1ijtktodTZv7xbfUQsSW8h3r6N00czhvs8K964qld5+XHkfU9V1TyhrOnR/wCF9RkGq6HbxsYE&#xA;hubQ+nqCQ+nw9Ic5A9Afi5P+yuyqWef9T83aL+Xi6NeW8F5FfTILbUTOIp5YWf61+9t1iCpIh+By&#xA;h4nqAvLiFUt/5x9PmaOTzPqdppMVyk09rYsWuhFxa1haagPpty/3sxVlPnfUP+cgLfXY77yjpVrd&#xA;6d9VgR9Kubi29EXLSzeu5Yi3nbjGI6ESqB/I25VVINM86f8AOTOrypcW3li2tdOd4kla6tltZk9I&#xA;8rgpb3F+sjct40JNHHFh6e+KprqOtf8AOQt9p80OmafY2+qWlxY28rIixITc6ZJJesfrUkyvHa3V&#xA;xBwMLHmY2FTVlCren+Y/+ckRHf8A1ryvp5W3jMen83g9e4k9CRllk9O/9JVE0aIy/DyD8hx4lcVQ&#xA;2j+d/wDnIvVryEReU7GxsfrrWt/PfRPDJbxhYC0kcT3iG5RGklCyIQJAteKHbFXtGKuxV2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2Kvm/85vKreXfPB1a3ThpPmY+ryAosepRr+9TYbevGokHiyvir1b8&#xA;vPNh8zeX4XLg67pQCXCsSDKvGgLE9pQN/BxWmwxVM721R4YhFULHVbc0IYJHWsZpv6kPxBaVPDkV&#xA;q2+Ko2PU7e4tkF3J9WuISGW5anph6bEsDxHJW3BI5A/CStGxVGJPqrIrRxW0yMAVmWd1Dg9GCiJ6&#xA;V605H5nFUk8xWQ17Q9Q05LgXd7cwSRWrW4Ho28xU+nKzEsvON6NVjXb4VxVJ9X1eG68q+X/Ostfr&#xA;tvNaakLfvDDMvoXsSrXb0be5lLk/tL8VABRVMJWm0zz/ABTOqvceYtPeGOMUCJNp8gdE5dfiiunZ&#xA;2pv6f+quKoTT9MjksPM/kmVv3lxcTssqgB/quqJ673Pt6c0s0cY/yFHToq3HaXPmjypocMMqWWt2&#xA;Lq9xM0ZmjgntC9nexOivEzpKwmg+2pIJYGq4q8d/N3zP5g1HWpIZ9VsZ7LRldBNBZTRxltjM3Frq&#xA;UmhXjWvbFXqP5WeTvPWgeSrGAajp1pc3nK/vYJtNnklSa6PqNG7rfRAmJSI/s9F79cVXebvKf5tX&#xA;ev2WqaBr0Ft6FkYbuP15ra3mnBl9MpZvDqEMY/eq0kj+o7cFVeAqWVSuw8sf85HW9nZRTeaNNuLj&#xA;6xHNqU78d0EkjzRQr+j9kkWRVFd19P4T8dEVTW68s/m1FeTvpWrQQxzXN9LNNLeyytLHLIWslWC5&#xA;s7uG19CJvSpDty4yN6lDGyqSv5B/PebyjHplx5ttf0pa3VnNaXcclzG3oW9k0c0U08aRSTepdFX+&#xA;MEEbsCP3eKrLfyV/zkZLf6Lc6h5ysg1qCmqNa0RJI5JauUtzZ+k8qxCivJtXoq0ZnVT3yx5e/OuG&#xA;/wBFm8z+YbS9itJnfVUsykMc0TR3Cqoi+pKzMryQmvrKpC/ZDDk6r0nFXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYqkXnbyhp3m3y3d6HfExrOA9vdIKyQXEZ5RTJ0+JHANO4qDsTir5x0TVvM3kjzU8F&#xA;3GLbW9NIS9tgSYbiFukiH9qGYCqnqDsaMpxV9C6DruleatM/SGlSKJiFF5ZSNRlcbqH4/EjDj8Ei&#xA;+HemyqyRJIbkAh0mNeKGqynqxC+l8TDufT5r3aOtTiq6O3SSsxt4Z0ZiZbpraG8q56gG3MMh/wBl&#xA;FWvXFUcL25YBZLmaNB0NvYTo3yrKJlp/scVY15f0lp4PNHlSW0EFu884eW5bnM1nqiGfohYMolln&#xA;jX94KcenbFUFLqkn+CNL1x63OvaBPDca1NUsI5LMvZ6mXY9AkT3HFBv3ApU4qnd67aX5606aN/rF&#xA;xrVrLp92K0X6xBW7tKip9NFi+tUHU+5qSqwf8ydYXyy99ZaBr95Bq2qSm4v7e3WyMELSIFkYGS3l&#xA;lRnpUKJNiS3U7qsG/K/8tL/zdrTXNxqd0mhaVIr3E4S1Jlu0KyRwIHgZGCGjy8lIpRaHkaKvoH/D&#xA;Otf9TZqv/IrSv+yHFXnnnXyjaf41k1C589T6Pcro8dveXZtfRkROV0ttNcanbG0hgRp5qiBuCytE&#xA;uzEbKoLRdF8v3cWuWL/mqdRdZ9Njike6aUWbw3cNwjILy6uoZpbh0ROfEqJOSqvWPFWO2ekafpeq&#xA;Jp7fnPLZ2+lRPaDSpI7uztkNoj2E3qubyIDlLZOaK6UNWi4lg2Kqn5aaH5U8v3uhyw/m691oNgJC&#xA;dKYy6fY3E3JbpgztcBA6/pGDlG3JjurA0ZVVe3/8rB8hUnP+JdKpbCtz/ptv+7HNYvj+P4f3kipv&#xA;+0QOpxVObK9s760ivLKeO6tLhRJBcwuskbo24ZHUlWB8RiqtirsVdirsVdirsVdirsVdirsVdirs&#xA;VdiqQ+c9K806lo/o+WNc/QOqxuJEuTbw3McigEGKRJleitX7S7incVBVeWeZfzD/ADe8hWcP+Ir3&#xA;yxqtwxUR2MLXa6jMrNTmqJGkQVdyWKKvvWlVXmP5k/mZrXnRbUy6fY2V5p7CWC4tg5vOFfjiEztw&#xA;9OQfstGRyAPbFUz0hfN+i2kHmjRne90sg8da0tWkVOO7xXtr+8lt3Sn7xHDIP5zir0Xy7+fdhfWq&#xA;w6/Yx3Vu+xu7MrJG1KU5ROSOoqSG+jFWZWOveQtWb1tO1tLe4oPhkkMUh8F/fcZuA6FY3AxVPFsN&#xA;dRQYdQE8TCqAFYwo/wBeRLt3r7t9/ZVjt9Y6naed9NubkLJHrVtLpkrPcNxaa25XdsrRxRQK6iI3&#xA;R4t18RiqWDVvLOkXnmby7r2qww6dI63KWNqoRWgv4mSeLgpmkB9eCZmCkU579RirzLWvzdsdR8o2&#xA;GgKsME2n8VvNRlkEc7XVsDE88YUqYy5Vm5EkkN2xVJvJvkLS/Nd4Li91SLS9F51ub+e843M/crbJ&#xA;JJX4v9/OOP8ALz3oq930/QPyi06zisrG8tbe1gHGKGPVJQoFan/d/Uk1J7nFUR9Q/K//AKuUH/cV&#xA;l/6r4qxvzrP+TUd0NJ8zC5i03UdOt4v0it7dpZXcJvCkVtyt7gSXDxzSlmPBljV/idQ1Cqkkb/8A&#xA;OM0sdhZehLcwAeramddWm4CCGzlUN63KTglvHAdxwREIbiAwxVD6/ef8432yab5mbTrm5Pma5u9S&#xA;stRs5L23mlvYLqGGdqNNbTJIJJ+ajiAFV2FP2lUt+vf84vvFZ2UWgXl3DbrPrVlEyX3pkpbPLcsj&#xA;XEyI4RdMEbCpjL0C1/ecVVaKX/nD+Gy9KFoxaXlpJF6Kfpgq9rFKkkr8BX/dlqvKWlW4bsaHFXqf&#xA;5e+avyyka48l+TbqMP5bDQzaYiToYVSVkajTqPUHqVqwZuta7iqrNcVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVWXEXrQSQ82j9RWT1IzxdeQpVT2I7HFXhnnb8pPKXlmJb610HXfOOqX7MCguZmX1BT97&#xA;eTwBbj9rY/FXvTrirAP+VGfmneW9zrVrolpp9zNJF/uNDwwyvEpHwxpzZEVUr8U0pkLfaqTyxVjl&#xA;rrPmryTr+p/Ubx9J1SwdYb4WksdxFK6oCY5o6PBIYyxQ1qVbkAwocVZz5t1y9sb+CL8yfINrDql+&#xA;rTQ6xpN0thcyhCquX9CS5SZ0Lr8MsnHfYYq1oXlvyb5mufqvlvzZJY6jJ/caL5htUW4dv5Y7i3eK&#xA;GTxpGJGHfFU5m/Jv80bJK262Nwpr8Freyq23iJYYV3r/ADYqkfmj8t/zTj0ibUbuwb09NH16V2vI&#xA;5CEt/jkoqs7MTEGXYV3xVG3X5K+brO+0/UNQnt4bCcPb3EumQXeryoHT1Y3aCGKBuPKPhyUkAvir&#xA;NPLfkb8rNJmS7vdP1fXL9aMJtQ0bUnjVgOqW62ixbHdSysw/mxVnH+IvKH/Vqvv+4FqX/ZJirv8A&#xA;EXlD/q1X3/cC1L/skxV3+IvKH/Vqvv8AuBal/wBkmKsF87/mX5D0TzZBDq3lGO8tRp8Fwmqy2yQ3&#xA;SVmnljtxFew26pxe1Mio06uzfYjY4qkw/NT8iY9Rht08kxcPVs4YLhNP02qXc6V9MqZFZDbCNVlb&#xA;pGw4mm1VXaz+cf5aWWo6LpP+B4rnSp47SbT5hbW5WC31a1+sTcIVjdFkAkiV41f4+da7bqpUfzo/&#xA;J2yvrFo/y9s1iuP0r9ZuLeHTJZY4LRJULRpB6nqi4jUqxDCLcqJHo1FUe/50/wDOP9xYpFdeSpFt&#xA;FRIY4LjSLEL6R9a4hVI2fdGkWbjxFFfkW41JxV6h+XGreTdcGs6noGgjRry2v5tN1ZpLW3t55Lm3&#xA;4vJyeBpBKoaT7XI71+eKszxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KvPPPn5G+RvNWnmK&#xA;Czh0TUVd5E1GwgijdjJX1EnVQvrRuWqwJrXcEHFUHe/kD5d1pLF/NGq6jrV3p+lxaXayNIkMcTQq&#xA;FF3CiqXE5NWLSSOKncGgoqwO3/5xa1NNRuLO71KyvNCuecn18RPBqMM/H93IiqJI5BzUB43k4EVK&#xA;qj74qmPl/wA4/m3+XepjQfOGkX/mbQlbha6xZRS3c4Qn4WWRQ5lG28UxEq9mcUqq91UwXdoCyFoL&#xA;iPeOVGQlHH2XjcKy7HdWFfHFWKeXrjzbo+i2mkTaFNenTY/qcd6t1bD14rcmKKYh3DBpI1Vmr3OK&#xA;ph+nvM3/AFLM/wD0lWn/AFUxV36e8zf9SzP/ANJVp/1UxV36e8zf9SzP/wBJVp/1UxV36e8zf9Sz&#xA;P/0lWn/VTFWKebfPn5kaJfXV9b+XrefQrWzsgthK7x31xqWoXb2sUFvcKZLVgremXFOXxDxpiqSw&#xA;fnV+ZEen2klz+Wuoz3LQTNd+it5GFmhiDKgjezdh6z/ZozBQR8TNyVVUdr/5vectH80w6efJtzca&#xA;Xfi3isLmk6M1yLRry8SqQz8uCvFGnJI15LJyeiPwVZt+X3mm781+TtM8w3WmvpEuoxtKLCRmdkTm&#xA;yxsGeOFmWRAHU8BsfDfFWQ4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FWmVWFGAIqDQ77g1B+g4q3irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVf//Z</xapGImg:image>\n               </rdf:li>\n            </rdf:Alt>\n         </xap:Thumbnails>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n            xmlns:stRef=\"http://ns.adobe.com/xap/1.0/sType/ResourceRef#\">\n         <xapMM:DocumentID>uuid:D1901A446631DD11B693883DCB3DE232</xapMM:DocumentID>\n         <xapMM:InstanceID>uuid:8b042820-52bd-2b40-8c3d-932332e9814c</xapMM:InstanceID>\n         <xapMM:DerivedFrom rdf:parseType=\"Resource\">\n            <stRef:instanceID>uuid:CE901A446631DD11B693883DCB3DE232</stRef:instanceID>\n            <stRef:documentID>uuid:CD901A446631DD11B693883DCB3DE232</stRef:documentID>\n         </xapMM:DerivedFrom>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:illustrator=\"http://ns.adobe.com/illustrator/1.0/\">\n         <illustrator:Type>Document</illustrator:Type>\n         <illustrator:StartupProfile>Web</illustrator:StartupProfile>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xapTPg=\"http://ns.adobe.com/xap/1.0/t/pg/\"\n            xmlns:stDim=\"http://ns.adobe.com/xap/1.0/sType/Dimensions#\"\n            xmlns:stFnt=\"http://ns.adobe.com/xap/1.0/sType/Font#\"\n            xmlns:xapG=\"http://ns.adobe.com/xap/1.0/g/\">\n         <xapTPg:NPages>1</xapTPg:NPages>\n         <xapTPg:HasVisibleTransparency>False</xapTPg:HasVisibleTransparency>\n         <xapTPg:HasVisibleOverprint>False</xapTPg:HasVisibleOverprint>\n         <xapTPg:MaxPageSize rdf:parseType=\"Resource\">\n            <stDim:w>14400.000000</stDim:w>\n            <stDim:h>14400.000000</stDim:h>\n            <stDim:unit>Pixels</stDim:unit>\n         </xapTPg:MaxPageSize>\n         <xapTPg:Fonts>\n            <rdf:Bag>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stFnt:fontName>MyriadPro-Regular</stFnt:fontName>\n                  <stFnt:fontFamily>Myriad Pro</stFnt:fontFamily>\n                  <stFnt:fontFace>Regular</stFnt:fontFace>\n                  <stFnt:fontType>Open Type</stFnt:fontType>\n                  <stFnt:versionString>Version 2.007;PS 002.000;Core 1.0.38;makeotf.lib1.7.9032</stFnt:versionString>\n                  <stFnt:composite>False</stFnt:composite>\n                  <stFnt:fontFileName>MyriadPro-Regular.otf</stFnt:fontFileName>\n               </rdf:li>\n            </rdf:Bag>\n         </xapTPg:Fonts>\n         <xapTPg:PlateNames>\n            <rdf:Seq>\n               <rdf:li>Cyan</rdf:li>\n               <rdf:li>Magenta</rdf:li>\n               <rdf:li>Yellow</rdf:li>\n               <rdf:li>Black</rdf:li>\n            </rdf:Seq>\n         </xapTPg:PlateNames>\n         <xapTPg:SwatchGroups>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xapG:groupName>Default Swatch Group</xapG:groupName>\n                  <xapG:groupType>0</xapG:groupType>\n                  <xapG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>White</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>255</xapG:red>\n                           <xapG:green>255</xapG:green>\n                           <xapG:blue>255</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>Black</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>0</xapG:green>\n                           <xapG:blue>0</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Red</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>255</xapG:red>\n                           <xapG:green>0</xapG:green>\n                           <xapG:blue>0</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Yellow</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>255</xapG:red>\n                           <xapG:green>255</xapG:green>\n                           <xapG:blue>0</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Green</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>255</xapG:green>\n                           <xapG:blue>0</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Cyan</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>255</xapG:green>\n                           <xapG:blue>255</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Blue</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>0</xapG:green>\n                           <xapG:blue>255</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>RGB Magenta</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>255</xapG:red>\n                           <xapG:green>0</xapG:green>\n                           <xapG:blue>255</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=193 G=39 B=45</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>193</xapG:red>\n                           <xapG:green>39</xapG:green>\n                           <xapG:blue>45</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=237 G=28 B=36</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>237</xapG:red>\n                           <xapG:green>28</xapG:green>\n                           <xapG:blue>36</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=241 G=90 B=36</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>241</xapG:red>\n                           <xapG:green>90</xapG:green>\n                           <xapG:blue>36</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=247 G=147 B=30</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>247</xapG:red>\n                           <xapG:green>147</xapG:green>\n                           <xapG:blue>30</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=251 G=176 B=59</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>251</xapG:red>\n                           <xapG:green>176</xapG:green>\n                           <xapG:blue>59</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=252 G=238 B=33</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>252</xapG:red>\n                           <xapG:green>238</xapG:green>\n                           <xapG:blue>33</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=217 G=224 B=33</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>217</xapG:red>\n                           <xapG:green>224</xapG:green>\n                           <xapG:blue>33</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=140 G=198 B=63</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>140</xapG:red>\n                           <xapG:green>198</xapG:green>\n                           <xapG:blue>63</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=57 G=181 B=74</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>57</xapG:red>\n                           <xapG:green>181</xapG:green>\n                           <xapG:blue>74</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=0 G=146 B=69</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>146</xapG:green>\n                           <xapG:blue>69</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=0 G=104 B=55</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>104</xapG:green>\n                           <xapG:blue>55</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=34 G=181 B=115</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>34</xapG:red>\n                           <xapG:green>181</xapG:green>\n                           <xapG:blue>115</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=0 G=169 B=157</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>169</xapG:green>\n                           <xapG:blue>157</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=41 G=171 B=226</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>41</xapG:red>\n                           <xapG:green>171</xapG:green>\n                           <xapG:blue>226</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=0 G=113 B=188</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>113</xapG:green>\n                           <xapG:blue>188</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=46 G=49 B=146</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>46</xapG:red>\n                           <xapG:green>49</xapG:green>\n                           <xapG:blue>146</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=27 G=20 B=100</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>27</xapG:red>\n                           <xapG:green>20</xapG:green>\n                           <xapG:blue>100</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=102 G=45 B=145</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>102</xapG:red>\n                           <xapG:green>45</xapG:green>\n                           <xapG:blue>145</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=147 G=39 B=143</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>147</xapG:red>\n                           <xapG:green>39</xapG:green>\n                           <xapG:blue>143</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=158 G=0 B=93</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>158</xapG:red>\n                           <xapG:green>0</xapG:green>\n                           <xapG:blue>93</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=212 G=20 B=90</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>212</xapG:red>\n                           <xapG:green>20</xapG:green>\n                           <xapG:blue>90</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=237 G=30 B=121</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>237</xapG:red>\n                           <xapG:green>30</xapG:green>\n                           <xapG:blue>121</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=199 G=178 B=153</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>199</xapG:red>\n                           <xapG:green>178</xapG:green>\n                           <xapG:blue>153</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=153 G=134 B=117</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>153</xapG:red>\n                           <xapG:green>134</xapG:green>\n                           <xapG:blue>117</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=115 G=99 B=87</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>115</xapG:red>\n                           <xapG:green>99</xapG:green>\n                           <xapG:blue>87</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=83 G=71 B=65</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>83</xapG:red>\n                           <xapG:green>71</xapG:green>\n                           <xapG:blue>65</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=198 G=156 B=109</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>198</xapG:red>\n                           <xapG:green>156</xapG:green>\n                           <xapG:blue>109</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=166 G=124 B=82</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>166</xapG:red>\n                           <xapG:green>124</xapG:green>\n                           <xapG:blue>82</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=140 G=98 B=57</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>140</xapG:red>\n                           <xapG:green>98</xapG:green>\n                           <xapG:blue>57</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=117 G=76 B=36</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>117</xapG:red>\n                           <xapG:green>76</xapG:green>\n                           <xapG:blue>36</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=96 G=56 B=19</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>96</xapG:red>\n                           <xapG:green>56</xapG:green>\n                           <xapG:blue>19</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=66 G=33 B=11</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>66</xapG:red>\n                           <xapG:green>33</xapG:green>\n                           <xapG:blue>11</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=236 G=28 B=36</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>236</xapG:red>\n                           <xapG:green>28</xapG:green>\n                           <xapG:blue>36</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=0 G=169 B=157</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>0</xapG:red>\n                           <xapG:green>169</xapG:green>\n                           <xapG:blue>157</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=102 G=45 B=145</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>102</xapG:red>\n                           <xapG:green>45</xapG:green>\n                           <xapG:blue>145</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>R=139 G=146 B=152 1</xapG:swatchName>\n                           <xapG:mode>RGB</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:red>139</xapG:red>\n                           <xapG:green>146</xapG:green>\n                           <xapG:blue>152</xapG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=100</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>255</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=90</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>229</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=80</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>204</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=70</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>178</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=60</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>153</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=50</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>127</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=40</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>101</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=30</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>76</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=20</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>50</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=10</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>25</xapG:gray>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xapG:swatchName>K=5</xapG:swatchName>\n                           <xapG:mode>GRAY</xapG:mode>\n                           <xapG:type>PROCESS</xapG:type>\n                           <xapG:gray>12</xapG:gray>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xapG:Colorants>\n               </rdf:li>\n            </rdf:Seq>\n         </xapTPg:SwatchGroups>\n      </rdf:Description>\n   </rdf:RDF>\n</x:xmpmeta>\n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                           \n<?xpacket end=\"w\"?>\rendstream\rendobj\r2 0 obj\r<</Count 1/Type/Pages/Kids[5 0 R]>>\rendobj\r15 0 obj\r<</Intent 16 0 R/Usage 17 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r24 0 obj\r<</Intent 25 0 R/Usage 26 0 R/Name(Layer 11)/Type/OCG>>\rendobj\r28 0 obj\r<</Intent 29 0 R/Usage 30 0 R/Name(Layer 10)/Type/OCG>>\rendobj\r32 0 obj\r<</Intent 33 0 R/Usage 34 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r36 0 obj\r<</Intent 37 0 R/Usage 38 0 R/Name(Layer 4)/Type/OCG>>\rendobj\r40 0 obj\r<</Intent 41 0 R/Usage 42 0 R/Name(Layer 5)/Type/OCG>>\rendobj\r44 0 obj\r<</Intent 45 0 R/Usage 46 0 R/Name(Layer 6)/Type/OCG>>\rendobj\r48 0 obj\r<</Intent 49 0 R/Usage 50 0 R/Name(Layer 7)/Type/OCG>>\rendobj\r52 0 obj\r<</Intent 53 0 R/Usage 54 0 R/Name(Layer 8)/Type/OCG>>\rendobj\r56 0 obj\r<</Intent 57 0 R/Usage 58 0 R/Name(Layer 9)/Type/OCG>>\rendobj\r60 0 obj\r<</Intent 61 0 R/Usage 62 0 R/Name(Layer 13)/Type/OCG>>\rendobj\r64 0 obj\r<</Intent 65 0 R/Usage 66 0 R/Name(Layer 15)/Type/OCG>>\rendobj\r68 0 obj\r<</Intent 69 0 R/Usage 70 0 R/Name(Layer 14)/Type/OCG>>\rendobj\r126 0 obj\r<</Intent 127 0 R/Usage 128 0 R/Name(Layer 12)/Type/OCG>>\rendobj\r152 0 obj\r<</Intent 153 0 R/Usage 154 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r161 0 obj\r<</Intent 162 0 R/Usage 163 0 R/Name(Layer 11)/Type/OCG>>\rendobj\r165 0 obj\r<</Intent 166 0 R/Usage 167 0 R/Name(Layer 10)/Type/OCG>>\rendobj\r169 0 obj\r<</Intent 170 0 R/Usage 171 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r173 0 obj\r<</Intent 174 0 R/Usage 175 0 R/Name(Layer 4)/Type/OCG>>\rendobj\r177 0 obj\r<</Intent 178 0 R/Usage 179 0 R/Name(Layer 5)/Type/OCG>>\rendobj\r181 0 obj\r<</Intent 182 0 R/Usage 183 0 R/Name(Layer 6)/Type/OCG>>\rendobj\r185 0 obj\r<</Intent 186 0 R/Usage 187 0 R/Name(Layer 7)/Type/OCG>>\rendobj\r189 0 obj\r<</Intent 190 0 R/Usage 191 0 R/Name(Layer 8)/Type/OCG>>\rendobj\r193 0 obj\r<</Intent 194 0 R/Usage 195 0 R/Name(Layer 9)/Type/OCG>>\rendobj\r197 0 obj\r<</Intent 198 0 R/Usage 199 0 R/Name(Layer 13)/Type/OCG>>\rendobj\r201 0 obj\r<</Intent 202 0 R/Usage 203 0 R/Name(Layer 15)/Type/OCG>>\rendobj\r205 0 obj\r<</Intent 206 0 R/Usage 207 0 R/Name(Layer 14)/Type/OCG>>\rendobj\r263 0 obj\r<</Intent 264 0 R/Usage 265 0 R/Name(Layer 12)/Type/OCG>>\rendobj\r289 0 obj\r<</Intent 290 0 R/Usage 291 0 R/Name(Layer 2)/Type/OCG>>\rendobj\r298 0 obj\r<</Intent 299 0 R/Usage 300 0 R/Name(Layer 11)/Type/OCG>>\rendobj\r302 0 obj\r<</Intent 303 0 R/Usage 304 0 R/Name(Layer 10)/Type/OCG>>\rendobj\r306 0 obj\r<</Intent 307 0 R/Usage 308 0 R/Name(Layer 1)/Type/OCG>>\rendobj\r310 0 obj\r<</Intent 311 0 R/Usage 312 0 R/Name(Layer 4)/Type/OCG>>\rendobj\r314 0 obj\r<</Intent 315 0 R/Usage 316 0 R/Name(Layer 5)/Type/OCG>>\rendobj\r318 0 obj\r<</Intent 319 0 R/Usage 320 0 R/Name(Layer 6)/Type/OCG>>\rendobj\r322 0 obj\r<</Intent 323 0 R/Usage 324 0 R/Name(Layer 7)/Type/OCG>>\rendobj\r326 0 obj\r<</Intent 327 0 R/Usage 328 0 R/Name(Layer 8)/Type/OCG>>\rendobj\r330 0 obj\r<</Intent 331 0 R/Usage 332 0 R/Name(Layer 9)/Type/OCG>>\rendobj\r334 0 obj\r<</Intent 335 0 R/Usage 336 0 R/Name(Layer 13)/Type/OCG>>\rendobj\r338 0 obj\r<</Intent 339 0 R/Usage 340 0 R/Name(Layer 15)/Type/OCG>>\rendobj\r342 0 obj\r<</Intent 343 0 R/Usage 344 0 R/Name(Layer 14)/Type/OCG>>\rendobj\r400 0 obj\r<</Intent 401 0 R/Usage 402 0 R/Name(Layer 12)/Type/OCG>>\rendobj\r425 0 obj\r<</Intent 426 0 R/Usage 427 0 R/Name(Roots)/Type/OCG>>\rendobj\r429 0 obj\r<</Intent 430 0 R/Usage 431 0 R/Name(Onion body)/Type/OCG>>\rendobj\r433 0 obj\r<</Intent 434 0 R/Usage 435 0 R/Name(O1)/Type/OCG>>\rendobj\r437 0 obj\r<</Intent 438 0 R/Usage 439 0 R/Name(O2)/Type/OCG>>\rendobj\r441 0 obj\r<</Intent 442 0 R/Usage 443 0 R/Name(O3)/Type/OCG>>\rendobj\r445 0 obj\r<</Intent 446 0 R/Usage 447 0 R/Name(O4)/Type/OCG>>\rendobj\r449 0 obj\r<</Intent 450 0 R/Usage 451 0 R/Name(O5)/Type/OCG>>\rendobj\r453 0 obj\r<</Intent 454 0 R/Usage 455 0 R/Name(O6)/Type/OCG>>\rendobj\r457 0 obj\r<</Intent 458 0 R/Usage 459 0 R/Name(O7)/Type/OCG>>\rendobj\r461 0 obj\r<</Intent 462 0 R/Usage 463 0 R/Name(O8)/Type/OCG>>\rendobj\r465 0 obj\r<</Intent 466 0 R/Usage 467 0 R/Name(Guides)/Type/OCG>>\rendobj\r469 0 obj\r<</Intent 470 0 R/Usage 471 0 R/Name(Pylons WSGI layers)/Type/OCG>>\rendobj\r580 0 obj\r<</Intent 581 0 R/Usage 582 0 R/Name(Request response)/Type/OCG>>\rendobj\r611 0 obj\r<</Intent 612 0 R/Usage 613 0 R/Name(Roots)/Type/OCG>>\rendobj\r615 0 obj\r<</Intent 616 0 R/Usage 617 0 R/Name(Onion body)/Type/OCG>>\rendobj\r619 0 obj\r<</Intent 620 0 R/Usage 621 0 R/Name(O1)/Type/OCG>>\rendobj\r623 0 obj\r<</Intent 624 0 R/Usage 625 0 R/Name(O2)/Type/OCG>>\rendobj\r627 0 obj\r<</Intent 628 0 R/Usage 629 0 R/Name(O3)/Type/OCG>>\rendobj\r631 0 obj\r<</Intent 632 0 R/Usage 633 0 R/Name(O4)/Type/OCG>>\rendobj\r635 0 obj\r<</Intent 636 0 R/Usage 637 0 R/Name(O5)/Type/OCG>>\rendobj\r639 0 obj\r<</Intent 640 0 R/Usage 641 0 R/Name(O6)/Type/OCG>>\rendobj\r643 0 obj\r<</Intent 644 0 R/Usage 645 0 R/Name(O7)/Type/OCG>>\rendobj\r647 0 obj\r<</Intent 648 0 R/Usage 649 0 R/Name(O8)/Type/OCG>>\rendobj\r651 0 obj\r<</Intent 652 0 R/Usage 653 0 R/Name(Guides)/Type/OCG>>\rendobj\r655 0 obj\r<</Intent 656 0 R/Usage 657 0 R/Name(Pylons WSGI layers)/Type/OCG>>\rendobj\r766 0 obj\r<</Intent 767 0 R/Usage 768 0 R/Name(Request response)/Type/OCG>>\rendobj\r767 0 obj\r[/View/Design]\rendobj\r768 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r656 0 obj\r[/View/Design]\rendobj\r657 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r652 0 obj\r[/View/Design]\rendobj\r653 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r648 0 obj\r[/View/Design]\rendobj\r649 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r644 0 obj\r[/View/Design]\rendobj\r645 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r640 0 obj\r[/View/Design]\rendobj\r641 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r636 0 obj\r[/View/Design]\rendobj\r637 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r632 0 obj\r[/View/Design]\rendobj\r633 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r628 0 obj\r[/View/Design]\rendobj\r629 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r624 0 obj\r[/View/Design]\rendobj\r625 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r620 0 obj\r[/View/Design]\rendobj\r621 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r616 0 obj\r[/View/Design]\rendobj\r617 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r612 0 obj\r[/View/Design]\rendobj\r613 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r581 0 obj\r[/View/Design]\rendobj\r582 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r470 0 obj\r[/View/Design]\rendobj\r471 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r466 0 obj\r[/View/Design]\rendobj\r467 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r462 0 obj\r[/View/Design]\rendobj\r463 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r458 0 obj\r[/View/Design]\rendobj\r459 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r454 0 obj\r[/View/Design]\rendobj\r455 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r450 0 obj\r[/View/Design]\rendobj\r451 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r446 0 obj\r[/View/Design]\rendobj\r447 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r442 0 obj\r[/View/Design]\rendobj\r443 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r438 0 obj\r[/View/Design]\rendobj\r439 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r434 0 obj\r[/View/Design]\rendobj\r435 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r430 0 obj\r[/View/Design]\rendobj\r431 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r426 0 obj\r[/View/Design]\rendobj\r427 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r401 0 obj\r[/View/Design]\rendobj\r402 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r343 0 obj\r[/View/Design]\rendobj\r344 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r339 0 obj\r[/View/Design]\rendobj\r340 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r335 0 obj\r[/View/Design]\rendobj\r336 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r331 0 obj\r[/View/Design]\rendobj\r332 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r327 0 obj\r[/View/Design]\rendobj\r328 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r323 0 obj\r[/View/Design]\rendobj\r324 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r319 0 obj\r[/View/Design]\rendobj\r320 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r315 0 obj\r[/View/Design]\rendobj\r316 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r311 0 obj\r[/View/Design]\rendobj\r312 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r307 0 obj\r[/View/Design]\rendobj\r308 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r303 0 obj\r[/View/Design]\rendobj\r304 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r299 0 obj\r[/View/Design]\rendobj\r300 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r290 0 obj\r[/View/Design]\rendobj\r291 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r264 0 obj\r[/View/Design]\rendobj\r265 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r206 0 obj\r[/View/Design]\rendobj\r207 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r202 0 obj\r[/View/Design]\rendobj\r203 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r198 0 obj\r[/View/Design]\rendobj\r199 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r194 0 obj\r[/View/Design]\rendobj\r195 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r190 0 obj\r[/View/Design]\rendobj\r191 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r186 0 obj\r[/View/Design]\rendobj\r187 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r182 0 obj\r[/View/Design]\rendobj\r183 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r178 0 obj\r[/View/Design]\rendobj\r179 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r174 0 obj\r[/View/Design]\rendobj\r175 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r170 0 obj\r[/View/Design]\rendobj\r171 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r166 0 obj\r[/View/Design]\rendobj\r167 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r162 0 obj\r[/View/Design]\rendobj\r163 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r153 0 obj\r[/View/Design]\rendobj\r154 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r127 0 obj\r[/View/Design]\rendobj\r128 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r69 0 obj\r[/View/Design]\rendobj\r70 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r65 0 obj\r[/View/Design]\rendobj\r66 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r61 0 obj\r[/View/Design]\rendobj\r62 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r57 0 obj\r[/View/Design]\rendobj\r58 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r53 0 obj\r[/View/Design]\rendobj\r54 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r49 0 obj\r[/View/Design]\rendobj\r50 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r45 0 obj\r[/View/Design]\rendobj\r46 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r41 0 obj\r[/View/Design]\rendobj\r42 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r37 0 obj\r[/View/Design]\rendobj\r38 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r33 0 obj\r[/View/Design]\rendobj\r34 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r29 0 obj\r[/View/Design]\rendobj\r30 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r25 0 obj\r[/View/Design]\rendobj\r26 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r16 0 obj\r[/View/Design]\rendobj\r17 0 obj\r<</CreatorInfo<</Subtype/Artwork/Creator(Adobe Illustrator 13.0)>>>>\rendobj\r610 0 obj\r[766 0 R 655 0 R 651 0 R 647 0 R 643 0 R 639 0 R 635 0 R 631 0 R 627 0 R 623 0 R 619 0 R 615 0 R 611 0 R]\rendobj\r5 0 obj\r<</CropBox[0.0 0.0 14400.0 14400.0]/Parent 2 0 R/Contents 782 0 R/BleedBox[0.0 0.0 14400.0 14400.0]/PieceInfo<</Illustrator 603 0 R>>/ArtBox[6794.06 6962.0 7506.0 7463.48]/MediaBox[0.0 0.0 14400.0 14400.0]/Thumb 787 0 R/TrimBox[0.0 0.0 14400.0 14400.0]/Resources<</ColorSpace<</CS0 778 0 R>>/Font<</T1_0 780 0 R>>/ProcSet[/PDF/Text]/Properties<</MC10 651 0 R/MC11 655 0 R/MC12 766 0 R/MC0 611 0 R/MC1 615 0 R/MC2 619 0 R/MC3 623 0 R/MC4 627 0 R/MC5 631 0 R/MC6 635 0 R/MC7 639 0 R/MC8 643 0 R/MC9 647 0 R>>/ExtGState<</GS0 614 0 R>>>>/Type/Page/LastModified(D:20080718182723-07'00')>>\rendobj\r782 0 obj\r<</Length 7586/Filter/FlateDecode>>stream\r\nHlWˎ$7\u000eW\u000fZ(Ji`\f|\u000749\u0000\u0011AUy]\u0018\u001aCI\u0011ۯۧz}}m?q~jo~]ݳ^F_c\u0019#\u0017o~\u001efeG܏UGqԺZznxp\u0016\u001cJk˽\u001a\u001fǾ|zqW/\u0016޵4UYJ4<z\u0013oX/1\u0007~gپr\u0003策6B.1\\\u000f7VY_'|xi\u0013?mVmey\f~ \f!o KE\u001a^^\u0005\u001c6G8o~\\\nr\fy\u001eev\u00127q=\u0013W\u0018\u0002'ƫHx\\8+m\u0015fx_}\\uzԶ6(p,\bvG\r\u0003^u\u0010<ʴu8r˗w\u00191ʲZ~\\Kc\u001dP\u001e\u0013u<+/W\u0015*G+}\u001dp#\nG\u0019D5'^'\tWZg\u0016(*YA\u0012|c\u001f?to[\u0003\u0000F-\n\u0017ݺ\u0000\u00066\u0005B\u0004U5x\u00072\"1\u0007k\u0000ɟ\nKEGxq5󴀖\u0010\u001e;8\rdD\u0005\u0002qmq!\u000bI4q9\u0000\u000b\u0005D\u001b!j5ѳ%\"\tlz_BJAR@$R\u0002\u0010u\u0012\f2jOU*\u0000b̮.$(򙺤:b+\u0005\bpƋXͽX\u0004\u0007De\u0017yN[W,peq2#\u0004s=x\u001c{\u0016\u000el\u0001]Y ԧqBC\u0012S.sMP]\u001aP\u0015\u0016MJTde@\u0001\u0016S\u0001ȇ#>U'dWMbw~%Ԯ5\u0018ly\u0000&t\u0010CPQ\u0001ƺL\u0005\u0002\u0002V%\u0005\u0011˞R\u0004%\u0002\u0007E\u0005|\u000f\u0006=~f\u000fq;\u0017!P`\u001fH-,BxG\u001a,SP\u0018q,nOB{N!\"\\!qP\u0014%\u0005\u0015\u0017\u0010,Ң(\f\b\u0016\u0006:CS[\u001aU\u001ai\b[\u0014dڲth\u0013\u000f2\u0010Y ,YK(jƂ,\u0000:K6U`i\u001f\u0002J|\u001agש^S\u001d\u000f\"'7g+\u0005Ԉ+n\u0006\\$\tX\u0001P!Hmo4\"jؓ\n\u0002UEhce(SzZ{Vh\u0000m6r5piR`\u0005[^\u0000\u0003hZU#VcEBEVX\u0001\u0003@\u000f p\u000e|\u000bh(l\u0018C(8/yA\u001c3ȶ<ze\t\u0006\u0012|\u0003\u0015\u0018)\b_k3&@rt\u0015ۜH!X\b1Зx׵S#(\u001dνr\u001cǏ>\t\u001c.)*\u0014baA*d\u0019\u0002\u0018H <N\u0001gX}xMZzM\u000f\u0014\u000e 6)f鴡)\u0017N7\u0011\u001d]h+e-\u001e\u000e)H%x,\"J\bAH,W*S~^Xo \u000fj\u0006^8onPz\u0001z\b)\u001a\u0017+>uaM\u0000\n\u000b.\u0001\u0002<\"6kd\u0015\f\u0019h\\o\u0012\u001dƆ\u000flʑGm\u0001%v\u0011zd\tݘ\u00171N.FVԃ)\u0011\t$gW\u0006&\u0016\u0002/&3O\u0018WO\u000em\u001af/P\u0010-,|uh\u001a.\u0018\u0012{\u001ci8\u0006WUܰ]\t cr\f(!dяE= \u001eKܲ\u0011\u0010\u0006Pٖ&\u0001Q@e\rrBU\u0016\u0014\u0014L\nB`Fjw\u0000|\u0002bc(|\bl9) \u0001Tc˦Qss6}N\u001aS]t\u001c(\u0002bSWqO_7\u001858p\u0004<\u000e٥ٔP~r5h-(9DaK\u001d7lp+''#Pֳ1t)- &\u001cv|?\u000f>c>;FN2n\u001cX}\\!\u000e4yʴďN\u0012U\rdAO\u0005\bi\u0019\u0018f\u0019\u0006{\"=/Nç=\u0000BͩiKI\u0005ጰ1SCD\u000b\"i6L]NѬ7kNBDn,\t\u001a:=\t$.)M\u001e;pii\u0000G\u0011sI?.r\r\rǢM\u0001$9f\u001f838379qҶJ\u0017>6D\u0019\u0000!X)ΤQic\u001c#^8S_ ]3扮1tx 1\u001fDꑃ\"\u001eK\u0013Bf\u001fQ\b\u0001\u0012X\u0013\u0014Ԣ\u0003\u0002=\u001a¨\"r\u0019\u0011\u00118ܪ1\u0016\r#9KZdk\u001a\u001d\u0004\b\u0004x\u0016Fg}\u00101t\fJ5Ն\u0007R\"G sH<w\nzٹ5P\"zđ¬~.19@C\u0005\u00078v\u0017j6\u0007\u0017\u0006\n2KC4ڸ%Cϧz~nO?c~U0#Ag__~\u001f۴Y\u001eJ5_B?^ɿ\u0004{ \u0013W݅\u0015n\n=+B\u001e9rc\u0007\u0013ժ̝pl`S.;yf;[\u0004%`2Y\"-Ѣv\b\u0011\u0011\u0007m+\u0000\\.+ꁬr|\u001aYR\u0017ZS~\u001cƨJo&M&\\\f(F͎\b\b\u001aP\u0007\b.k9@ %\u0005\\5\u0018\tPE6|jDO6L\b@\u0013\u0017{d{3\u0003\u00193I\u001bz`$I=1\r\u0006dl\n*iT\u000eu˗\u0006\u0003f=#\foi\u001bUT|ЏS\u0011ӡ3yG?\u0019\u0017^` I9:zYIމv!*L+NLS2:(\u000ehTeT\u001c5&IHа\u001et/d;LB\u0002\u0000QYЭߦK\u000e\u001eo$g>E]Ŝ\u0019^ц\u000e@xXX\u0002}/\u0000\u0006\u0014\b\u001a2#^A%P{kA1nAm|μN\r\u001d\u0014H%<STt!q9z\u0015E}luI1'N\r\u0004\u000ej\nMzu\u0003$p(\u0016H\u000biRV΅,\u0016;\u0012nk=Х\u001f~ab{I5ZLz1\u001cP^f4kPi,CAo\u0007%G\u001b-_y<\u0001N׳':>X&\u001f\";?@K:VgW\u0016hZ07\u0011w_IFŀ|qdh\u0012M!C/.5MyUr\u000b4n\u0019Xj\u0004Mږ2b;B|\u0004ǛA\u001a1y՝(0\u001b\u0016LŸ>M\r6\u0006ñ\"4;а:U\b\u0017\u0012\u001e\u001cՈi{\u0019N\u0013Mj*Ho{5\u001d\u0006_eBsMb\r\u001a/jƗA\tЖ\bp\u0000\\|\u0004yFdEk8\f475!\u0000\u0015J0ZP)a\u0004|$%Rx%C\u001c-ڦ\u0001obTv\\\u0019'<p59n<P,-.ƨQ];!\u0016B6Ki\\Iζ]\u0015TWS\u0004T[3M.0Nĕ$\u0012bէV\u0000}QmYN0|Ӛ \u0002;\u000e\u001e\u001d2+\f荅|âR^\t\"SH\u0000Î\u0000KD:u\u0005Қ\u001f\u0018u\bJ\u0015\u0010\u001dݗ,BU#,qe\u0005P\u0017:\bք3\u0003tȮk9B_x^h\u0015RimiZe?ܼB\u0005ce\u0006[ӗoLزȵ^\u0006\\éH䂴WK_=Z<It\u001d\u001fWlPdg\u0000£:ւ:o(\t-̈́\\aucYdlq\u0014$fpX%Pҗn׈\u0006P`S\u001c^i;@\u000ehT&OBXSk`&PF\u0011X\u0003Y̅\u0006CO*\u0018@A\t:\u000e@\u0015Je˃hiσߓɩ[\u001f\u001a\u0010\u0016aj\u000b8U{ͬHBlx0c6\u0018||{.\u001e5\u0004r\ro47oE\u001ecs{ꜘ|\tRj h MFN#j޻M議ٝݮ\u0012k\nc9^V.-/Zؖ0>ڻnQr\u0007\bbg8\u0017\tǑ\u001fj\u0011̌\u0003\u0005a\u0002NUk1z%Ri[\f\u00070PIQ\u0012\"Z&t\u0010ԨXNTDIBގlX14#\u0004Aг3<aY3?\u0003x W\u0018\u0019\u0012s\u0006}\"G'8&\u0016<FR%\\\u0016:XiI]R\u0018i\u0011\u0016jY\u00195Ն̠\u0010\u0019Z3\u0012\\]|vx\u0002Ƒ\fmQSHXz\u0012\u001c^\tOk(\u0013X,@ީS\u0001fbج$3\u001eUXJ\u0011&\u001b\u0006\n63N,<\u0011\u0018 ѼKͧҟf:|ŚطT)˕ y!=}\u001b%>G\u0002\u0004\u0012t!\f\u00156ަu\b)n&:n]Al\u001bT\u0012L'⇠-X3[\u0004+(\u0014^\u000fÍ\u0018!ZѢWaY.Wlƕ\f\r]\u001cu2a\u00187P۶؛;\u001a^\u0002\bNvf\bWD\\\u0000l\f;]5\u000b\u0017\u001al1h^T\u001b\u0001L\u0017LE11\u0003:2ms1Kkq{~\n+\u0002Ks.%xV\u0000\u0004K2YZ\f\fJF~\u0013MtHK\u001bZ=\u0010)u\tP׌qLuw!-]\u0018]=F<m9fcY \u0019شG\u0011\b\u0006k\b$8\u001d:]^r^t\u0003\u0012|ZQ:r\u0005>g\u0004..\u0019\u0010(}$tL>ƃ\fJ\u0005\u0013I\u0005\n`\u0016\u0010*Kh\u0013\u001eqM{[j\u001b\u00018a\u0019:tW!\u0019)O\bx\u001aJ$\u001dv\"ae0&[\u0017\u0002\rWhrXp)uDm\u0017ֽ)\u0001HkR*km\bD95\u0012.v\u0016iI*cװ!-lJՖb|Z|\n_\r+\\Y*\u0010A7q]ta+ݾM@\u0015\u0005}e2V]`yC\u00072\b\u0018\u0004\u000bxXKfqbo\u000bء\u0000\t&A\u001bmz3uKYх!.{֗gbA7\u001bFfYw,uF~b\n\u0018#J8Ń!I~\f\u0000.>DN\u000e'nwX\\G@b]!9>6,\b:u\u0017hN\u0001\u00076\u00129iI4z\n\u0003U\n6\u0018Cؓ\u000et(K\b'V\u0001cG@\u0019c\u000eӀ\u001dM`sU&\u001d.m\u0011rUA\u000eC>&\u0010jyI8\u0010=\u001cQE8䴼\u00001VA\u0006\u0015ǂM_$l5&bA\u0005\u0011\u0007s2 !gnsxi@\u0000\u0016w̜\u0004BE\u0006f{\u0002䱨U̇\rdj`\\\u0011u\u0006bҴԀl\u001b\u00177\u0004\u0016U5-Mlp˯&\u000f\r\u001d-\u00105\u0001:ǅ)\u0013vl7E9s3 :Hj\u0012\u001cuվ\u0013H\u0001\u000fT엎f\u0005$\bR}?H>\n/\u0000f\u000bM6)j\u001dW|}aU@֟Ϗ=yǷrkyHϏ}|{}IO_Ϻ']\u0007]lRշfE'6\n݃\u001f$Qؒ+'\u0016H;q\r\u0003c{ޢ\u001fN\u00124L\u0018~\b/UUA#\nfkT`c/\"\u0015\u00078W\u0001\n\u000e2G3 %\t:[r\r\u000f9IvdMP0O\u000bWu}z]\u001f߫?W\u001fObX;e\u00143\u0016Y=h\u0011M\u001c,UMVk?&w\u0019*9m\b,쟳)J\u0003y\\,\rPAO\u0011kF\u0016mЌ\t$A %\u001aN~{\u0006D\u001fU?1~[\fs\u0012D\u0002\u001d/ʏ9ٲVH\"qkZ\u000bק#qR\u000e6\u0003ߍ3*r$\u0005\u0013GfX,[E_\u001b87\u0004r\u0011xI^\rWQ\u0016ƀޔRT\u0018\u0014+,6\u0012pZ-W&;d\u001dDv`~q\u0004;bʁy1\t\f\u0004\u0001\u0002{ H@\u001c˂OU.R\u0005\u000b\u000egU\u0017\u000b/Fbzj\u00125\u0018Y5e=*\u0006VHof\u0007k\"\u0006\u0004\u001eB\u0019I\u0001Ĺ֕\u001b\u0001'/\u0015RzM[a<PJ@\u0007u!\u0011\u0003P\u0019\u001b(\u001c\u001axO0\u000b60 \u001a\u0000\f\nPi$Qp\u000b[\u0018)qaD@OH\"\f\u0002KV4\u001a@7{kj\"\"\u0018\\.ϛ7\u0010O2&dΫm\u0004@ J\u0018`g`wr1UPCqa䰡tTy\n|P\u0003\u000eP@ndnba0]D4 i~Ք-\u001a\u000b\u0014R`&ERO$\u000e\t^\u000e@f\u0001\u0014A\u0002QS0Á\u00148G<5_Q\n\u001cϚÙ쪐\u0015w/Q砖\u0005!RTUgB\u001d_P#AI\u00183G`\u0010\u001aN$j\u000e\u001bzF3c`\u0012Y\u001bEF&mYbԆ\u0006\u0002(\u001cz))\u001d\u000ftN\u0015h'f\u0011\u001dX!\u0005S\u0018'\f0i\t\n\u0010.=kRSI\u0012`؅ޏZ\bAT@'\u0005\b`⹁˝?\u0006MN\u001e\bi;?\u0011\u001a5\bM\u0006T3*6\u0006a\u0011\u0013\u0002Hgg\u0018\u00168K\b}\u0000,,:eI\u0012I3a\u0001\\\"\u001d\u001f1r\u0005\u0012\u0005剙\nAY۟5kY%PJ.3hxk)\u0005{v\b>d'\u0010irA\n\u0000$up\u0006V;\u0006|\u0004\f)i\u00161\u0003e%kQΰ\u0000\u0018\u001b<MAΘe\u00001\u0004PT:\u0019\u0002V\u0017swU\b}WGZl\u001bL\r\u001c5\u0002\u001f5:{D?+\"2WOzL\u001eKH\u0006r)ʍsK0\u0002/P=qv@R-,\u0001X\u0018cWAK_b/,@\u0004#i\u0016}kIŞi-1Ǵ@77=ؼ]\t\u0007|p3=\u001c6Na\u000f )ds:;\u0015C|yIh?\u000f_Ҧl݅nC&j\u0018Qlѫ8\u001dO[vkv\u0016n/̤2.-v~9\u00035\u0012ެG70{\\(K\u001f_Nϯǃ\u001c3=N\u0007WG\u0002}\u0007sr\u001c\u0007\u0003Ͷ-sja\u0005\u0007^\\E4߁܁Exnt1ʶ1[m><S9$Sq:d[>|ʛ+>\u001e*}\u0013HK?MY\u0010}.\u0014L*l'ۿKJvL]Ran66e'+\u001do{=G6@\u001eO9d1yT/\u0000\u0002e;G\u00028Ħzs\u0004l\u0012fiL\nz|l\u00029Zy1,\u0011\u000bUh\u000fS\u000ep<Qy`0d:V+\u0015\tQAcȽsWm\u0000Z0U\u0001;\u000f*\nhRtϢ{!Xn>J\u0003\u0010Yxu\u0010\u0010\nd\u0002#\u000e\u0000sO0\u001cԶ$مj\u0014v(-\u0001_9\u0004gϡ]K\u001brz\u0000(\"\\\u000e\u0012\u0010\u0016k\u0019`;3|>*:@\u0001\u001f{\\p@z@twwa\u0002U&\b;n?_;H\u0019'>3.Hv\u0005rF\u001f]-m\\h(јu\u001d\u001e\u001c!\u000ebpu^Mº5G\u0012\u0019+΀yPHU@@\u001b5\u001c!\u0012\u0005/\u0010'y(y^FϳU\u0013\\\bͱ2;|m<υ*z\u000b\u001a\u00077죭 ˑ\"*G]\\Ŗ;ؐ@\u001dK\u000e\\DWDw\\\u001a!݅I\u001br=wЀPp*R\u0003(7rfςsͭ\u000boBWgl.7#ΥdTk.\u001bq\u0011d}\u0012ș>\u0004\u0013=(%\u0010\u001c\u001e~]G8pZG ;\\jAh\t)B\u001c!#3\u0010[\nA\u00104 \u0010\u0000Sd\b5ZX\u001dr'Xo\u0002\u0013LWj\"hHG2\u001e>*l\u0013ń<$\u0016rw)#\fMɐ\n\u000fF9U4\u0017c\u0000\u0003\u0000\u001eg\rendstream\rendobj\r787 0 obj\r<</Length 70/Filter[/ASCII85Decode/FlateDecode]/BitsPerComponent 8/ColorSpace 785 0 R/Width 105/Height 105>>stream\r\n8;Z]Z0bFC>$j/6U$%FM\"'+1;C<$Li+])Vg2!!#5UC8\"O>17_8/#QOi)!8u620E=qg,^f~>\rendstream\rendobj\r614 0 obj\r<</OPM 1/BM/Normal/CA 1.0/OP false/SMask/None/ca 1.0/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r780 0 obj\r<</Subtype/Type1/FontDescriptor 781 0 R/LastChar 121/Widths[212 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 612 0 580 0 492 0 0 652 0 0 0 0 804 0 0 532 0 538 493 0 0 0 0 0 0 0 0 0 0 0 0 0 482 0 448 564 501 0 559 555 234 0 0 236 0 555 549 569 563 327 396 331 551 0 736 0 471]/BaseFont/AZOSYB+MyriadPro-Regular/FirstChar 32/Encoding/WinAnsiEncoding/Type/Font>>\rendobj\r781 0 obj\r<</StemV 88/FontName/AZOSYB+MyriadPro-Regular/FontStretch/Normal/FontFile3 784 0 R/FontWeight 400/Flags 32/Descent -250/FontBBox[-157 -250 1126 952]/Ascent 952/FontFamily(Myriad Pro)/CapHeight 674/XHeight 484/Type/FontDescriptor/ItalicAngle 0>>\rendobj\r784 0 obj\r<</Subtype/Type1C/Length 2479/Filter/FlateDecode>>stream\r\nH|yP\u0014g\u001aƻ\u0019\u0007٥N[\u0013\u0002\u0011g;\u0011M/\u0004\u0004QAQ\u0007\u00189\u0004\u0019`C$\n\f\u0018܈\u001a@\u0014t\u0004\u0012\u0004\u0019pTD\u0005#J,\\mtk{jO8fk8>~vPȜ)˶b\u0014\u0001ʨ8ʺ,Ώ'at;_\u0002C.O\u0018Mc68^U;7!Q\u001b\u0015$s6mw}|x̎L\bWʂj\u0011\t\u0004\"I\u0019)͎\u0005ZeJRb]\f\u0007e\u0001Iy\u001e.\u001eޮOh\u0018L!S)b\u000452RRD*\u0015M\u0013\u000bVlMTʼeʍ\u0018\u000b\ra_ad\fs09M07\u001calE62\f\u0017c1,\u0014&\b.\t\u000b~X\t\fp/\u0004op\"WZdB\t\u001f(\"\u001ez\u0012\u001f-^\u0002?t\u0001\u0017.v9#\u0001sHG\u00194\u000b~!\u0005d\u0012\u0003=亏c9_d#dQԵ\u0003)\u0010\t]=4Vh\u000e&\u0004\u0011Ob\"~$]\u0010MTt2\u001d_\u00147\u00146;c'E(]߁V\u000eiM\u001a紑?I\u000e֮d[\u0006s\u0018\\6eS\u0007\tXEJ (\u0005\u001c_ \u001c\u0004w Ƅ78\u0006B\f\u001c5>x򟛐\u0001\u0004~}\b\"?|4\u0011z2jQ/Ԋ)\u0017(\u0014l}d\u001e8<vT\b\t\"\u0011Ơ^>\u0015艹.LJЇ;Nإ\u0013\n\u0006\u0015n \u0019G܏ѧ\u0000Gw\u000e\u0012>':pw|>3\"vO\u0004.1ZvEǚ :0;pPydmEsfrҺ\bJ\u000fv\u001d?)8/SPZ_Ͼj*_zf~w*G\t\u000es\u0014\rޜJ~BS2pz{\u001f]qͫ*Wo\fJ.9*WYߝ?~LAтFyn]2+`\\JR˴&N\u0005\u0007\u0013[΂[ϳ7_A9N^\u0017~MrV&JJ\u001bS\u001e\u001fRE_Ϝ\u0019\b6ܳ(_Uk]\u0003+#\u001cm{l\nj\u0005ݾ\u0002\u0001\u000e\u0017a<mKr9Qu.\u001bm\u0017#<hd\u0005\u001a/?\"'=~Cr\t]Cĳ[~mA\u001a\u0019\u0011ˮS\u001e\u0007t\u001c%vX\u0017^?(\u001d\u0019*v[\b;e\u0011lo>\u0006Q\tm\u0001(R\u0015b$!g\u0011&V^tj#SYFؤ\u001f\u001a@8\u0012ʠFtrHl\u0016vtB\u001ey\u001cr|\u0004zo4\\>\"\u000b\u0005^D/s\"嬄,v{_dfdI\u0001˚Gg\u001daA\\6/C+Fi\u00036\u001f\n\u0007D|80y{%\u0015A\u0005p\u0015}h2<\u0004=KI3ڈX֗u\u0005>qymLӏ\u0007A\u001cUFx\u001bFڏ9\u001c2C|\u001aaG7Y$==БgR\tH&GHd\u0012wp\u0007ZvHE&i\"b[ΒsM\\ScU'$0Х̐\u0006\u0004\u000b\u0004ۛ*Vq\u0005Yy2$Ԯ\u0003)&Ld\u0001Ed\u001ak\u0001\u0003YWH\\f8sY<C, \u0019\u000egm\"MHNT\u001bIJ\u001f\u000e~\u0001\u001ecTbz܈\u0017)I\u001d\u0017_>V[U}4;R\u001d+Н\u0003)#ָ֠#'\u0018,t\u0015\u001cY/-(\u001a\u001a\u000b0K\u0004\u0016h\u0014÷\u000eg\u0016\bZ\u0017Hڰ!1̏\u000b\u000fP;\u001d\u000eȠ\b?2H\u000bDS\u00170\n\u0000\u0016aq̛\u0006o\u0010së7\u001cU槀\u0017uYiPgL(1C\\Ss5\u0016\u000b'0\u0007\u001c^Q>\u0001Q(!ae\u0012s\u0018S__(:ʯɾk$\nN5\u0015ꊊ%/\u001fCu6]V\u0010(Ĳ\u0005\u000by\u0006P\u00119֊hRF@sg \u001e\\o>IlegI4сa\u0000),c9gfI(*X<O՚\u0016j\u0012~Y%\"iGѹ٢\u001c]'[?\rX\u0019$&障,2]^hK \u0019\u0010>hNd^bA:pgCqηzs\u0019I]ыҪ[DY→Pw\rkq\\PB\u0012\u0011i-BQ$iM\u0000\u0017OD/.E\u0003u\u0001\u0007R`q\u001es}\u001b\u001f\u0005~}s\u001bZz\u001f\u0012\u0012\b\u0007\u000ebvxw\u0012|\u0013rx\u00153\u0006{{~\u001ed{bbP\u001b;o\u001f3\u0007>aι\u001e\u0006\u0013x<\u0005\u0006\u001a\u000eIw\u0012S\u0013x\u0015&x\u0005\u0006z\u0005\u0013М\b\u0006R[U{\u0018\u00060x\u00054\u0006F{R~XZ\u0019\u0006}y@\u0018A\u0006<{V{WZ\u0019\u0006~}K\u0018\u000e7\u0012v\u000bw\u0001[\u0003x\u0015GR\u0005\u001a\u001ew^misxqun}uA\u0018ǿ:\u0018\u0018.\u0006+hfn\u0019\u0006!\u0018\u000e6^/t\u0006JLo\u0007\u001e`E\f\t\n\u000b\f\rh\u0014\u0015\u0002\f\u0000\rendstream\rendobj\r778 0 obj\r[/ICCBased 779 0 R]\rendobj\r779 0 obj\r<</Length 2574/Filter/FlateDecode/N 3>>stream\r\nHyTSw\u0016oɞc\r[\u00065la\u001d\u0004Q\bI\b\u0001\u0012BH\u0005AD\u0005\u0014ED2mtFOE.c\u000e}\u000308\u0016׎\u00178GNg\u001f9w߽\u0000'0\u000b\u0000֠J\u0016\u0015\u0014b\t\u0000\u0003\n \u0002\u0011\u00002y.-;!\u0007KZ\t^\u0007i\"L0-\r\u0000@\u00198\u0007(r;q7L\u0019y&Q\u0013\u0004q4j|9\nV)gB0iW\u00198#8wթ8_٥ʨQ\u0014Qj\u0001@&A)/\u000fg>'K\u0002\u0000t;\\\u000e\u001b\r\u0006ӥ$պFZUn\u001e(4T%)뫔\u00060C&\u0015Zi\u001b\u00018bxEB\u001f;Pӓ̹A\u000bom?W=\nx\u0016-\u0000\u0004[\u00000\u001d}y)7\u0018ta>jT7\u000e@tܛ`q2ʀ&6ZLĄ?\u001d_\u001dyxg)˔z\u0016çLU*\u0006u\u0016SkS\u0013eO4?׸c\u0001\u0007.\u0000\u000b\u0000\u0000R\r߁-\u000725\tS>ӣVd`rn~Y\u0002\u0002\u0002&\u0001+`\u000f;\u0010\u0002\u0010\u0002A4\u0007 \u001d\u0002\u0014A9\u0000=\u0007-\u001dt\u001e\u001el\u0002`;\u0018\u0003~p\u0010\tGp\u001e|\t[`\u0012L`\u0006<\u0005 \b\"A\f\u000bYA\u000e+\u0005Cb(\u0012R,\u0000*T\u00162B-\n\u0007ꇆ\u001dnQ\u0004t\u000e\u0004}\u0005MA\u000f0\u0002a\u001el\u0007\u0018S\u001cx\tk&\u0013^\u0007\u000f>0|\u0002>\u000f_',\u0002\u0010\u001aG\u001c\u0011!\"F$H:R!z\u0015F\u0006Qd?r\f9\\A&G\u000brQ\f\u0015h\u0012\u001a\u0015E]a4z\u0005Bg\u0004\u0006E\b#H\t\b*B=0HIpp0MxJ$\u0012D\u00011D, V\u0010ĭ\u0003KĻY\u0012dE\"EI2EBGt4MzN\u001d\u0004r!YK \u000f?%_&#(0J:EAiQ((\u0017)ӔWT6U@P+!~\u0019m\u0013\u001aD\u000beԴ!hӦh/\u001c']B/\u001b\u001fҏӿ?a0\u0018nhF!X8܌kc&5S\u001d6lIa2cKMA!E#\u0016ƒdV\b(\u0006kel\r}}Cq9\nN'\u0003)].uJr\n\u0018\fwG\txR^\u0005[\u0004oƜc\u001ehg`>b$\u001f*~\u001f :Eb~\u0016,m,-ݖ\u0007,Y¬*6X[ݱF=3뭷Y~dó\tt\u001ci\u000bzf6~`{v.Ng#{}}\u000f\u001c\u000e\u000ej\u0001\u001cc1X\u00156f\u001cm\u001d\u001c;\u001c'\u001c_9\tr:\u000e8q:˜\u0007O:ϸ8uJq\u0015nv=MmR \u00154\t\nn3ܣkGݯz\u0010=\u001e\u001e[==<=G</z^^j^\tޡZQ\u001bB0FX'+t<u-{__ߘ-\u0011G,\u0010\u001d\u0013}/\u001f\u001a\bH\bh\u000b8\u0012mW2p[AiAN\u0006#8$X\u001f?AKHI{!7<qWy(!46-\u0017aaa\u000f\u0017W\t@@`l\b\bYĎH,$((Yh7ъb<b*b<~\u0014L\u0012&Y&9\u001e%uMssNpJP%MI\fJlN<DHJIڐtCj'KwKgC%Nd\f|ꙪO=\u0006%mLuvx:HoL!ȨC&13#s$/Y=Osbsrn\u001asO1v=ˏϟ\\h٢\u0005\u0005#¼\u0017oZ<]\u0014TUt}`IÒsKV-Y,+>TB(/S,]6*-W:#7\u001f*\u0015\u0003\u0007\be^YDY}UjAyT`#D=\"b{ų\u000f+ʯ:!kJ4G\u001cmt}uC%K7Y\u0013VfFY\u000b.=b?S\u0017ƕƩȺy\u001a\rچ\u000bk\u001a5%4\u0019m7lqlioZ\u0016lG+Zz͹mzy]?uuw|\"űNwW&e֥ﺱ*|j5\u0001kyݭǯg^y\u0017kEklD_p߶7Dmo꿻1m\u0001l{Mś\r\u0006\u000enLl<9O\u0000\u0001[$h՛B\u001cdҞ@\u001diءG&\u0006vVǥ8\u001anRĩ7\u001c\u0002u\\ЭD-\u0016\u0000u`ֲK³8%\u0013\u0001yhYѹJº;.!\u0015\nzpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\\dlvۀ\u0005܊\u0010ݖ\u001cޢ)߯6DScs\r\u001f2F[p\u0011(@Xr\u00194Pm\u00198Ww\u0007)Km\u0002\f\u0000\rendstream\rendobj\r785 0 obj\r[/Indexed/DeviceRGB 255 786 0 R]\rendobj\r786 0 obj\r<</Length 428/Filter[/ASCII85Decode/FlateDecode]>>stream\r\n8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@\"pJ+EP(%0\nb]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\\Ulg9dhD*\"iC[;*=3`oP1[!S^)?1)IZ4dup`\nE1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\\.?d>Mn\n6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1\nVNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<\nPO7r\\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(\nl[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\\~>\rendstream\rendobj\r603 0 obj\r<</Private 604 0 R/LastModified(D:20080718182723-07'00')>>\rendobj\r604 0 obj\r<</CreatorVersion 13/RoundtripVersion 13/ContainerVersion 11/AIMetaData 605 0 R/AIPrivateData1 606 0 R/AIPrivateData2 607 0 R/AIPrivateData3 608 0 R/NumBlock 3/RoundtripStreamType 1>>\rendobj\r605 0 obj\r<</Length 912>>stream\r\n%!PS-Adobe-3.0 \r%%Creator: Adobe Illustrator(R) 13.0\r%%AI8_CreatorVersion: 13.0.0\r%%For: (Kelvin Wong) ()\r%%Title: (pylons_as_onion.ai)\r%%CreationDate: 7/18/08 6:27 PM\r%%BoundingBox: -7 62 706 564\r%%HiResBoundingBox: -6.44434 62.5 705.5 563.9785\r%%DocumentProcessColors: Cyan Magenta Yellow Black\r%AI5_FileFormat 9.0\r%AI12_BuildNumber: 406\r%AI3_ColorUsage: Color\r%AI7_ImageSettings: 0\r%%RGBProcessColor: 0 0 0 ([Registration])\r%AI3_TemplateBox: 400 300 400 300\r%AI3_TileBox: 111.5 -55.5 687.5 678.5\r%AI3_DocumentPreview: None\r%AI5_ArtSize: 14400 14400\r%AI5_RulerUnits: 6\r%AI9_ColorModel: 1\r%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r%AI5_TargetResolution: 800\r%AI5_NumLayers: 13\r%AI9_OpenToView: -94.5 634.5 1 992 699 2 0 0 50 75 0 0 1 1 1 0 1\r%AI5_OpenViewLayers: 3323333333333\r%%PageOrigin:-66.3003 -266.2988\r%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9\r%AI9_Flatten: 1\r%AI12_CMSettings: 00.MS\r%%EndComments\r\rendstream\rendobj\r606 0 obj\r<</Length 9071>>stream\r\n%%BoundingBox: -7 62 706 564\r%%HiResBoundingBox: -6.44434 62.5 705.5 563.9785\r%AI7_Thumbnail: 128 92 8\r%%BeginData: 8930 Hex Bytes\r%0000330000660000990000CC0033000033330033660033990033CC0033FF\r%0066000066330066660066990066CC0066FF009900009933009966009999\r%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66\r%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333\r%3333663333993333CC3333FF3366003366333366663366993366CC3366FF\r%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99\r%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033\r%6600666600996600CC6600FF6633006633336633666633996633CC6633FF\r%6666006666336666666666996666CC6666FF669900669933669966669999\r%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33\r%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF\r%9933009933339933669933999933CC9933FF996600996633996666996699\r%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33\r%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF\r%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399\r%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933\r%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF\r%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC\r%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699\r%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33\r%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100\r%000011111111220000002200000022222222440000004400000044444444\r%550000005500000055555555770000007700000077777777880000008800\r%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB\r%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF\r%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF\r%524C45FDFCFFFDFCFFFDC4FFA8A8A8FD7EFF522727527DFD6FFF7D272727\r%5227272752527D7DFFA87D2727277DA8FD6EFFA8A87DA8A8A87D52F82727\r%527DA87D7D2752A8FD6AFFFD04A87D7D527D52522752FD0527527D7D2727\r%A8FD62FF7D275252527DFD04522752275252FD0627522727275252272752\r%FD63FF7D52272727522752527D525227272752527DFD04522727F8522752\r%277DFD65FFA8A8A8FFA8A87D52277D7DA8A8FFFFFFA87D7D7D5227527D52\r%7D27FD68FF7D5227527DA8FD07FF7D272752A87D27FD04527DFD63FFA852\r%52275252A8FD0CFF7D2727A87D525252277DFD63FF7D7D7DA8A8FD0FFFA8\r%52F85227FD0452FD79FF522752527D5252FD79FFA827FD045227FD50FFA8\r%A8FD28FF5252527D5252A8FD4FFF7D2752A8FFA8FFFFA8A8FFA8FFA8FFA8\r%FFFFA8A8527DFD14FF7D27525252277DFD4FFF527D52A87D7DA87D52527D\r%7DA87DA8527D7D52A8277DFD14FF7D52527D52527DFD4FFF7D2752A82752\r%5252FF527D7DA8FD0652A852A8FD14FF7D27525252277DFD4FFF52A8527D\r%527DA8527D527D52527D7D527DFF277D52A8FD14FF27FD05527DFD4FFFFD\r%05A852FFA87D27FF7D7DA8FF52A87D7DA8A87DFD13FF7D27FD0452277DFD\r%58FF52A8FD1EFF52527DFD0452A8FD77FF7D27FD055227FD77FF7D277D52\r%52527D277DFD74FFA85252275227FD0652FD0CFF52277DA8FFA8FD05FFA8\r%FD05FFA8FFFFFFA8FD4EFF7D7D52522752527D52A8A8A87D7D527DFD0CFF\r%52FF52A87D7DA852A87D5252A8A8527DA85252A87D7DA87D52FD34FF524B\r%52FD10FFA87D5227272752527D7DA8A8FFA8FFFFFF7D5227FD0CFF5227FD\r%0652A8527DA82727FF525252A8527D52A8275252FD33FF52F827FD0EFF7D\r%522752527D7DA8A8FFFFFFA8FFFD04A8FFFF7D27A8FD0BFF52FF5252277D\r%A8A827527DA85252A87D527D7D7DFF5227527DA8FD33FF52F8F8FD0BFFA8\r%7D2752275252A8A8FFFD09A8FFA8A8FFA8277DFD0BFF7DFFA87D7D52A852\r%A8525252FFA8527DA87DA87DA852A87D7DA8FD33FF7DF827A8FD09FF7DFD\r%04527DA8FFFFFFA8FFA8FFA8FFA8A8A8FFA8FFA8FFFF7D27FD14FF7D7DFD\r%42FF77F8F8A8FD06FFA87D27FD0452A8FFFFA8FFA8FFFD07A8FFA8A8A8FF\r%A8FF7D277DFD13FFA8FD43FFA8F8217DFD05FF7D52277D52527DFFFFFFA8\r%FFA8FFA8FFA8A8A8FD05FFA8FFA8A8FFFF5252FD57FF7D21F87DFD04FF52\r%2752522752A8FFA8A8FFFFA8FFA8A8A8FFFFFFA8A8A8FFFFFFA8FFA8A8FF\r%A8F87DFD15FFA8A8FD40FF27F852FFFFFF27FD04527DFFFFA8FFFFFFA8FF\r%A8FFA8FFFFFFA8FFFFFFA8FFA8FFA8FFA8FFFF7D27FD15FF52A8FD40FF27\r%F827FFFF27FD04527DFFFFA8FFFFFFA8FFA8FFFFFFA8FFA8FD04FFA8A8FF\r%A8FFA8A8A8FF7D277DFD13FF7D21A8FD40FF52F827A827FD0452A8FFFFA8\r%FFFFFFA8FFA8FFFFFFA8FD07FFA8FFFFFFA8FFA8FFFFFF5227A8FD12FF27\r%27FD41FF7DF82727525252277DFFFFA8FFFFFFA8FFA8FFFFFFA8FD09FFA8\r%FFA8FFA8FFA8FFFFA8277DFD11FF52F852FD41FFA827F827527D52A8FFFF\r%A8FD05FFA8FFFFFFA8FD0DFFA8FFFFFFA8FFFF7D27FD10FF7DF8277DFD42\r%FF27F8F852527DFFFFA8FFFFA8A8FFA8FFFFFFA8FFFFFFA8A8A8FD05FFA8\r%FFFFFFA8FFA8FFA8FF7D2752FD0EFF7DF8F8F8FD43FF52F827277DFFFFA8\r%FD05FFA8FD07FFA8FFFFFFA8FD07FFA8FFA8FFA8FFFFFF5252FD0DFF52F8\r%27F852FD42FFA82727F827A8FFA8FFFFFFA8FFA8A8FFFFA8FFFFFFA8FFFF\r%FFA8A8FD04FFA8FFFFFFA8FFFFA8A8FFFF7D27A8FD0AFFA827F820F8F87D\r%FD42FF52522727F87DFFFFA8FFA8FFA8FD07FFA8FD05FFA8FD05FFA8FFFF\r%FFA8FFA8FFA8FFA85252FD09FF5227F827F82727FD42FFA8275252F820F8\r%A8A852A8FFA8FFA8FFA8FFFFFFA8FD07FFA8FFFFFFA8FFFFFFA8FFA8FFA8\r%FFFFFF5252FD06FFA87D27F8F827F827F87DFD42FF7D277D5252F82727A8\r%F87DFFFFA8FFA8FFFFFFA8FD0DFFA8FD0AFF7D27FFFFFFA8A85227F827F8\r%27F827F84BFD43FF5252527DFF52F82727F8F8A8A8FFA8FFFFFFA8FFFFFF\r%A8FFA8FFFFFFA8FFFFFFA8A8FFFFA8FFA8FFA8FFA8FF7D27527D2727F8F8\r%F820F827F821F8F87DFD43FFFD0452FFA827F827F82727FD09FFA8FFFFFF\r%A8FD07FFA8FFFFFFA8FD06FFA8277D7D27F8272027F827F827F82052FD44\r%FF2752525227522727F827F8F827FD05FFA8FFA8FD04FFA8FFFFA8FFFFFF\r%A8A8FFFFA8FFA8FFA8FFA8FFA85252FFFF7DF827F827F827F8F827FD44FF\r%7D525252A87DF8F8F827F827F82027FFFFFFA8FFA8FD05FFA8FFFFFFA8FF\r%FFFFA8FD0BFF5252A87D2727F827F827F82727FD45FF7D275252FFFFA827\r%F8F827F821F8F827A8A8FFA8A8FD06FFA8FFA8FFFFFFA8A8FFFFA8FFA8FF\r%A8FFA8FFA852F827F820F820F827F8F8F8A8FD45FF7D52527DFD04FF5227\r%F827F8272020F87DFD0CFFA8FFFFFFA8FD07FFA87D4B27F827F827F82727\r%272027F8A8FD46FF7D275252FD05FFA87D27FD06F852A8FD07FF7DCAA8A8\r%FFFD05A87D7D52522027F8F8F827F8F8F8277D7DF820F87DFD47FF7D5252\r%7DFFFFA8FFA8FFFFFF7D522727F8F8F8277DFD05FF7D21FD0627F827F8F8\r%F827F827F827F8F8F82727A8FFFF52F820A8FD48FFA8275252FFFFA8A8FF\r%FFFFA8FFFFFFA87D5252272727A8FFFFFF77F820F8F8F820F8F8F827FD07\r%F82752522752FFFFA8F827A8FD49FFA852527DA8FFA8FFA8FFA8FFA8FD09\r%FFA8FFFFFF52F8F827F827F827F827F827274B52527DA8A8FF7D5227FFFF\r%7D52FD4CFF275252A8FFA8A8FFFFFFA8A8FFFFA8FFA8FD06FFA8FFA87DA8\r%527D767D527D7DFD04A8FFA8FD04FF7D5252A8FFA8FD4DFF5252527DFFA8\r%FFA8FFA8A8A8FFFFFFA8FD06FFA8F8A8FF7D7DFFA8FD07FFA8FD05FFA8FF\r%7D5227FD50FF5252527DFFFFA8FFA8FFA8A8A8FFA8A8A8FD06FF52A8FF27\r%52A82752FF527DFFA8FD04FFA8FFA8A8FF7D5227A8FD4FFF7D277D52FD07\r%FFA8FFFFFFA8FD07FFA8A8FFFF52FF7D7DFF5227FF277DA852A8FFFFFFA8\r%FF7D5227FD50FFA8275252A8FFA8FFA8FFA8A8A8FFA8FFA8FD07FF52FFFF\r%7DA8FF52FFA87DA87D52FFF87D52F8A8FFFF7D5227A8FD50FF525252A8FD\r%06FFA8FFFFFFA8FFA8FD06FF7DFFFF7DFFFF7DA8FF7DA8FF7DFFFF7DFF52\r%7DFFFF525227FFFFFF7D7DA8FFA8A87DFFFFA87DA8A8FFA8FFA8FFA8FD3B\r%FF7D275252FFA8FFA8FFA8A8A8FFFFFFA8A8FD06FF7DA8A8A87DFF7DA8FF\r%7D7DFF7DA8FF7DA8FF7D7D7D2727277D7DA852F8F82727F827525252F8F8\r%F85227F827F852FD3CFF525252A8FFA8FFA8FFA8A8FD08FFA8FFFFFF7DFF\r%FF7DFFFF7DFFA8A8FFA87DFF7DA8FFFFFF7D275252FFA8FFA8A87D527DA8\r%A8A87DFF7DA87DFF7D5252A8A8FD3CFF5227527DFFFFA8FFA8FFA8A8FFFF\r%A8FFA8FFA8A8FFFFA87DFFFF52FFFF7DA8FF7DA8FF7DA8FF7DA8FFFF5252\r%277DFD0BFFA8FD47FF275252A8FD04FFA8FFA8FFFFFFA8FD05FFA8FF7DFF\r%A8A8A8FF52FFFF7DA8FF7DA8FFA852FF7D5252277DFFA8FF7D527D527DA8\r%7DA87DA87D527D7D277D7D52FD047DA8FD39FF7D275252FFFFFFA8FFA8A8\r%A8FFFFFFFD05A8FFFF7D7DFFA87DFFA87DFF7D7DFFA87DFFA87D7D522727\r%27A87D7DA8A82752F852F8527D7D275227527D27F852F852275227A8FD39\r%FFA85252527DFD05FFA8FFA8FD09FFA87DFFFF7DFFFF7DFFFF7DFFFF7DA8\r%FFFFFF527D27A8FD55FF52275252A8FFA8FFA8FFFD05A8FFA8FFA8FFFFFF\r%7DA8A87DA8FF52FFFF7DA8FF7DA8FFFFFD0452FD05FFA8A8FFA8FFA8A8A8\r%FFFFFF7DFFA8FD44FF27525252A8FFFFFFA8FFA8FFA8FFA8FFA8FFFFFFA8\r%7DA8FF7DA8FFA8A8FF7DA8FFA852A85252272752A87DA87DA85227275227\r%A82752272752F82727A8FD43FFA8F8525252A8FFA8A8A8FFA8A8A8FFA8FF\r%A8FFA8FF7D7DA8A87DFFA87DA8FF7DFFA8FF7D52275252FFFD06A87DA87D\r%7DA8FD057D527D52FD45FF7D277D527DFD04FFA8FFA8FFA8FFA8FFA8FFA8\r%A87DFFFFA8FFFF7DFFFF7DA8FFA87D527D52FD08FFA8FFFFA8FFFFFFA8FF\r%FFFFA8FD47FF7D2752527DA8FFFFFFA8A8A8FFA8FFA8FD04FF7DA8FF52A8\r%FF7D7DFF7DA87D522752277DFD07A87D7D272727525252F8F827F852FD04\r%27522727FD39FFA87DA8FD05FF7D275252527DFD05FFA8A8A8FFA8FFFFFF\r%7DA8FFA87DFF7D7DFFFF52522752277DA8A87DA87DA87DA8A8A852FD047D\r%A852FD057D527D527D527DFD39FF7D27F82727525252FD052752527DA8FF\r%FFFFA8FFFD06A852FF7D7DFFFF7DA8FD045227A8FD59FFA8A82752275227\r%7D7D522752527D7DA8A8FD08FF7DFFFF7DFFA8FD0652FD0BFF7D7DFD07A8\r%7D52A8FD047DFD04A87DFD3AFFA87DFD052752277DFFA8522727FD04527D\r%7DA8A8FFA8FF52A8A8522752FD0427527D7DA87D7D7DA8FD047DA87DFD04\r%27F852F8A8F827F827F852F827F82727F87DFD38FFA8522752527D275227\r%522752A8FFA87D525227FD06527D5252277DFD05527DA8FFFFFFA8FFFFFF\r%A8FFFFFFA8FFFFFFA8FFA8A8A8FFFFFFA8FFA8FFA8FFFFFFA8FFA8FD3AFF\r%A8FFA8A82727F82727522727277DA8A8A87D525227522752275227272752\r%277D7DFD10FFA8A8FD07FFA8FFA8FFA8FD43FF7DF8527DA8527D27522752\r%2727277DA8FFFFA8A8A8FD047D52A8A87D7DFFFD0FA8FF5227527D525252\r%A852275252522727FD05527DFD3CFFA8A8A8FFFFFF7D272727FFFFF8FD04\r%27A8FD07FFA8A8FFA8A87DA8A8A87DA8A8A87DA8A8A87DFD05A8FD06527D\r%7D2752527D275227522752527DFD42FFA8A852F87D52FD042752F852A8FD\r%05FFA87DFD6DFFA85252A8A8FF2727277DF8277DFD05FF52FFA8FFA8FFA8\r%FFA8FFA8FFA8FFA8FFA8FFA8FFFF7D52A87DA8A8A8FF7D7DA8A8FD54FFA8\r%A8FFA8272752FD04FFA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8\r%527DFD0527A8FD0427FD59FF7D7DA8FD19FFA87DA8A87DA8A8A8527D52FD\r%FCFFFDFCFFFDFCFFFD2AFFFF\r%%EndData\r\rendstream\rendobj\r607 0 obj\r<</Length 65536>>stream\r\n%AI12_CompressedDataxis%Ǒ \u000b?`?h\u0004Cf,%DiZ1\u001aT\u0005R5]\u0007\u000e9~\u000ex\u000f\u000f\u0005G\u0006ª\u00008Eͷ_n^ݗus\u0015\u001fvn?{+^O\u001f>G/~U\u000bOC_MɃWD<޽˫W\u000f_\\\u000bw\u001fzn?|-|\u0017^u\u0011\u001e\u001ao香_v7o}z\u001fW_WCw56U\u001a\"yۻ\u000f\u0013uu'\u0013z\u001e\u0004\u001fؿ{ۏ߼Çݻ۷W\u0001r{/w_u\u001f9{\u0011\u001eO_ݾۻ\u001f>}\u001e˻\u001f*}w|\u000eVǫ\u0019mn뗿Ow\u0019\u0010G\u0007\u0018\u0016\u0010Fݯ\u0000ۻ\u001fa\u001e\\\b~Gx+FX\u0005w7?զMs?.O\u0018m}p\u0015i:Sy-ͻw<߾_06b?巟^߽WB4͙w/^[\u001d6\u000f\u000fw\u001fa߽p72~u\u001dnk\u001bw\u001asi{50W\u001d 5WcW:\u0019\u000fv\u001f׎\u000b\u001bؑ߿_~9\fװ՗\u001dĻO_̛6vW\u0013GܿYa!>~{+k\u0003Ȳ\u0000\u000eo_޽g\u0006v- w?g\u000b|ӏᏡoӻw\u001fwWpۿ]ty==fׯoo\u000e/>}Gػp{-?rKܾx\u001e\u0010w~sR/;d޹G_qWW[>ܼgܳw<O'~S~4|g_0\u00177\u001f>޽p\u0002QO^x{\\\u001f|\u0003xs^*\u0003\tyG \u0011?\r\u001cЗwon\r^wǗwl\u000e7_x}@?\u0002}~~͛OKpX=߽\u001dt\u001dËO\u0017}\u0016t\u0001'_׷oGW/n_\u0007Sé~v=\u001fֽ{\u000e.?x%\u0011g\u0017w7\u001bތ |;ܼC\u001cy\u0012ts\u0011\"\u0012S\u000bIe8\u0003_+D\u0010[4[;z\u001dN~`\u001e\u001f=^\"^s\u000fw6@\u0005\u001ew>\u0000CуyØq\u001dxi~_yt=+~k~kןk~}7?ĝՍ4oě\u0017\u0011߁c/@\u0013\u001dn\u000f?y}#C\"-|.@5~\u0001.|\u0011:}\u000e_^}K+\u001fo֏ݬ?w\u001f\bh\u0019]c;rƯڱO|ɝ@\\\u001fz\u0000\b(p3Kh\u0016\u000f\"\u0010n_|707t\u0019O/L\u001e?\"7w?^vN7@\u0015P]xs#|e\u0014t{\rJFd8\u000fwW]l׀}ӛ?{\rx5\u00066\f\u001f\u0003qx߼\u0004>߿\u000b`ۏ\u0006\b\u0007\u0018ƿ^'\u0000ի1\fػ\u001f8x\t\u0013>,ӷ^}o_\rjӇ?_ݻ6O6L\u0001\u0013\u0014x7_^I\u001eX\tӧ\u0000{}w\u000b\u0010]ݯ^^P\u0001{.~\u0017%W\u001fdltox}Or e#_^\r pe]\u001fu\u0004\u0014%\u0010:y\u0019߽\u0011Eo|\u001d\r㟏\u0017۷@\tn]\"\u0001\u0005zV$Y\t'}_~y&v?!]\u000eDZ'x;\u001a\t\bu0j\u0012;4f=Cۀյ=&yFhsiv=vMv]wKЍݦvn\u001d\u001d\u0003|c\u001fMw?\u000e$\u0018S\u001c\u0014縉۸xHMjS\u0014SJcҜ6i\u0010fh~C\u001aa\u001aa3l]G\u001cL\f\r'\bSi`*I\u0013ڷ\u0007j81Vyv\u001b詡\tj\fqynd0xę\u0007\u0018~Á'\u0000Shm\u0002Q&S`[36'S\t,PRb\u001b`\u001e8ʶ\u0007_\u000e[m4c{l\u000e\u0003~\u000f9̇0\u001eC:\u001e\u001dz@\u00166?~\u001f>w;amwݼvnإ]\u0004lv\u001e~nvئm\u000eNU9n\u000efn6y3mͰIa\u00137۴f>·y??\u001f~m\u0002n\n\u0001g@\u0013813N#<h&y\"<\u000ewj\u0002\u000e{\u0000S\b\r{Dr\u001fX\u0005M#\u0014ۑ7\u001fCa\u000epf8HL\u0012K<\rZxK{D#\u0001\u0011Lk>5>\u001f\u0007\u0001\u001ei!X\u001e#@\u001bX\u001d,pD@?@\u0001\nG؇\u001d\b\u001au\u001dP\"\u000e@%@-@7&!\thI׷\u0011䞨\u0006(ԍHQ\u0004z\u0001q\u0002*\u0005j\u000fT\u000b\u0017P/\u0013{h!mQw%w*;3DC\u00124V|cVr\u001a0sFA@\b\u0002k\tpn\u0004ܛ\u0001\u000b{ر# H\u000bx\u0003&\tpx\u0003\u0003>쎀D-\u001e>\u0005\u0011N\fa\u000b8q<}hwzSy\u0013(؛w!Z.}xrVm9y\u001d3x\u000fgbQ;I\u0006j|\u001b\u0002KX!b%ʗp\u0014\ba\u001a)\u0017-\u0012\".y\t\nf>.`!zb\r+\t\u0007%WqZ2\n\u0005[\" DDfZ$^\r\u0011cU⯎?z%؂mk\u0011\u0005\u001b^̺$a]x6%W-\bR0`%m\u001f\u0019K:[\u000b[`2VbK+̳\u0003mpFY7XFWB98\\\u0003u`ܡU\u0010iD\u000f\u0010h\u0015FZ\u0005eDB|`m/mGn\u001a0\u001bǉ\bmmp\u0004wӍ\u0010*Ote^t\u00078zg*_{t\u001d_\u0012j\u0015s\u001ez5f[X\u0018pAz8L\u00151\u001e-TDcW;\u0005Yd-NaI(BW v/cH|Kq߂#w]GpGql\"\u0006h`$ \u0004T\u0005\u000fBS\u001b\u001e򱆙y8xS\tVta\u0006xTǺC2\u001f\\r-\u0004厹%L\u000bޔV\bc\u0005\u001e&\u0010\u0016s-1sF+\u0017?0*ߛg\u001d\bS&\\g\u001feo]\u001a\u0012BO\u0010\u0018\fc1VrOch!L\u001dFv\u001b\u001a~\u0011\u001f\u0006\u001bcj86\tMx5io?|=n?v꓍ܘy*\u000ezIu*ױ<'\u0006w<P\u0017\u0003|\u00074;O0?̱m\u0010СM\bq=A_4GpeiV~\u0019\"S%\r8O;^\u0003vyLO\u0017\u001c\u000euWCF>!N=8,\u0018ۑ Mӥ#v'qa\u001e\r½{^{ylO0԰\u001f+X\u0017JԫPAV숭dk,>UuP\u0016J׬7VYT\u0015<peU(\\hi\\\u0007hsݒH*׎pu\u0003Uś\u0001\u0001\u00194\u000e8N<nm\u00009o\u000f4\u001b\u0006ѡ`3)M\u0004L\u0013lfN;G\u000eW\u0014G;ws\u000f\b\u00134f\u001fhs@\u001d\f\\p#'\u0000hxg4뀌o@I\u0004!\u0005\u000emI\u0003\u0003%Ζ.<fQd+\u0005\u0005\u0016\u0013\u0006ӍW;YAϺh+:ZͪYe}gխod\u000fnv<Ȗ/7(#tj߃ll\u0017|}i߃m~e/˭㏅\u000e ^\u001fl'[G;6\u001f#{^N։\u0004v4!c\u0007 {GYwureo\u0003m.n@۫\u0007wúǺ˺rq\u0007\u0016;둧CsCֵR\u0011U^Q%\u0014&(ZV\u000eFLY\u0018\u0017\u0019\u0013\u0011\u000f}\u00188[\u001e\bz˱H\u0016f@[\u001cb\u0017\u001a\u0012 \fH\u0007i\u0001q\u0012 \u0006\u0000\b\u0001N\u0001vu\u000b<t\u0003\u001eag=\u001d\bgt\u0007*ۂ@\u0010A,3\u0011@\u0004ΉD\u0019\r.6؄\u0013\u0016bsMpŦnO\u0000\u0003`|\u0004$4p.\u000epB\nJMp\u0006X\b窃Y;\u0019`yaa#,v\u0007K\u00005>`\u00136\u0015\u0013ymC\u001fԷ z\u001eag[ع\u0019o]L\u000b~O\u000b\r?JA/\u0013yb\u001e'Loiwrۄ\u00111\\\u0017\"obx]g{G|\u000fո_d/\u0019.<\u0017fx3i\u0019\u001er\"y7\u000b\u0005\u0006M%IToW!\u00127\u0000}RN\u0001$ؾ\";)L*&.DlIX!һoLR*kɴc<[\u0012A̶\u0003WQk[ȿ3/k6\u000b\u0014\u0005];\u0005\u0012؋E\f)5R\u001a\u001c\u0019d=<\u0010\u0016<šJf邱Hc@%xuw\u000b{Wr,ְQ6gT%i9\u001b%J&P*Tb٭<O2\\03\u00034PW+\u0019\u0005B\u001aVn\u0010fz\r'\u0012Q\u0004w\u0017  6ȓ<\u001dDm :qa\u0015\u0004\u0014\nGl\u001d+\u001fy ۞mB%oDFwE\u0001A\u0002\\ფD2\u0019g\u0015%$N\u001eH`a\u0012Ox$QIU\f8\u0004\u0011({\u0012(\u0007\u0011'g˗J\u0002\"`q#ځ\u0005\u0004\u0005\u0018H2\u0004X\u0005R H9]-\"&䚀Kn\tm HF쓰E<|ò<\"(\u001f%@dcNA\"q0i#\u0003߉po.b$MI'4\u00021 \u0012tD.\\l*8\u0011vic\u0005;U\u0006S'Cw'B\u0003G#6\u001a\bE\u0007o#̶A\fd^\u0014if\u0011dU˒~މV:wo`lBR\u0006%\u001bqA\"\u0002|sʕc{T젋~Hu覟\u0002uoX1c1FdlK\"7:Ӣ\u001b\b'\"đ4w\u001dG\"\u00074o\tt \u001a=\u0010I\u001cμ;r̿<&,@\u0014.\u0012H1\u00107r^f^9{핻W9||rӪ;RGBH\u000e1I\u0004\u001eh*d_\f|GJ,\u0014bL&5\u001ed-n|\u0012\u000b(*̒O(<ʁnyx0\u0006|uě Ҩި\u000371\u0007\u001avl\f93b֑P2\u0018NfN d[GHОm]\bjqǫ\u00050?vM5E؁w;E\u0019\u0019~Hhq&[dxmէ99\u0013\u0013GcZ+\u001d_\u001cF\u0015<8ПМod#\u001f\u00192Bz}\u001e\".W2\u0007a%gs9\u001cl\u000e|6\u0007>\u0003́&gs/g\u000e<gTxt\u0012^BJM\u001aSI4sN6Ow1a\u000e\u000b\u001aX\u0004q\u0012Qm9h\u0014:n\t\u001eҡ\u000b8l\u0016\u0010\u001aC\u0013v˽A\u0003\u0004\u0017;\u0011З˦h\u001e7N%\u001b\u0004\u0010PC\u0002/\u0018]\u001c؇h--ڰhM\u0006Ǵm\u0016mh;m<cvp\u001bB0\u0003oWZON2ZHw5F\f-4sHb]ҞMr(XXƪ{\"y-uK\u0010|ntVolv\u00114Ǆ/nE5[?PhXiGnAVq\u0004?OXX̞ֆ1k</L[8\u0019w\u0014uY[79\u0014;q`,wMO\u001e\u0016g}\u0007l\u000bs.i\u000eTo\u0015/u\u001dIvC!4>\u0013@Q#ϖ<\u0002Ŗ\u0017'<GQH?\u0006RIQ}\u0010ڭϑ(n8FzSy\u0010{n282\\)\u0002ۙ+=hP.\u0002\u0007QxI]\u001b[`(<h\u001b;\nǣ3i^TuN9x'>)iF+\nE\u0011#\u0006k=D%b\u0019&uA\u0014\u0006RHm#Z«^0kC\u001a\u001dqٌ]{'Q/r\t0\bzuG\u001aŬ\bFuV\t2nmHE\u0013n\rt\u0010\u001f\u00012i\u001d?\b\u0012L-\u0013eƖ6\u0010\u0017\u0010Ba\u0007Q\u0006@]F\b\u000bqm\nqʩ\u000eOZYcuiA_9KXhҢ\rE\u001biӲ5Hn޲mNmق|#17#?X\u001cv~q\u001b6q\u000b4s .JڢZg߅\u001b\u0004fҖvֶm\\\u0005qmtmp-\u0015-\u0016ύ|+Yl\u001d\u0016m\u001fvU}mOMق|#sI}\u0004S~RYVi@\u0002\u0004N&\"$B2d터\u000f\u0012J\u0011UbDU#\u001ca\b+HXEJ\u0012qK\bdm4\nOiJ\u0002OteVaCW\u0014Ds\u0011E:\u0012|[\u0005fsǪ\u001c7\u001b~N/Xeۃ4Z6\u000bT_~?|Յ\u0011SvgH3V \u0000XC:!\u0010\u0006d\u001c`e\u0017HP\u0014\r\nD\b]\u00025E!\n?\u0019R8=dWHgo]uD[ծPq^;X/H\u0007s.߼?J^7'9/<;8\u0004k\u001ao\u0001.\u000b?nNJ3oūO<v>ጫŉS\u001a4g;|\r0o sgVϫA)\u001dQ>\t\u0013-u\u000f{Ђ&8\u0013;XC\\\u0004kwuК%YJZ\u0000\u0011\u0013q0F8 y 5A*\u0010c?^?DԡH2\u0005tQh7n|\roH&\u0012pY5$8Ѣ\u0004Z~􋞿S\u0003`*%ZL[c\u0011U$7EbՋ֩ǉ*Q\n\u0015soᒇVW8ǋe\u000bKc[\u0010g5\n<IN\u0004GR=K⽂:[x\u0005{s!\u0011\u0007Zz+P0\u000fI\u0001\u000e!:\"\u0011;~DrQMޠ\u0000M\u0000HR3W&%2\u0006\f;O=\u0017-;*_-2wa\u0017X-}vۛ\u000e}+\u0016-\u0016\u00173\u0004SEZ~M\u00199\u0017l)\u0016\u0014sr:.q5Kv\u0014{B\u0019Ufy .MV\u001d~Ff;K&~e%C/^Js\t\r;\u001c@'#\u0007Lfe(iB 1\u001e$vjrNp4OY\u00148+!S\te5Ë츪[Y\f%/W9J.h$\u001dPD\u00071j\u00046ʝ\u0015;OU)r\u001eDlM\u0016,pK%^s>[7| \u000e>n~0\rXm\\\u0016tAA~\u001akhs^\u001bh\u000bu\u0013i\f\u0016</rgi\u0005\u0018a]в\\O.{ s2\u000eLO|3\\c\u0005\u0005;\u001a\u0005\t\u0011\u001cͿt/A+K\bH#q\u0015oI\u0010\u001e)`\u0002/&\f\u0013Q\b\u0006\u0012<G\u0003,Ƚ\u0013;RG~v0\u0004\u00005(\u001b\r\n\u0007,i\u0019Q\u000b:\u0005\u0017\"N\u000bՑ\u001bbeE&~UG1#LL\u0013acYPFYEՔ\u00115锛\u001b6\\R\u0005 ^z\u000b+P֮[\u0001=\\\"\u0003Kib\u001d|HZՅ2^^:9w@zK4^i㞨.].\u0015R{Y*՝OKfѿJlSa\u000e3g_j11\u001a34i2.4\u000e\u000b3E\u00141pkׄ)d]L\u0000\u001c¯`\u0006\u0019>\u0019òo6,\r#+8R2ՑK\u0019kT$j\u000bLcSI֕g\\Slzl\u000bnjtU[\\uA*eZtƾdy\u001d\u000e*\u0016\u0012\u001e\u0006X(%ÌMU1a\nUa\u0004EO-Z\u001f8\"k\u0014`'\"\u001c;l9,\u0011s\u000e>L\\-炥\u0014s\u0001><\u0013η\u000bؖt`1Np q\u0007rv\u001fщdayJI[;\u0001ӶB?|\bwolO!v<\u000eשm\u0007aݣ1h\u001fC[1\u0004\\m\u000eŮ\u0006\fdt\u000bWr\u001d<Hr\u00073\u001b\u0013t\u0010߿}{\u000f>P\u0002|^=|x׳\u0003n:\u001cx\u001c}}}}}}}}}}?K#}׳5ﶯz}\u0003WH\u0012}Rb\u001b\u0019SSr~]\u0016\\\u0013YLĥaQ]/]6\u000eb%j$Uɰ6\u0013S\r\u0015Evo8e#\u000b1,Z2Y\nן\b\u001b\u0010k.9frLlQCj\u0006x:Ξ:x\"\u001d-h\u0012l)[1q9\u0003Nc\u0013\u0017Ma+&\f82\t̀BlhjQ\u0019`\"{Ș-:I\u0011NpK\n\u0016Y\u00154#n{uWwo^\u001bq^bf\f\u0011Oi\u0007|=ȩDj\u001cSv5sB'tHc:B>aJUlM7Nc\u001dQn)uLPW%\bz=;*k\bWui8m\u0010\u001d{(\u001bbw̜iC(XM:KB\t۔\u0003Tm\rP)kDɜ|\u00077JGw\rސxp=u\u001co.3;]Qi:b\u0016QH\u0016T\u0016K?\u001agd\"e\u0017h_Vb0ޕԬ\u001dA~\u001c\u0015'P8T\\\u0015w.d(:F\n6\u000b7w@ \u0001P[\u001f\bc!/.Ň8{\u0015D5$_NX@e\u0006\t<\u0019`cvm\u0013D4Q\u000bzn[+/ε\u001cihAx\u0019j\u000b;Ґ\u001c9%\u0007z3Y$f% hnْ\u0006\u0011u҈j|TvI|ȏ{;nŋ{0.:\u000fȮE\\-XPtiAl\u001e\u0012E7T{ZY:]--\u000b|撐Vǚ\u000e+&\u0018\u0016!sIGə\u0005%\"{goSnYCeUЃ\u0005D/ɜ{(\fEDQKwAA;\u0014\u0017\t\u0001pte=9?\u001d\u0003\u0006\tO]\u00199l2&A]EN\u0000X\u0017\u0015kfm4J՜ƅ\u0011Y0Bay;{I:\u000fH\u001d㼆yOy\u001f_z\u0017{wm^pM߈u&DJבܢx%$xv$|ZPT5jq=|.ع(y~:\u001a;{\u0012pU/\u0006>b\u001d\f'ǟ\u001b%㳨YukQU)e+u43.\u001f)E\u0014PM:\u0019e1Ҫ\t* \":>Cf7\u0006ˁy`\u000e\u000b+\u001dEۃ\u0005\rmP=gj<whE\u0017m\u00102\u001cs?\u001dJRc}1a\u0015J\u0007\u0002gNK٠\u001c\u000bl\u00006>G\u0001sw!n{צŢ\u0001a\u0018ۣ0hu:h\u001aٯ٦7qE\\/e,sedΖ2@Վ\bX^ʒ,2\u0018\u0011kgH`\u001bnp墮O\u0015q\\\u0018^bI\r\u000ft\u0003Mt\u0017CіnCXY׊ցYT;Owt\u001d߈l\u000btG2JW\u00039\u001d\u0019DAډO\u001cl2L(=:z0ڑ.yԑ9ֵ`tJ\u001eX+<믌\r&'$]d\u0007]P!WSu\føH\u001328\u0011w#GVG\u001eo\u000f\u001b4\u0013^\u001dx^l9Ԝ5\u00043[ꙛ(sc.f\u0002:h\u0004P\u000ȇQ4ZH}\u001f((A7ჸ\u0005vl1B\f3^sC5~r'+,3F\u0015ѝ1J->\b!<\\*\u0011&\u0010!'(G5q1=5#<5Oc1-<\u001aoF\u0000TkBytm<N\u001fh\u0012p+#c:a:\u0007u#\u0018GϑFU\u0011zO\u0003OE-O\u001fc=0\u0005\u0001>f\u000e\u0019z!jkf\u0007:\u0002HǱ}xW\u0017S\u001a\\\u0015\nqvhJpAX*\u001bn1yW超70\u0014T2x\u0015xy\u0017m.td%1A\u000fno٠r?ȱ<wxMU\u001a\u001e)\u0011HUJ,npv-/rd2<\u0016\r6$JF/6W\u001bN\u00183Y2dzCf\u001a%7\rb~B \u0012M6gQ(\u001b\u0011Zb\u0013Sڕ=<lsOR2\f0Ǒ&\t&\u001cvvU\u001b\u0002&`V*4a-$l-EN8\b;\u001anGrQj~ĤI)O\u0010ѹ\u000f\u0001S9Dtn\u0012 '\u0011\u000fu\u0002<|<\\-'hvy61eF\n9'HSҭ\n\u000f\u0006\u0016\u000b?\u0016\u000f1\t,3\u0013C|J?1$\u001299o\u00149\be꼊_%)3LSyygbQrZV͟#\t\u001b1Qp$\u0012\u0019ʨڤD\u0010¡v\u0014)i-a9K'$\u0012[Ow8!\u0014;ujRz[E\u000260S&cxU\u000f\u0004fkJ\u001d8bici=3\bٳEKҜȐҜxI$s\\e,Jo̶Ppm!MmIO)L/bGSU\u0014WYN\u0017lhp5{cD33:\u0016\u0004\u001d\u0003m,t\u0018 \nm&n&ycirOYk`K\u000e&&TU1lnZ*cƇvڤB_Z3%\u0019z\u001a)I͟>nf93f\u0007\u001a\u0002Nj\u0010VUq&(H\u0013\u000b\u0016jV*Բ\u0002mIeʪJc9ida yyuW\u001d05&Bo*̻\u0010}pŝFI\r*gj˳X >y.fj\u0014\"K\u0001\fLs;c#wFrbe\rCRg|]Z\u001et]P\t]9P͜JZ\u0019~QNLӶ\u000fEy\u000b|a\u0017@NNya\u0016;zs2-3o/_X\u00182\u000e&&\u0018$\u000f#\u001a\u001c\u000fME\"ً3\u0013\u0016Y\u001e\u001cMNv\u000e؅_\u000eY/^OnSOms}8O\u001eU\"!d\u0013*6чW\u0010pIx=V%OS\u0013vY7S.3[]\u0013!i\u0015uΫ,\t\u0017/#\u0016ָ.^h4\"ӣ!`䎝%\u001d%j,\u0011æIŒ/p^e]iZk^\b\u001d|ak.sM3p\u0002Y\u001e<\u0019_&59;c\u0012#OˑkRLj4ܩf6Fagx\f.  9K$\u0007oE(7\u001e=!\"aR͈cjp\u000b \u0006/\u0015LKs\t8\t\u0014b\u000f.\u0014\u0012UҐ.RC\tW'6ʹc\u001c\u00014Ϧ\u0015\\Z%rF\u0011MvVVYN\u000f>\u000f]\u001dt܎\\&7\ry\\\tYҬR\u0006[+'\u000fC\u000f~2Ia3YLYG+\u0006*v\"<;i<:YVi,&tZi`mYȑ<2\u001fx}6\u000f&\u0004霂*[\"Bvpr^,V\fUGZq\u0003\u0016:\t\u0014*. Z6*7\u0010lh.[\u0005V8_Ҧ-\u00102\u0011U8\u0015ԯA%V\u0016\u000f=u8\u0015W9#\u0017:\u001alAA\u0007؜Y{~\u0006Jn{\n\u0007\rzP]½\u001fB\bάD(\u0003\b.Z:qa0}6{J\"\u0014>{,WMai\u0001%/\u0005J\u001a\u0007\u001a%פG\u0014\u0013_7}?\u001d} }2S\b3a_]xC2\u000ea?硫y<t'U\u0011\u0004i;ܣ\"Ep\u0005dvj޶ROY\\\u001b\\\u001be&u\r❩\u0000ED\u0000\"(\u0004T\u0001\u0000 љ<Wrۼ{M=SA-|\u0005\"IClٱK!g\u0001O95D \u0011pr\u001e[Yߋމ>JO\u000b[!|\t\r\u0012\u0004(9X{5^P \u001e\u0016\r~٪\u0018]E\u0005*\u0007$&q\u001dK\u0014,K-vr.ЌT)S\rf\u001f\u0014ɆAږ*&py'z3\t,3\"Qr$\u0016Ա\u001cDc׹m\u000eB\u001d]pY\u000b\u000e\u0016\u0019\u000bvcm\\ʕgISYVIqNdֵ\rul\u0001=3}:qgtδ:<Vo38_\u0011\u0016bBމ?\u001fĄ\u000fdAS6H0.`VZ\u0007O|hK~s\u001d>Ö\u000b=,i;\"^N~\u0005REN\u000b&\u000e\\D\u00179%/r\u0002\u0004\u0003[\u001b,\u0006\u001f\t16`\"/Yr[یݗ\u0018rbO&\u0012%\u0014eCk\"\u001c'm3\u0004$ˀl\u000e\u0016+:?\u0005\u0013\u001c\n\u0017\u001c5(N>T\u0002\u0005[Y1\u001dVq-@ӨB˲\nz.Q4VP5(@ddd\r\u000eY3\u0015T=\u0016\u0011P5ig\u001e띲o\u0012I{\u0017\fEk\bh*hZ\u000b\u000fQȎQK?=jX\u0011P\f.z )jN'm\u000eO+e.kVM8\u0014֜nB,A\u001bV\u0013_ˋh[Ui \u0015륉eň\u0017â䰻JV,\tO\u0019DMc,M\u001fY\u000f\u001e\\gIS\u001cV\u0000=ήT-\n9H\r`>>\u001cEQe\u000f\rN\u0014U6iQc}%yuw5שUG\\\n'ꐴ\u00166kXn,'k#)'{]\u001aE2i{V21=IӸ\u0015.\u001b}e* \u0005a\u0011>dOޕ\u0007sh,ggY\"zK9\u0004\u000bФ\u0011sxRǊT\u0018e\u0003IЃz4d\u000e\u000es\u000b'\u001c4O\tN\u000eK\f_zs4P\tӠ~}bIWt\u0004\u0005|5&\u0018~\u00077\u0018i:Յ7n+!\u0018`-oa}F\u001c_\u00167Z\u0016-\u0015\u000e.V\u0013\u001bm0\\x`r\u000f]Z\u0002E-FݣYhK\\ %!S\u0013*s\u000fd`*F9\t\u0002[\fz\u0002rêř6RSA\tY*aQpR\fO1{*N'\u0002\u001bs꜕F5=\u0016ߓo¤vֶPz\\QQ\r\u001fOf\u0003j\u0010\u0006\u0019nX6YlWfmecF-y,_d\u000bg}S|o&W\u001d5qۇl3\u001dQ(fľkO\u0004M\u000eYʎVF3J?v&UQt\fn\u0016؉wwg[\nb_\u0014\u000bg.CmCPEӈ[W@V(\u0016Y6\u0012X|@RSi\u001d$;03}yIJr(\u0011Y(\u0001 e\u0013&n\u0013c\u001e[\u0007sfJi?wr/^\\`&O6AK)@K\u0013|\u0012+^\u001c[GNz-dԓ$-\u0014\t^\u0019\u0002+CG')֡\th^\u001d9N}\u000f3_w\u0006խֲ\u0011#|h7'\f\u0007N\u0007r`2嵗a{:LVײM\t.<Sr*l|\u000e\u0017C?\u0003St]%6.rvN jý\u0016Fł#Cak\u0016]qxD\u001b\u0010vXΛѼ)mi5Բ\u0011Xmk\u0011{g\rvF6ghv-tƆQ\u0014g%~\u001433\\\u0018\u001f%#^\u0014f9Vk\u001fl\rgQlp=7c\u0017xZ\u0012?\u00029K\u0019olGy\u0004o-ZzI{/tK\bf-KhJ덿\u000e\rTv(:teм\u0018d\u000faH\u0016K!t\u0013lk۟Ѹ>C\u0003\u0013Ym\u0015sr+7/\u0016>1Vf3[\u001aCaksf8[\n59\u001f3+Rr\u0000Ky\u001bWmϹDPpD)\u0013\t\u000bfAsJjs֕zQ -R|rtu%i--~K/2][iFXVYՄKU)'\f0\u0014ןi.H\u0003\u0010\u0018秳k\u001c?ť[_lV3S3^'2u?EgWYsvtEd,r%{,\n\u001f+\u00155K\u0003zE0R\bo -+.|Oq}ibg<{\u00193CV&\u0019Hz\u0012̓/.nV)\u0011[@\tDxr\u0015q=_n,ݫu`\\ENq\u0019$X#m~*Rhz\u001cɈj@\u0001E.V\u000fc\r8V?W'\u0010v\u000flVFy,\u0002ry9x\\\u0004\u001d(Gz=\u00172Ť\n&.if\u0019i7ę\u0017\t\u00169WL[$)>RK\u0001'Y״\bV\"jǈYe#LHE.$?,Px%ˢ@׷x%n\\$JD{K.Sٙvǲ||\r\u0016ar7ou+\u0011,\u001eq\u00135$ZvpډfXy%*o\u0017\u0005{*\u0016wUyɻ\nߘUId9Sl*\u000fK\u001f\\KO\u001e+\\$g&\u001e\u0017p]\u0013UNbYm[)Q\u0016=%5òe>\t+\u0015)`.s|].#\u0001\ny',Iq8\u0015Ն.fi(\u000bɜj(,ueiX^5\u0016]0`%rS\"՘_V&w\u000e6\u001adI\u0015\u001cJ(\u0007JEX\u0007\u001diX\n\u00174;G}Z\u000eT7P/I}\u0001'x\u0001EB<\u001fI): z\u0013җ9)(i]ũ\u00023Ҽ\"CY4d\u0010yъ\u0018\u0016\tr&]NpkA:/YSq\u00127ʵIb._\rz\n\u0016<ߒquܷ]W\u0011\u001cgQ\\(\u001bc\u00152\u0011RsDw67;N\u001af[\\eK\u001f*\u000fn)\\r-t\u0014\u000f)3\u0011Ɗ\u001c\u000fr\u001b\u0014I#ʂ\u000fH\u0015{\u0013Wt6&{®#3$sf`\u0014eEN\f-g\u0010\u000bҦ.ZCj RűIXYm\u001a:.z\nrZ'\u001b\u001fs\u0016ǑbGu*.K=Q\u0001D\u0005\\5_\u0012Ӥim;ZpT8͏w\bl%\\\"o2~my\\\u001djX\u0004}\u0016\u0015x|\u0004C:U6\u001ez\u001c\u0016\fH@A\u0002D\u0005\u000bMZ\u0013pW^x\u001eӣb\fDR3\u00002.*s\u001c\u0017Pz;v\n.cc.BQd<c6|y\u0017S\u0005_\u0001Er9~v\u0010k.MGKZڲ\u000e2SU\u0015tAҋkUtr9F˲<eH͜yp93}p8%XͲfFE[\b\\*ft9Ld(uZʉi-%,ӍEE׹\u0001Ps\u0000j\u0016n?\u001aԅ\u000e/*55޺JsUUJu.IY/I\u001aZK\u0014nR\u001cR0#R=k?\u0018/\u0011d*TǼ>0m,ఆUTWV̂rKFBm9Yvڗ^\u000b'}\r\u0010\u0010)$qArXx(w.a;/3o\u0016\u0019\u0004\u0005T\u001c!iZٝI\u0018\u001aIi\u0004\u001a*fqؗ\\k\\>k֬\u001eWD'5L\u0007;Mnɒdb[̓Y;<s^f\u0016\u0010'\u0017/ҋi-\n\u001c|SAV\rTC~/\f{\"\u000fQ\u0003\u0014XAg\u0015v%Aļ~S]՟fm:\u0017-.תPh֔LWڿ=[Tp\rtK6H\"\u0002|sJ!q%\u0017\u0016\\ez\u0010Y\u001ej\u00163:`B\u001c\\PJXu>W^\u001b50\u0001\u0012F\u001b]Q~JV¼[R\n,U\u001bt\u0017\u00177b/:pq<g}%Ɨ\n~*j/3\u0017m޻-)\n@\u0015Nn+W\u0000\u0015VU&WٍP\u0010WZVҕΕhW`t\u0002!bO=B4Cnjֳ\u00191.\u000ft\"%p\u0004\u00125{4IF\f݌O\u001fmz+Kk>+\u0012\t\u0002.Ny\f=Eg\u0013jSUMEj:\u0019j@e\u0013*\u001f\u0010>\"x\u0007%R\"PLzA5k]\u0013|=C68䋒#E\u001d_pu)%ܣZVb}t\u0016mXqѦU2>m\u0016mhc=Vryo\u000bɭA\u0012:]ϘKU\u0015<Z(7\u001a\nE2aX\u001e³Д>|/>Ukwm}_\u000bwK$}~ce\u000bl?)oEP\u001c)D\u001bicF ߊAzh}\u000eb1{Z\u001bc<$\u0015POcf\u0016'c,5\\Ͽ[r0~\u000f>Bt\u0005F\u000eH?49\u0005\u0005V>>\u0012H@Һf{\u0011[I$0nbG,\f>J\u001c\u0017ilQ}\u0010ڭX#Y\u001f8\u0013G}J\u001fs6bj\\,t0\rm'\r\u0007Y.\u0016l\u0013\"j\u0019\u0016Wl=\u001ckEi:;verm'\u000e\tѳ\u0012`,]uA-N$\u0005ZX\u001a@Z4r\u0015\b;J^j\r\u000bT\b^D`\"\u0014[\u001b\"{\bpk\u0014\u0015\"5\u0011)\"%GEL,\u0001j(jIQHˈ- \u0011\u0017\u001aJOߑ\u0012Qf>L\u0005zD-a\u0007\u0006km\n+\u000eO[YK)V0q&-P*|\u0018*\u0010Jۜl۲\u0005FLRi7}ٻloLW_K-kڄ9\u001d4ޙEkUXXE#_p&詐2ˇ~)D-b\u0016\u0011a\u0016\u00198Ř?,$:\u0019q?c\tf9Uk]իZg\t\u000e4>QK\u0015XWJuJj_QUbMU5V%E\u0016\u000e;V,ڶ\\~Q`۞L*l*\u0016x$#u\\`f\u001d=|q\u000b\";*\u001erwBe]8!6uOBU\tZUիf@\u0000֮~5C \f8Q\u0004\u0004\u0005\u0012j%E\u0002\u0011h*@Ma0tw\u0014o\"\u0015۬l\u0017!>/Ez[^Ktp>wX}wnw[i|-j\u0016l_Kp\u0006b\u000f\u0019\u000687[J{|kx>xw\u0016\u0012\u0002\u0011g:u<ٹ,\u0001i:v$1\u00070otv3U ǔ(\u001fPބ=nhA\u0013\u001cV\u001d!`õ;mh͒Ah%-TuD8N@\u0018#\u001c`<iu\u001a \u0015lUi\"O-\u001d\u0013ތ\u0013WB㔾1uk\u0005\u0001\tD\"QNp5/\\`FDv\"\u0011v\"\rb\u001a,H\u0016\u0013,Ι/E\u001bXE;I)\u0012^ԵN=NTb\u001fw\u001a_pCv+E_ǲ%-f\u001aKk)?SZp3\u0015wEgW\u0019\u0005P-}D\u0015=\\lٓ%+\u000bQFxlUuDz#M\u0016\t]ze,d9\u0003@6\u0001,+{eR\"cckEh٭_\u0011]Usx\u0013)|m˖\u0017ND/XXqݚ\u0017ߌ//S˯a|s&bAN1'\u001c\u001dWdwKy2d.\u001dA\n%]dXݩ\u000e?[#\u001d%\u0013?2Lhⴤ\u0011q\u001c=?a\u001ddwRX6fehK\u001c\u0002 1\u001e\u0013prv\u0018W[:\u001c\u0000bF\u000f;~-)C\u000f\u000esF\u0001Gt\u0010s\u0003n\u0003}.ztg7E\b\u001a%\u001fW9K%^s>[7|\tњm\\\u0016tAA~&Cb\r9ڋ3\bל?},OlBW\fx?/m\u001c*iC\u0018a\u000b\\O.F s2\u000e\u001bO(D(\u0019Փ]YPcQ\u0010Wuv\u001dE}^\u001cBG.{@\u0002Y:\u001f%Bm.$\u0011\fRb]A0A.Y{'vt=A Jz4ר۱(\u0002Yߋzqz\u0011V\u001d0Y& P\u001d22*\u0019MܖA|\u001b.h\u0002\u0010/n}\u0015\\jek-Ԁ\u001e`.h\u0001%BӃ\u00154]hj\u000beX^^\u001eҒ\\zuoJU^\u0014ep˥z\u000bZj/K;\u0014е+Yi0\u0012Ta̙EZ̳z̬\f+Ml̥j4MiL1u,5b\nY`*śCV\u0015 2J\u000eaOxW\u0018FVqeU\rNO.46d]y5ŶǶ 薭&Ng^Ÿ5\u0015X\u0017@\"^F|{Iк5S\ft\u0014\u001e%\u0017dcPsa\u0019sᏚ_\u0007o\u001a\u00055\t\"ݎ=}[v;6\u001ar|.u\u0007\u0007N8\u0006\u001a-%<|GZ\u0001p \u0001Cw\u0003bGt\"\u001a\u001fG9W܍G\f\u0007\f~\u001a\u0011S\u0016\u0011O!v<\u000eשm\u0007aݣ1h\u001f\u001d1ڄ+\u0011`N\u001a,0\u001a\u000b3.St(ּ\u0001\nC{xLd )GTOL\u0012\u0005\u0014\u0014\u0016\u0014⺚\u000bY5$\u0013f,YJ!sf\rUGH,U\"rhI_mDTۙ#\u0016k\u0014 u\u0006\u001b&'wǱP)&Q)\u0016JESEV1X\u0018_Vl\u0017jűT+d\u001elt;:.]A310{g\u0011>#G\u0011\\\u0010cښ\rb\u0005!22xtSS)};\r<[\u00052\u001f\u0003\u0015Rdt\u00124\rG$0S'\u0003S/\u0007b\"\u0016q\u001a~BQ_,UqmxY&D\u0018u\u0005\u000f6*\u0016o=2fVC\u0016{b6\u0006emPQU\u0007{dqlo[|\u0007T+٪w\u001ax\u001d1`|}f'hbtO{\u0012\u000bc&\u0003jԕZ\u0019$~]\"DN \u000f\u0016.z\u0017.1r\u000emaW+\\Nzk^0<.V^Sy\"h>\u0014A\u001bU!5f.?\u000eO\u0017\u0015KR\t\t.q[xՙs2*K\u001fuahC{}w/Px]^32gԗ}\r.}՝]Wnu%E&(+g@xFUO[\u0014vVkzZCR.P+p\u001frݎ\u0007~wr\u001e;L\u001b\u001b|bw˽Y9e_)U;\u000bY:q9/y\u0005+{Zj!FF_\u0015UL\fRQӇEM%\u0015U´\\^\u00114ݱ\u0016=K`岗M&[*\u0017=\bE{zXͅ\u0005\u0007ȏʋ\u000ba\u000b\u0015Y>IqV\u0015\u0013C!'^,%\u0016\u0012OR\u0017\u000f\u000b9\u000b\"w+1CH<8$š\u0014\\ˊ\b2,EqCQ'X8\u0001'\u0012\"I\u000b>vr~Kq%=xP8\u000bI\u000f\u001dMX\";F\u001e\u0019Q6\b&!q\bV$\u0014\u001a0D\u00175\u0015_m\"d#\u0014Yxe_$\u001aϗ5aNa>\u0004Uf8ԕLi\"z\u000b\u0016\u0004)\u001f$Q*P\u0006/QRMx\u001d+q+Mu/)1L˃N\u001fd[igvbl[(\u0014HǲӒ\nJ\u0002Jǎ4<K\u000e/^^$YJ9Tr\\z\u001c\u0014RBENO\u0002=+BJX<-\u000b,6.\u0017?\rNN9jtJ\u0006-Z\u0011U2ga&ϡ]B\u0003\nH}}8/^E7!2I\r\u0015tcE*vbCU.-dZZ\u0013rL)v|Y\u0011v\u0012\u0019^u)\u0019Y0xzZP\r#^~WKautٮζWB\u001cYa;]s)\u000ej8&x\u000fV\fw\u0011\u000fy->MwlѴ\u001eD\u001e'UvҔ4zד<o,3]\u000b\u0015qtf\r&I'x\u0019sQ\u001cka\u000fVPgg\\9\u001dQGy&3W\u0016VRcM-r-r_y_Y5r\u000e>H\t\u0010\\FK\u0017<tz6d-A(βN\u0019w]\u0000%\u001f\"\u0010k?'q\u001ē5[(q=\u0007q\u0019y.\u0003:e2s(\u000fCڇ\u001f>\\Z«ҋ\b~ān-H\"\u0011f9'3&Qmhj\r0XIa\u0013\u000f\u0016;\"û\nnN)^&=2G>Ә{bZm\u001eS.·Ò5\u0007v3\r@25K\u001b\u0019\u001dZ{,\u0012FG\u00175[ak\u000frkħcЯ>\u0005K!s.BE5q캱g&_[q̽\u0016&xM2 'yLe\u0012ŷmʲA\u0015Emgtik#YX\u00160ى׷+r\u0017^%\u001b5,Vu\bIՂ!\u0013}2*;lBg@y\u0013\tRywb;J\u00141`mF\"+61S|\u0014gj\u0018Meꦖzp~\u0016\u00067m&5\u0013TrpE]\u0014\u001a\u000bQbK\u0001 NZCkf\u0004D{VIA4juāE\u000b\u0019$xzcX\u0015\u0012c$\u00018\u0000Bٰ\u0002\u0019\u0005Gu;2[%\u0010\u001e\u000bW0V\u001cvEqM;/ :\nʪD)\b͟\u001dҲF;q$֦҂|{Vz@Tc0lrpO`RTKG]%-C\u0016ۊK\\KNqW_;6#_s\\q?\u0005ڊB`/LUq=ۖe:쬐;\u000f{ݧIYQ\u0007ˌ3{\u000eoJO1{z\u0010\n\u001fj8_EڔUl \u001e$\u0016\u0014\fJ@=\u000f\u0013bJY1\u000b\t\"*\u0004\u0016\u0016%[\u0016GA~b;kͳVg]\u000beI#\u001b\u000f{$o{S\u0010\u000emЦABOEkkݢ9#ioXRm?UG7ߝP֦tgݟvW޳sjyA45U}ٕr6,rˊ\u0004;d\u0003a\u0010\u0010c'\u000bML\u001a\u0018\u0018\n\u0012\"\u0010\u0005E5G0\u0014<[/Ho۲\u0005r/c\u001ak>*r9QDcs\f,`\u0010='\u0018\u0016\u0004ؼ>[Ɏ\u0015ᜟT}b;(\u0019>7\u0012_0l]+P\u000bc9FKuFIڻ/0l\u001aMQ\u001dY洴JGM\u0003g,.IӋUr95<z]K4\u0014].:B類P\u000239h\u0016\u0004BVy:SF\rULXq\u001ci:i&G\r<0pi\b}m\u000fW#\u000b{zz0\u0016C>;Inz\u000b^D3\u000fh{_VE|%'$kr,&vERR/ta\fpQtpC\u001cf`#\u001c؆h\f\u0014)\u001e3cm\u0002$xT\b\u0011g:\n\u0007\u0015\u0013/\u001c.۫#w[a8\u0007\u0007]\u0016\u0019$\u001d<\u001dD{\u0014豖\u001fJl<ٓ{#Տ-f\u0005,\t *J$UWq_遍$0eGeR~ZߞC/\u001cuv).JdJQ֬Xe\u000eJ\r\u00129%l_#U>\u000f:6QQ\u001a\\;W+h0dE`H1s|\u000eitUDŰPRj(C-88@.麤\u0011\u000eZ\u0007\n\u000bY$j\u000e,OPSs\u0003;:;\t^\\|f>\fFH\u001dΟ1hU5w}W2K\u001c\u0013G&?A_:\\\u0003\u0013urJ}ɏj6d\u0013=[3+v\t\u0018b[tc:\rΗ(*\u0018 <{\njɺ\u000f\"\u000b\u001c\u0014H\u0018կQ\u0001\n\rtUd'Or6Z\u001d\u0018m.sQmI|D\u0012Qq^O_TG4x\u001d'\\T:a)ΗP\n;\u0000\u0007\u0015\\/r`,\\P9\u0006[&=\u0018͋<g=Ȟ9N9e/\u001c\\wmJm\rbNw\"ib\u0011\u0013zL\u001c<]\u0015\u0012f\t,귛ѳՈ|\u0006\u0007B;\u0015\u0003~7_\u000f_~n\u001e\u001f/=ۏ\u001f޿+i\u0017\n@:ZB0\u0000\u0012\u00049\u0005i\u0019a\u000bj\u000fO\u001f'\u0000z\u0015~}\\$\u001f~\u000b\u0016}q +-U\u0002_C[z\u001foՇѴ~R?b\bu?I,'~LQ\f\u001f6498+\u0019Ǌ\u0006\b#kԢ@P`\u000bh[\u0018VjG`^;\u0002M:\u0001z\"י?y\u0010!\u0001\r\"\bS}qn:a\\[~5rxIs\t\u001aìD\u0010ֵsj߿\u000e\bbf:_w-Q\u000b\u0012\u0005s\u001d۩W~\u0000m3~٨GwW-~0-L?c/R3CǸ\u0010p\u0012\u0016\u0005\u0018XAg*UF\u00194a\n\u0016nt\b_q\ts/A\u000e\u0014\u0001u@C\u0006ܒ7'vn\u0018\u0011F\\\t\u0007SDŏm<5\u001c\u000be\u001e]\\9,ML\u0010h\u001c\u0001'?w1gSƟBűsf@+q\u001a1PGfֿ\nN_s\u0003\u0012N͓\u001bgO1\u001aiX\u0001\u000eٺ\u001a$ھXw\\=|\u001bi,:&X?]\r|\u0007ڈ?w\u000b\u0018\u000f>\u001az(IU\u0019^q$pzX\u001e|\u001eO\u001e[PCF2I\u000e\u001d\n\u00183<4\u000e6\u0007c\\\u0018\u0015JnvX\u001cp\u00188^c O2L\u0012\u0013\r]&b]*f!%pa\u0006\n|A&\u0001OG\u0015<P\u0014袋\u0017\n!ͱ@5}my\u0006\u001dR\u001eBݦu\u001cA][n\u0011?{\u0005\\ц%EU\u0016aIykSCQ\u001a\u0011\u001aŧ\\ǡA}\f^\"8nL\u001b4O1QB\fN\u0007K\u001c\bm;\u0002ne}B]d\u0005\u000fb\\:G0z5xで\u0010s\t[c\u0002;\u000f\u000f\u001aO1`\b+\u0018*CڊW*4TaUl2X\u001f\u001cVTwc\u000f>)G&爋*̘\u0007}m`ջG\\\u0005g\u0014p,G~<\u0015Yªrݔ(iz`t_\u0005\ny\u0013WHq-`gyP|-N^\u000b؊\u0007Y%\u0019\u0015\u001c_&,K?BN{\r<15~`aBS\u001aL?U?}Á\u0015\"/EY\u001a}ß_?/Bsk\u0014\n=I]KB:/\u0011Qj\r\u0002bF\u0015¾*ac˛l\r&}K\u001a-,j?\u001a\u00182hQbJ:Ϝ3S\u0014Vp3M|X\u0001nvv`\u001a0a9<\u0005i\u0018O\t'W\u0001lܿzջ%~%^ͷ\u001favyӛ߾x~q\u0017\u000b\u000f/?O\u00012_\u0016Ѣml\u0014-03i\u0006\u001aL>\u0002 i&4ξ.\u001fՁ-\u0001on58`P(1H{X\u000b1`x24h`Az<\u001ad8\u00167\u001fD\u0016\\\u001f_(C&\u001az}P\u0006Z\rע@+?^\u0007TO\u0002\u0019p\u001fbNŮ?`{`\u0011\u000f\u0001\u0017\u0007\t\u0001_SكZvێ\u0013``aap׶b0\b\u0006\u0006AKU\u0011S\u000f\u00070(\u0003\b<,N_\t3LA0\rQ65Fц7q\u001e\u00198įzam'X+\u0003*u\u0018a#\u0006DX\u0006a1\u0014D\tuR\fI\u00071Fǀ\u000fyYth\u000fUGu\u0006N^FM+\u0010\u0003qJ\n\n\bƽ\u00035 O\u001ceX}!@\t\u0018#+61\fF['oQ]Gyt-Ò#\u000e6=$y\t\u0018Mq\fFeW2\u001e\u0015\fEC\u001eK~ tHJ\u0011`@e\u0000p2fIM:f\u001d̽\u000b꠿^\u001d[\u001eA=\rNK\u000f5:)\u00047c?Z;}I?OM(),tx?'C\t\u0005\r\u000b^h\u0010`3\u00006)P\tN\u000ed\u0007Ģ1|<`'S\f\u0004vyVD\u0015&\u001f\u000f\u00007z\u0012ul?\r쬰6rp$<0\u0003K*\u0007\u0000OAאA=\u000ev>\u0001RM\u0002:\u0000\u000e\u001epXaR4tt\u0000\b괒\u0000{*=@At\ti\u001am+]DӴ$\u0018HH\u0017cw\u0001z]\u001alu\u001cG}\u0019c+v\u0010c([[5z]ہ_\u001c.8i\u0010JP\u001d\u0018\u0011\u001b\u0017ٲF\u0006t\u0018>\u0003 4\u0000ƨ0$\u0011NN3+;2v&0CCR`7v\t+=\u0004bE(\u0011MF`ǾS;4FM{#q:Ea\u0011<\u0000fȤ|vN;&b29MQ\tA\u0012GփH\u001d\u0011\u001e1s\fP\u0004N:\u0003bx\u0011ņ/;x\u00071l3o\u000f\fvfG>\u001c\u00188\u001a\u000ey81\u001ei{#\u0001\u001dNȥȢ\u0003@2w`ۚT0\bF\r#&\u0003\u001b~m\u001fpSCwA\u0018qܳ\u0000\u001c\u0001\u000bAC5\u0001I;K\u00066\u0002z\u000efA<vs!*0\u001agw聪\b:su̎@ȧ\u000e(h\nӭi,)\u0010[$xl\u0004\u001dvV\u0013\u0012@|a\u0013-P\u001742Fgg:sCL,\u0000f62\u0016>ǟG=hK\rh\u000b\u0007_3P\u0004\u001dS\u00075\n1!pl\u00159R\u001cGO@0#\\\u0013\u001dEg\u000bc*\u0014gYXZ\u0000S+\u000eh\u0005\u0007W@u\u0003t,q6Ii\u0017Kӷd!A\fer9E\u0004<+޶;\u0015\be\u0015\u0015\u0001FZvxŢNLf\u00120ĴEM4\u001b\u0017ujeE? *I2\\\u0004ۀ&\u0001hqRLUz6\u001e@\u000bE\u0001i\u0003ޱ\u000f\u0015P4yZmeJɓ\u001c\"m'/]uS'\"8\u0003u\u001e1o*\u0006(H:\u0003'9H$(PaݦzS&K\u0005+k1U\u0006A:t\u001dt\u000e}!=(+?E>B$%b`\u00146\n~\u000bCt\f]G<*;MQ&\u0006\u001b[$wЛ\u00048\b\u000eC\u000e\u0002G/{:.V\u000f\u0000\u0011!\n):(;0ķ\u001a嚕\r˳cP[Qvu\r\u0018}y4:8B6gƒϢIJaI֝we\u001c\u0000P`\u0012.!6<\u0006!\"\nɮ\u0001+6\u0012.UׁB\u0018/c\f\u0004,\f\"\u0000c\u0007ԗ\u0000g\u0011'\u001d\u0017.$\u0003I\u001f\u001d\t\bl&}R?9\u0014\u00153\u0011h9\u00118klea0aTtF$Ӵl0{;\u0016r\u0007®\u00000p\u000bӋ\u0005`UNn: \u0010|EU_0\u001c$\u000bx,g؁ww\u001aY\u001cG`\u0013u$\f-bd)&\u001eNxxыޯ\u0004ܷ?\u0004\bD&L8S\u0012`B;Kx:+1!*\u0016\"N\t\u001dt.Psd\u0000U1J\u0013KH\u00012FI\u0010Mo\u001fnGх@i0dc\u000e\u0012YFeB\u0011lt\r^ؤ\f\u0010M1\u0003E N\u000761GM\u001d\u0011%81?ƓXP\u001a\u0013D\u0019!\u001f3\u001a\u0019_\u0019X\u001a'dE\u0015&]\u0018\u000en$ҏա\u0005Tk6g\u0003|hDXc\u0018\u0014\u0013N\"]\u000fI\u0000Ud'uoAh8f])!\np\u0018lP}\u0012F\u001ev\u00162+\u0002\fa\u0012f\u0019\u0007)\u000e&\u00116[Vـ4Nz2r\u000fQP\u000bdZp]X-04@JuF\bt:\u0010Ez#Se2f˦4vFy(XSm\u0001to@lbd\u0000ȚikZ\u0015V2,f:!69|`2B+UUJD݆,ypյ\u000bgW=~:6\r@\u0010\u0019\u0019*G8vs\u0014s3b,:ԋ\u0006)kM\u0005`\u0015<\u00010b0vQxR8W\u0000;z\bLېq\u001d4h\u0011YTi5N>\u0005J;znC?9n\u0004^֧4@c\u000fN25I\rwL\u001b\u000fȘg`S%;zBXoS>}_jfX\u00188U۝^=\u0005:\u0018Tقd8B\u000b\u0014\u0015-\"]$c\u0003{`\u0000If\u0010\u001d1#tʮ(gGjEe^\u0000F3\u0010\u0006IP4C_=A\u00053\":sw@/\u0003UaH~`\u0000N<Mz$\f4P)Z}HeE3\nYEw\u0001G\u00181<91燝\u0002\u000e\b8 ū\u000e>W(Oϱq\u0001N5bD\u000e=SP~g\u0010(dlɤ`<epZ}'g\f[\t\\\t6|\u0005\\\u000bn\u0000\u0004\\F\"\u0001{Y0\u0010\u0001W&N\u0001\u000e1`1}','\u0016\u0003MXz\u0002Nm=\u0005\u0005`$U\u0011S\u00066v0¥/#\u0010i;HmpUh)\u000e&\u0005\u001cu\u0004Lk\bF\u001fE\u001e\\y\u0011:L@y\u0000\u0001s\u0007pyeP\u001e!jf\r\u0003\u0011\fD+~-'\u001c\u000b`:$\f$M9\u0003щYsl\u0013-\u000b\u001c*\u0000#k\u0016xg\u0019UB,@Q\u0012t\t(k؇Ǌ/7\u0012)%Eٖ?\u000fƬga\u0011\u0017Hٹ\u0003T]j\u0007\"<\u0002$\u0014 aݐ\u000e/ܶU,;n\u000b\"2[Ym\u0014tI\u0007]\u001aWxSwH\u0004\u001cnM\u001a\u001dah:wB7\n&\u001e\u0018@0p\u0017ĺ\u0002\u0010_\u001ctfR[p3}%`REc$$pf-@Ts\u00001\u0018N\f7v\u0010\rkI!杌2߮\u0005\u001b1|t\u000es]̊<[\u0014 \u001bEfxH^\u0015G.I\r\u0011\u000bD0R0\\\f\byM}\u0004\u0003\u0015XaȽ\u001dd)Q=\u001d$\u001e\"\u001f\u001f\u00001z\\}\u000e0@.\u0011\u0004FE\u001exI\u0019A\u0007u@~\u0001:\"\u0010qԅ5`zD-\u000b2\u0001@XM].\u0015\u0010\u0016{]V\b<J'$\"\u0010\u0015c\u001fu\u0005o>\r\u0014N\u0001CT^Wr vJ+^*u B\t\u0006˴.<\u001b$Lb:\u0014!\b\u0003 \u0003\u001b\u0013w0V\u0006-\bPгQO}#\"\u00014\u001e\u0013謈лz?sDKy\u0006v\u000e}DˀE:cdAe\u0005\u0005Ѯ\u0001<\u0003A\f\\,aO*ޑB`Lٮ!\u0014\u0017wN݅&Pal<0rX;\u001a~Iy\u0003\u001eh\u0003Geli;)&\u001b=z\u0018}\u0017Ǝ7';Dyv\u001cKÌ\u001fv\u0013.ڭ[ݓў,Af\u0016WF|\u001b\u0000ѝ1uy\u0004\u0015R3ȳiPg*\u0001מ^:d<0\u0004&\u0018--\u0010+İQ\u000ew\"MC+3\u000e|\u000f/E촷\u000b4MB*禍,\u0001\u000e\u001a\u0005v\f`8\u0019\u0012<cf\u0010\u0006ĳk{\fl;rrn\u0007v*\u0006\u001d5W`\u0015e: \u0002^D-Pn(\u0004\u0004\"B\u0001*#\u0003\u0001m\u0003\u0001t\u0004vjt\niR2E|v0G:\rد=F\u001dq\u0004P,\u0002$\u0019A/N^\fNz\u000bwrnFvaB&F֪z;7\u0010L\t\u0013)\t(w\u0005<,5\u0006c2jZ\u0007\t (\u0014x'\u001ep\bl<ٷʿ¨tQ\"@W` 읎\u001fG u)?+s&g!\u0006sʜ8VG\b0t \f\u001e:\nʀ_\u000f\u0001M\u0006Scb=s3\u0002,\u0007\\̤ؕG8ʣC\u0006h\u001f\u000b\u0013?>dOa\u0003\\\u0017gE\u0016O@`]gv*2+:HP\u0013\u0013ز?mbDM,o'l.I\u0017]\u000e\b\u0014;8*1t 8*[S\u0012\nFa\u001a>\u0015x\u0003&fo\u0003C7cb\u000f]E\u0010U0@q0tu3SzT\u0010H\r}\u0011/ѯ\u0002\u0003\u0019E\u0011&$\u0004F.C̨!R\u0006<9ϊD]\u001cZ`6\u0016\u00057E\u0019<\n\u001eGr\u001bi\u001c\u0018\u001c$\r6x\u001ar\u0001ceY^2p\u0019=\u001b 9¤gTD\u0000ZQ9QT&-\u000e*Eb\u0007RVb@77\u0003IhTR;\u0000UGh\u0007U\u0015S\u0007VO\"9hgT(Lc0p\u0015cII:F736So\u0006M*;xhO<\u0006*^H\u001aME\u0000Νv7{T;n\u0006K'b\u000e,%p\u0011,>?I燹5\u0014sq|;.\u0019\u0015JNZ\tE\u0005\f|%`\u001f0blԈĠhݒ1^\u0004FNuJ:\u001fe`3)E!Aj#\u000f \u0001J&GQUh6_\bm3\u0013ԡ\b'bBëV/Z(vSz\u001dFm;ME#P\u000e\\(\bZCzVE`h\u0004u\u00111\u001cF#\u001bu\u0004>P~\b\u001d)Q\u001fBJ\u0003b yK2$\u001fL\u0000ʐ#@`u\u0004H=ʂ\u0006}\u000eȬ/CZg<IqJDWY\u0011\u0017`ThrM7ZxT\u0012t\u0004Y\u0006J}7S\u000bGғ\u0007d#bEɡxV\u0015l&3Թ;%k\u0007(iԋ\u00010ʎL\u000eLTvzP/\u0019WQ3\u001a\u001dȘ??\u000fQ\u0019?]1bQN[ߔT\bw\u0011Ӭ\u001ahWyb']\u0006&m\bw@\u0014\u001b\u0014%={IA\n\u0019n\u001c&N9\u0012\b#@\u000eZ\u0007m3/0\u0014;\u0006mX\u0012묙K\u0003\u0007\u0012, j\u0019xk>%\u000eL\f[FySgg4\u0014vjAyDg\f\\\u0019>%\u001cTqh/!\u0004\u0014nyᎁ\u001b$~f;\tR;\u0000: \"F2\u0010\u001d\u0014'E{ebIQ\u001b%I`s2\bXWB\u0019vR3\u001bkHD2J)f\ns^AP\u001cԢw\"82pL0v\u0010JT\u0003fUYM\u0013A\u0006\t: p\u001cغΪ\u001bo\u001c\u0001Eݭ\t!$#@`^\tyz0r\u0007-:djϬ\u001e\u001c$#\u0001\u0001gQ\u000eF9j\u0000\u001dI|r\u001c\u0002\"p48\t\u0013x\u001b\u0018\u000fb\u001aЙWGj\u000bM\\Hţifvx@iQ\u0001s*%<\b\u001d;Y`<\u0013:Uz\u0010I\u001eg;\n0}\u0015\f\u001f28Dgl\u0018#Cd@\u001dfm2oK\u0002*\u0011~\u001c`qGi=\bQ%\u0000\u001a-\b4Yn\u0019\u00005zGSH\u001a1\u0016L(%@7\u001d\u0004z(ȑu;8{\u0010u!\u00003vF~\u0018T\u0019w0:AqR+ܲ:\u001a-\u0014\u0000\r*L\u0018fv\u0017b=\u001dF\u001c1j\u000e\u0006\n&Q?\r3z \u001dr\r\u0018D(\u00053cÑ8bYz(y\u0019P\u0007\bG[\u0004V\u0004\bN\t\\Gu(lɋd[x}Gh/\u00126E%A#\bsgq/\u000b𿄄@0[\u0016\u0002\u0017 Y\u001eI\u0003\r1\u000f>\u00120!?;$|I\f6qleTթ[{gmxtUSUgSr>\nK;XE\u0002\u000b0_X\th\tp5_o\u000f]@\u0010p[\u0012:\u00064\u0001kx@)1)LVĊ4n;4GAؽYaq82\rS ~Lx\u0012B{\f{\u001anA \u0016=a3`\u0006g܉$@by!{iF?Щ\u001cv\u0006\u000f҅m\tg\u0014\f!eh\u0005=\u0007\u0015\u0011@)R\u0004\u001c2\u000fmU\fܫr\b'L\u0018\u0015JU\u00008&\u0015ѫH\u0000lIw\u001d\u0013|\u0014?cwt<\u0002z\rv@g(\u0018n\u0007\u0017\u001aҘCR\"g\u0006\u0005cOJb N\u0001<\u0018@ZB-\u0018͹*\u0004\t\u0019\u0002\u0001\r\u0018\bXA\u000e\f{\u0004\u001aht;\"bEr4l\u001eOr\f<\u0014aw9\u0012\u0010&vE杊\u0019 \u0004\u001bY\u0000<]Txz\u0006R\u0010db\u0005r\n\u0000-˟\u000f\u0005\u0001d`1@`@\u0006\bk6\u000fA⻰agGY5\"?:\bw9%IQ\u0019;`[ޔT\u0000'\u001euդ\u0003\u0000&\u0000\u0014v&N@\u001cKTф+\u000f@`\u0006\u001a&6<\u0005@\u001eք`JuL\u000e\u0007Ʌ!\u0013\u00146\u0002l1ME\bҵĸ5Z\u000bǥ\u0006|\u0015°XAqEX\u0016z\u0007#x*\u000b\"9pH)ksxqp>34Q\bXg|03\u0018P\u0002gq\u0018F\b4\u0002.\u0000H\u001b11[M0*OeTy\r\u0005:\u001b\r\f5; @Man\u001b?'\u0004\u001ewಢk\f:\u0018T\u0004y=a\u001cG*i\u0007t0LfӋ(\u0016$\u0002'\u0003\b\bH\u00064겂6t;@m<w KZ\u0010@0On#3`dW\f-Kx,Q(\u0018;k)6\u000f\u000b9p\tZ\u001dyJ\"\u0001z\"1K\"q\u0007b(m2Z.x\u0010b\u001bYWD\u001dsX=W\nȚD2rg\b\u000e$ء@Q8\fJ\u0015\u000emE2\u001a\u000fc  N\u0003\u0004\u0012:T<\u0004\u0002;yڋ+\\\u000b\u001c00,DK>j\u0010ɀ)B\u000fT\u0017\n3\u0001\u0003\u0005VCS\u0013#(\u0011K/\u0014é\u00110E\u001a&bhHf@\u0005C-7\u000bk8E@\u000eύ\n\u0011=ML\\-\u0005\u0007d.M\t@AW8\u001e\u0000Qg&*1zBa6J\bq\u00073#9XuZ~yz,(\"k\fU\u001aϷg\\1\u001d\u0015U\bV0&ngM\u0017\f\u000edg\u0018СqK8D}H\u0004\\~P\u0000zq`N\b(\u000fsD\u001a;d< \t8\b`uV\u0007\u0000(%HP\"cDj\"D=\u0000\u0005\u0017U\u0013\u00114\u0000kaS.˺\f8RvuV6<$]M:@xT\u000b*\u0018\u0019X\u001e:\u001a\u000fPR\u0012A\u0000(Dap(\u0002+craR\u00157\u0001\u0006'<J\u000fH\u0005YF٨\u0010 .=\u0003pSPJ\u0000s59\u0000\u0001hb\u001aC \\\u001c\u0003\u001b*\u0017\u0016\u0015p*l(@k3=2\u0005@\\\u000b\u0017%|C(E6\u0004f\u0006H\t`֘B}F^\u0010\u0000M9n0m⚒\td4[@G\u0013Ji\u0018\f\u0018\u0016\u0001X\n\u0019\u0014\u0015Z\u0002\u0013\u001cUE\fLq1\u0015±u*a\u000e\u0012p*\u0005\u0006\u0016Ưp#\u0005\u0000PÔVz܋\bX\u000fהGc@qGdF@Q\u001c\u0012tT\u001b\u000e\"\u0011ѵ\u001c\u001dd\u0010ÄRr@KW-\"'ڬ\u001a\u001f@P\u0013I+ozc8H7d@\u001cD\u000bU)#.ry\u0001ȄCK,]aAҼBXEs\u00118r5.}M̙\u001b[hASb\n+AF0\u0007s/N\u0002G\rҗ\u001a6΋F\u001ap AB\to3I\u0006-MLK\u0006p\u0000yi¥1e\u0001<JSq\u0000ıe\u00130\u001a,ݐ{W\u001520\u0003Y\u00199>\r\"JX_U\u0013\"N\u0004Xs\nc̀dqj Y\u0010xk\u0015u4\u0017˨<\u000f\u0003Ulk6ΌxA\u0006^2aE+5\u0015{ΣF\u0003p9Mӻ9+ˈ1(g 9\u001b+8@!<\\f|墡K)2\u0018\u0007K\u001754䷾hx\u0003mM4ċ~П(q\u0005\u000e\u0006\u0001\bj\fO\u0001\u0018eUb\u000f<\u0011O4\u0014\u000b\u001b\u0003W\u0018\\qo\u0015WR\u0019\u0010\u0006p\u000f\nO0u\u001d3]2_)\u0014\\\u0015s{\u0017n#h<%xº\u001a4'1\u0003m[Ʌ\u0014;Y-\u0000\u0003STi\u0015W\u0001@PZxw\u00117ߨ5uik\u0019w$\u001b\u0002e\f\u0014m)\u0003\u0006\u0016*!\u0012\u0012d\n\u0001\u0003\u0007Z$uQ\u0003+~RmG\u0011-39T:0\\\u0002\u0001˂XK\bL9\fi\\\u0000^\u000b#|m\u0007\t\u0014gPiZxֱ\r@]UF\u001cn\u001dMz\u001bp\u001e9\\\u000bAd`\u0015(\u000e \fQ<0\b;q\u0000p&B<.2A[ľ\u0005e\u0017\\{,\u0004B_\u000e\n\u0004\u0001!=\u001ck!=G<\fSC &:&򸋁B2I\u0005\u001a\u001a}L[\u0002c@#\u0010\u0012O\u0010Q\u001f7\b]\u0019.\u001a(u\u001e0X6\u0005\u001f\u0015-T\u001b\u001e\u000e2\u0001H=Ӳq\u0011ŉ\u0019^3tXj8\u001e\u001f\\|P/=9' S\u0000g\u0016n\u0006PE|@-nb\u0003,x%\u001c\tiĆÊ\u0019*[l\u001d$\b\u0005\"8҃j.\t8]9XL\u0011\u0003߱u0\u0012mW i\u001acH8\u0010\u00017Htf'\u0006\u0000xa'\u001cLO\u0001rA\u0000]\t&Qǣ\f\u0018⺸\u0004G\u001c\u001cp֟a\\jD\u0006ȑs8m@\u0016qnp\u0019\u0002\u000eȀ\u001a\n=4sVq\u0000<$\tK\bq\r\n\u00023+ns/H\u001a@5\u0005uYFH\u0010ɨH\u0000\bioB\u0004A\\7 9[\u00113\u0013!&\u001a5\fl\"/\u00050?qdXaNb \r̂\u0006\u0003<FHLf,\u0015\u0006͠C=)\u0006\u001f${B9;C/v\u001c\u0014&pi\b\u001aB9\u000b`\u000f]}.΁ ׊\u001b4\"\u0013\u001d\u001f\u000eFp%ڄ{~1(-\u0019zǀK\u0000tPP\"\u0001\u000eƵr5~{L\u0001^\u0016\tӣ\u0017Y\u0010\u001eC\u0015Po3\u0001X WN!\u001e\u000e\u0014\u001fvP*\u0006͚\u0000+LMb{O\\P*[H\u0004%j?މAL\u0002Pq\u0006\rAQn\u0007\u0003h,J'SUqM\u0017\u001fb`\u000f\"\u000e'܀\u001b\\QY\u0019C.L\u001dK\f\\\u00177vp\u00140D\u0012V\u001cv7<V.0\u0017\u001eЀpn\u0007`*p[AޯI^z\u001d\u0000t\u0017\u000b.P\u0000'\u0001Ple\u0011!OtM-z̓\r@_\u0013I\u0005\u0019dE\bx\u0011(Qӱ\u0013)*38* 5\u000fCƀ\u0017N(!iK\u0000@~ב^вIlUaEac\u0018'\u0010Ca\u0015e\t^1\u0000 \u000f\u0006F\u0014\f\na*t\u0017\tq\u00041S\u0002`S{K?\u0010쨸\u000fNED\fG³\u0003,K\u001e$7\u0017^/f\f\u0014M<-[٣E\u000bS1tU\u0001h#\u0002(ڢRQ\r\u0011\"pDͅβ4\u0005\u0001\u0000\n\u0019=CwD\u0010,\u0007K%<W\u0003\u001ev\u0016a#{\u0014~\u000fRehUC7gc\u001a4ѐk1Ւ\\H\u0005\u0011Ѻ<\u0006`K\u001994+ғ9j\u0000\u0014\t8d\u0001Tl\fJ\u0017r\u0001\u0016o\u0012)\u001aNNm\u001c\u001c\u001b0^5\u0003.[:}4\u0007;x\u0018#0D~\u0004?b@\u001er\u000e\u0007jb)4\u0016`]ǔ\n3\u0012io\u0019iڂ\u001c\u00006ř O':\u000eLZ\u0004\u0006\u0005f)ü\u0014,\b$T:.\u0001<\u0017cRxȀG\u001ay\"x|T|\u0018$\u0019\u001e΍藃5\rTLRpLMd8\by\u0014\u001dv<ǔr2\\vك\bq\u0011 ]E(A@#`Ud4?z1$8\u000b,\b\rT\u0015ǒi[J\u000ep\u001fңġ\u0013'9zs\u00108|F*\u0012\u0011\u001f^\u0012TE:/\u000e\f\u001fnX\u000b\u0000\u000150:\u0004\",(C|\u0011\u0016IC\u0007y\b1TUGc\u000e\u001b1g`^\u001b],_A\u001b?0-\u000f8R<UI\\ZY\\݆\u000b\u0010pw=\u0011ed..PN@\u0014$πL`07Mr嗣``Wuz\u0019<(8;f\u0014+*\u0004L|T2+bxO\u001a֜\u0007H\u0005ra8M\t\ngŲ\u001cU\\@ZC\bP;#oL\u0017B,7|\u0010\u0010\u001cG\"0\u0015BOn+&\"Z3L\u0018~XWb׀D!\ng\u0019t\u0012\u0018\rC_\u0002?ؖC\u0004K5fL8צ\u0016ŉ!\u0007P[s\u00020\u0014\u0004\"DcB;X\u0000X\u001b!r%\fB;S`\u0017຋`x!3\t1d1m:\u0004\u00071-\u0016`V',jwޅޅ仃.ETuxq\u0002ɏϏ\u0019ǉQ ~l.\\jZUmb5\u001d;.S A\f)\\OO_\u0016\\ۚ\u0002(\u00055JH`\u0017I!\u0014nIDTe3\"GPVHv\u0016\u0012\u0018a\u0011W~\u0017+he\u001c\u0002+RK\u0007t5é;V}\u0019%my\u001dBLQףf^x\u001a\u0004VYݹs\u001e\u000e\u0005fZg\u0015rav\u0003tD0\u0004\u0010nXA\u0002e\u0000\f\u0000\fA\nqzK\u0019\u001e㙡R[5\f\u001a\u0000C\u0018\u0004`\t`Ti^k\u001a\bԘ\r\u001fRaB\u000e7w\u0018\u0004.\u0019\u0011(a\u0003dP]5B\u001c:u\u001e\u0016\u0002p7\u0001±F\u0004Z\u0012WH\u0001\u0016\u0003ң\\\u0016j\u000e\u0019\u0011X2\n):?\u001e\u0005ZD\u001e{\u0001\u00102Ty+\u0011Z0U<l4t<\\ŷ0\u0000\u0003Xb)$r\u001e)\u0013\u0019P(\u001b\u00040Y\u0017X\bJ\u0018.^'k%\u001a\u0014H\u0003\u0019\u001eX\u0018\u00069FP\\3:9_\u001c(\u0005-Vɞ]QdteQ\u0001\u0010\u000e \n\u0015V거,$\u000ef\u00114 N\u000e4\u0002iUE\u0014=5\u0000_\u001al\u001e\u0005\b+\nAV0eB;\u0006\u0019eBR3F{\u0005\u0015@.@\u0010\f󄂀;\u0001\u0015:.12\u0014\u0014B\u0007Mi=\u0006p\u0019q\u0012:Exʴą4\u0015_xcpMՂlP\u0016YwLL<\u0017\u0007\u001dv N\u0007-\u001e&PZ\u0010bf\u0011Tpa:r`p[\f[h;➐S.\u0011rxsVVz8rf\u001e\u0019D\u0004k\u001d|\u0017=\f|A=:\u00126\u0012Y`\u0017V5\u0002ܜ2i\u0007;\u001a3:$«\u0005MMUF*o\u0016L\u001d1\u0011a3`fikU`y,\u0002 \u0012X~\u0004\t\u0006k6yщE|R\u0002\u001d\u0010ZX\tF`yKd[\u001d\u0018mxy\u001d/*W\u0002\u0018X:fra:H]\u001b\u001b\u0001.w!\u0007^t4s\u0001jAi\f\u001b?\t1\u0003l=\u0007ᙅ!\u0000J\rס\u0001>Ov%Xh\u00024Đ\u0011,\u0000x@!?Rdo/\u0003S\u0011/u`\u0006T]{vgsd>񫲣\u0007\n>:͔|x\u0017;ӹ<U̎U~iXLWLesE?\u000fJ|9\u000e~O]q7JO[\u001cO*ɩ\u0006-@A\u0003S\u0014d4'[Dv<\u0015?o֞sSI`%EޣQ-r.y@%Ca\u0001?S\u001e(T\u0004B#\u000f2AНl\u0014=P1.\\)Ur~>G.\b\u0013\u00128r\u000b\u00119_bp\u001a[YSW\u000ff~\f.Tri$\u0019h\\)\u001a/2MV|%wB*QP<h\u0004Ha\u001f\u0012\u0004\u0001M}7dP)f=T6\u00131S]W6H:[Å\r/tPBвe0X)8\u0018\bPc\"}C3q\u0012)qa2\u0013i9L\u00134s\u0007\nR2\u0014bR):hxLK\u001fT~1%\u001eS\u0019W\\)\u00165k3N\u0006~nt*=^8M^0LcJ#a<Ry|?M\u0003&q\fquTtTʦ\u00037\u001d\r\u0018\u001d[\u001ec\u001eC9B;䶕C_nBF-b߃tN\u001dĸMB90 -S\u0015;NL5qdp*\u0017#Ǜ-J3~`\u0011\ru6\u0011a\\8Xȗ|h!Hy:9SWc\u0015;Q\u0014'\u00194?֝dj*toAM^=ҟt\u000bB6_\u001e/N\u001fd+\u000eH꿶5Jf\u0017$h Ch~0u-x,\u0006#\u001ck\u0005\u001f@݈\u0002ԣ\u0015FQ\u0013F\u001b\u0019ue\u000fqUaly$mu\u000eK\u0017i\u001c>]9,BBn_a:\f-\u0010/\u001e\u0002I>\\\u001cqr\u00026\u0014z4-I'itB!7PG6I\u001e~k˲x\u0012c\u0011]\u0007ԍz2W4m﷍gs\u0018G\u001d/\u0014g\nd}>\u0010H\u001d,b\u0007hW1\fa%bMPo\u0007'JƹӮҧk#=I\\_>@۲o־\u001blw!:50[4^h\u000e\"\u0011W\u0014Z̝MtłX\u0018tѸ;\u0014}58ܨ3|\u001eK\u0012}8ih\u0018ʖfr?3\u001d*dC,T\u0005)5j_#Iaoavq\u0019;Y\f;&\b2\bw\u00157cvTqm)?ځm_ʏƽ\u00187A\u0017VCpD|l.\u0017+;$\n}HAK\u0006xkH(\u0003k稹\u0013Sѳ RN\u00171\u0016k؆r!Xh\u0005\u001b0\u001e\u0006\nkԆ\"mXôՒ_\u00149x=\u001e\bZ 1L2]ir\f.EjۂK+y?\u001d}? e\u0017bK-\u000eQZv\b{\u001eI-2t\u001cZ,\u000e-\u0017&i\u0010-@=i\u00101p\b@\u0006Ѳ`e\u001c\u0016h[4\u0018\u0018#:A$/\u0000K\u0012!pC6OXڢ}\u0013!2\u001d\b\u0011\u0003uI\"D\b\u001b,\u0013!\b\u0011G>fD\u0018wL\u00183\u0013!POR~\u0007'B'B)DqaBE։\u0005dr%뾐\u0007:`\u0017\u000f\u0016=+=:D\u0018\u001c]Ph\u00181v/_L\n4\u0012\u0001\\@gu\"\u0012\u0001\bV\n]E\u0002H\fD>T>@xJS}OxJS\"N<\u001cG\u0017\fsTCrsVrH\u0013\u000e99d${ύҧv],KU\u001c6a⤱IM|2+<Kџ.4XeSB\u0019\\AvꪢY䧪$$_(ϛ͏\u0013|71ʴ6CqJj3JJ\\4K+K\\fE|:EsԷh\u0017eYk,+b?}'k'|;u<hW~H\u0017vy5|۳xCzs\u0005yz݉9\u0016\u001b\u0019b(DFh\u0001cf''ꍎdvmZ\u001d\u0016RG\nԴ_a_}:sU,\u0004\u0013˅8sɉerbX&'IXR\u0007g3KN)Sr9\u0016ON)<Ķi (9l}'9l'SD%Fe\u0013h{.sU\u0014'8\u001avO生\u0015ND)*{3P\u00192zV\u0000QP]\n5np\u001a,K?5\u001dpR\u0012N\fQ8xdɢw\u0012;ߙ͏g'\u000b;g\u000b9,\u0014-I)3%q,8S,\u000b.\t6-qcJMKN\\v,\u001c#^Cjڲ(P5J\u0018b60\u000e\"\u000ef\fQ9eH\u001dx8cm\u0016\f1Kf3G[Ϋ\u0002LXR\u0012Hb\u0017I\u0003c\u0017<Rb\u0017<AC\u0018I\"]$$v.趏Lb\u0017&.~\u0007\u001c'a;\u001d\u0018{MmC0\"㲊$%W[1nX\u0018\u0018\u0004+\u0003:h}Ucly$m\u0018@ \u001d\\o\u001f]I˜-,\u0004m[56;UYRVfy9\u0010OIIX\bˢTzp߀`iM\rך^qGWkJ.\u0006/nD8m<|͒\u0013R\f\u001b?\u0019m+\n\u0013\u0013%\f^K\u0016A:>.+#]aB\u001d\u0005\u001fv~Pfm$\u00186A+LX0\nZa\u0013h\u001ax|2l`ĘÔ\u001f+I[Y\u0004\u000e,D\u0002H@G\u0002$\u0012FV۹\u0018'6 H@\u001b*$\u0012\u001eD\u0002\u0016\u0001$\u00120\u000f?axA\u001d\u0005M\u0014әr:wzE\u00053,dR\u0018\u0003\u001a:L2}p8WK>|a-g\u001a\u0005\u0007e\u001a\u001dL)xS^S`%w31Ӫ$CSyDMEW/\u0017bB\u000b)qD0\u001d\u000bh\u0016%MJD&)BK\u001ceTBYJq#Ia8~Tˤ\\\u001e!\u001eֵ6vj\u0016Q\f5H]\u00069Dq\t9D*=:t\u0007\bzu)G\u0019J\u001d\u0012?yt~$7:\u0003$\t4C$7fϔLfG3-0T56\rg0id\u001d-\u000f)\u0006}5kޠij3OiJ^sݦXd-\u0003)\u001c:qP\u0018,cHk0iTwӵ]syܸ'\u001b\u001bm{>\u001b+G\u0001m$&rjd1KgT\u00180d˧vĉ@ʧb5[{^ٶ\u0012\u000fa@^\u001d!1,zmD\rv6C/\u0002LbK\u0016m\u0017Ifmĵ+[ǝ@rtERHgL:\u0017j91\u0015mWKnq똄\u0016sBp2\u0006\u000byr\u0018\u000e\u0014Ռh&Wwp\u001b;y@9\u0003_-\u0016ֲz\u0019{W\u0019=Z\u001b{^N\u0014l\u0015Hlΰ)\u0013\u0015\u0016Kb$\u0006(\u001dhmj,ee%\u00013w`c\u00187!nqQ\u0013\u0019u=Wi2\u001d)O9W;_Դ\u001f}Z/UU@]uY\fIжUcs+\u0013UVΉ&oj}X\u0004\t\u0001x\bt/\n%=e\":HI'/\u001b<miDe{4\u0019*\u000ex[\u000baMQz\tH$o18\b۵n[et-5I@VfԎ,Lu')\u001cN\f\u001bmm\u000e.\u001dH%\n~r|c9S\u001b\n@\u0019rxYTxM\u0012ZⳢry\u00161!\u001e%3\u0017wg\t!^c1\u0003w\u0012\u001dӼ+fd.Ըuw*̡\u000e\nˀR*˕$-_4Ъ\u0014\u0005Rt4\u0011\u0018zL5fֱ\u00036E\u0001Y\u0017=\u0019TYQ̒[#\u001bj]q\u0011\u0000Y\u00009z\u001f!CТ\t\f<Of\u0017]\u0007f\u0018Sc\\W@KU9U!9\u0015fs\u0000\u0001PLer\u0011U\u0019ևz\u001dGSnk:^J34W\u0002;)=\u0005FSm\u0003vT\u0002nj\u0004\u001c$\u0003r,ו\u0014TtBC\u001c\r=L\u0006r\u0002lFʵ]>\u0004Rh0KS깊\u0000\u000evi؆#\u001d`3e\u001b\u001a\"X\u001cK5S:U@#e:ǭYᮁ1Bv=wDƕbz<K6ŵ(jJHS+\u001eǔ\u001cf!4Ԕ푧j2,Rw6J\u0015X)25Pomؑ\r[\u0016偌ܛmU|\\P\u0006lqSi\tB\u0003\u0003|cT,kjp\u0005\n0Yn\fNjl(Uu&\u0019i%\u0001\u0019ݒmvM\u0019<\b\u0010%u$ \"E0,\u000f\u00010:0J_ND &p\u001a\u0002<%OY\u001a\"X\u001ca2#6X}\u001bҭiQ5L14A9f#%\u0018\u000ef5tC#VI\u000b -R8\u0016NBh f4[բ{iFȮ\u0010zTL&Jpr\fދeFd'U#D54l6\b潉\u0000M9\"z]5rIZu۵g_R\u0010\u000elHD\u0010\u0010*atL!_\f @5\u0005P\"p$\u0010arO\u001a$s@x\u0006ٜ]{i*rM\u0004K4\u0000A&\u0017V4=0G\u000f\r#0A\u001aA&FRg\u0014U3mK#\u0018d.O٢s7mQb\rCfƣ7P(\u001eb\\\u0018#x]y\bdǙ\u0011(Zr3b06\u001ej\u001c\"J\\GIACb\f\u001d\u0015X\u0005v\u0011h8B+C\u0013Zs'e\u0002-\u0001y\u0019T\\ 2j\u0014\r(\r\b\u000e)\"ߘ\u001eلF\u0004\u0013\r\u0005^]oB4[_5\u001b[\u001b\r4Jol\u00012\be3mOXD56S\tzMXk\u0017>$Xh\u0017BP'ZZdobRWc?Y65EbFK^ELEٖD\"L.0Aȗnt/b9y%\u0007b<ϖ\u0001\"YP\n{L_'C\u00038\r\b4rH\f%0\b:\f˅\u0010?í\u0000#X'Ѡ\r\u0001\u0004\u001e_gk\u000ex\u0012:\u0003>qژ\t.y(wDeSRc\u0000\f\u001enں'6\u0016\u001aU\u0002\"\u0006t\u0000\u0001\u0006qcQ-5`V\b\u0003\u0001\u0001\u0002lb^Ҩuր1=^\u0007\u001d\u0000{˫Y-\u0001&\u000fu=j*U\u0006)\fj8\u0010WKW\r-ԖtN65Q%`x\u0010\f=M\u0007\u0005\u0017βlj8\u0010\u0017!+\u0015\n\u0006\u0002VLp:5X'bv Q\rLյ@4\"]\\:T?\u0010S&Ɠ\\X\n*(+\u0013%\u0006z\u0013ރ-\t$E4.A`S)Xs1f9&\\lH\u0000D!{\u0006\n\u0011tUΨC<\u0007]`&)W\u0005z\u0003a\u0001\u0006*\u0000\f@x\r&{\u0014Iq\u0005kdfc|\u0000b|mWc.,\u0019U3\f\n\fvKoB~T&\"\"\u001d3IJ\u001c(\u001d\u0007U\u0011%\u001aP?J\tن=LA\u0016#==3H@ŠP(DNҕ{\u001a\u0001\u0010oGN\u0005%6@h#f(]NP\fgE\u001d;n\u001fp\u0007P/+w\u001ez[WȽݧ\u001f}3ÿulB\rf}⟾>\u0003|~[G6\u0002|\u001f<_<7\u001e[J\u00076\u0000ځz~k{}s\u001f{k^r\u001d{\u001e}\u001fᑿ7\u001a\u001bBn27om$Mg}{Ms[s`\u0000k\fDs;\u0001\t*]ִݕӧO)@}5(XG&9z6/mF\u0018\f(,~\\\u0003\u001eegfPo7\u0004\u001eʖwRV\fLM\u001bb\u0016\"\u0018صeH\u001bTh4\tF\u0019-)9C\u001e3s+i\u001a%B\u0001>nQ\u000b\u0000V짫I$+\u0016(cX\u0006iNs\u001ev1Yb<YX\u0016\u0010\u0005Al3V\u001cZ\u0002|fՒ\u0013\u0013%'\u0012\u0004\u0016\bVcTRvFՈ>\tJq>9mRI>'$PvSsi$(E~ng\u000fMjoXŧX5%XEXgɰ\u0015>K\u001cYTb 6d\u0016\u0010Ef-\u001e2Bo]!>q`Ŋ{\u001e{N\u00175sE\u0017:ͺ@k.\u001bn\\\u001b{\u0015\\|/\u001b7;wfjr\u0015]\u001btY]Wߴ}ecؑn7tcŹ\u0017\\|ڭ\u001dG\nM{ɻow\u000bέU\\w##[^}Φk/YUcŹ/wo?\u0017׾׿O~\u001d}ށ\u001b/[\u001d\u0001j{W?}?}g?{?~߿اjkC=\b>ՇcO=O>٧<}ݱa}e\u0001V+V^pɍ}o<g~q_\u000bg3?y\u001b~\u001b/\u0000j\u0017_ۻ}yiht\u0006}~Gk/>o\u0005NM\u0003>\u000b?~ï\u00076]ɧ}zѳigG\u001bX79\u0005{U[=Ɠ<_ݜvy'?|*Ŋ\u001c~?~,O?}w]\u0004X\u000bow~\u001a|\u0010x%\u0004'ս^/>_u\u0011bH=z\bNEי/}?\u0010t8\u000fW\u000b]⼋op3\u000f}?}\u0003,~뎘]\u0004\u001dܸc⭏|\u0018G<oM\u0019\u0006w\u0017OSf\u001d_\u001fy\u001b\u000eS\u000e?Omkgӿ?5\u000es\btNJtB}x'ChYao_4iq?\n6\u000b_:\u000f\u0007ϜiHKg?) \rBWlWyg8}\u0003\u0000~[>\u001f>\u0011~?r37诿s{깺\f\u0017{{{﯏^\u0004LpІɇ+,C\u001b.,z\u000eYԑ\u0013\u000f?'k\u0006\u0013\u001bO~Oq9Ceʎ#ygúb^sdr\u0019J\u0015]xU>o3A} >.\fTɚRCLT>e\u0010\u001fzñ}\u0004j\nW\u0015?g\\0V%kU*?ط\u001f\u0013y\u001f\u0012KWU+KB׾#ܗװBtu\nb*ȃy˟|ojRto{_F)EvZYu#c\u001fv\u001duu\u0014hHλ+^Dl\u001bM\u0007e_u!Nb\u0018'?Sc\u0003+@p\u0001JB@&/\u0000#ԔaM6B_\u0015\"۳jSjѻOnJh\u0017NT=߂4<WJ\topM&*_y\u0012-Jb\u0019U?A9h\u0003 ֎5\f~M>\u000f\u000fg{̙{\u001b'#<_~򌬅<\u000f&?Ug~?n?OW\u001a)}\u0006}~XW鋍\r\u0016?^lևh/>sسN9\u0017Ku>d5A^x>F_ɷKh?R\u0010}\u0014ϯ~\u001f/\u0003g[\u000fހ}%v_=!\rO۟E'^:1q~#v}{u\u0017һ̜:%9\u001e.ó'\\YQ\u0004ngC{Or2g1\u0014\u0013\u001f\u0012?3d7 v\u001fN\u0010\u0012\u000f?\u0015ϓ\u0018\fiI\u0013<.\u000bs?\u001bG,Y9'(4\\X\u0001\u0017S9͟\u0017)rS\u0017U\u001am7R\u000f>\u0006}~\u001b9co\u000fj\u001dMm\u001d\u001fd\u000fg\u000feu[>ǟz?3?}K\u001fxCLC\u001cwz׻G\u001b6ec\\ S\u0017\f%tX%\u001e<=dV\u0005\u001cd\feX\n¦f⁚-\u0004oP\u0001\u0012u\u0013xuW3Ɇ|c&k,\u001cXo\nq\u0017q6w\u0017^\u000bW^u\u0001\u001a[}]\\z饗\\\u000bW7hW_˯\u0017]}W\\vɚ\u000bW_'~\u000b.\\s\u0015W_sp]{՗_\u000b[YpE]_}7fE7^Ov]h\u001boR֭@>)7b\u0003\u0017p~æ=yӆu!MCΕ_\u0005\r7lٶw=6tt5\u0010\\)={_tM6n޶=\u0007\\җھu3iz._#=\u0017]zuk7lKiA>׻4]{՗^(\u0006!Fem)U7@&X)T\u001a2(b\u000b/<{^U7m\"L\\ǱL]ݺiM]y\bpaȞ}А4s\u001dAoxe\u0017]/Ѫ5W\\\f\fvI\u000eϱ\f2\u001b\u0015'h^ru7߼\r\u0013\u0017xN%w>Oo&\u000f!ICҔ\fj}6\u0007DEK[iKK'ze1\tĳ\u001a}WU\u0004\u001e\u0017v¶ `q7㯼6VWY-+]ue\b-Rz6RZh\u0019oH6#|9\u0019R20ǥ7۰y+z6oXw3y\u001e+[}1iJc=[ɧg9ҋC,\u0007\u0005k.#Mܽ~Fٰfp0\u001bӦ^H[|B6>8ŗ\\\u000e\"\u0004\u0007nkr\u001aDF]ED*]s\\s5iG\u0004S=\u0019FEEk.˯.ZP\u0011\f;ȄXH:tJUL6ʘqnD3l\u001c7c̸=8\n\taKL%Fp\u0005ǌe6\u0007U=Oר+TS=\u001eh\u0006eԪq<b\u000e:$[\u001d\u0003\u001bJi\u000e->F:e\fV\\5Cm\t.)ñШ\u0012\u00101`\u0016{\u0000r^꺬0N\b\u0003\u00042[`+\u001bZ\u0006VB}Ă5?֯V#\u0000c?cXj,{\u001b٨\\QeJF޻_ݗ]{\u001a9W\u0019kusWq{]S'Cw\u001dԝmkz\u0006+w\u001f؟;\u001e=kط7koyϟ3\u000b_?ͯ@h?O~Kկ~勏~#\u000ft-І'_?o\u001b_§Oa\nu7_}\u000b_#7Ͽg+\u001fgW\u0017>\u001fxoW^{;?̣~wmrľhÎN|_~zo\u001d\u001f\u001fٱ~\rNfkߑ_7\u000fmoSݼ)Xs.;S<U)d\u0010Zhy[\u001c><rݵt9W޼aӦ\r7]\u0019q?gbY\u0018\u0011==^Hx\u00030\"Th5T}1\u000b\f1Ϩ\u000b\u001db^q\u0017:yE^6\u001e7P\u0004V\u0015\"*rAa=-\u0004id0\u001f\u0005J98VwFf_\u0013,&{W82^VJD`Ych\u000b3.8\u0002`\u001cW,\u0005WI\u0013\\&Mp\u001d4\u0007ikoTN3QG\u000e\u00114v3\u0015n$4<_CfEVq\u0015w\u0011\u000fɪB\u000b넵`WOP\u0010\u0000=%!=\u000b)\u00011Zl8\u0015j\u000buV5BJ@\u0000k20l8<)\u0012\u001e\u0019\u0006\u0002ȌWVn+%Zg\rċu%TA=L_[1\u001d\"\u001duZ1|*\u0003\u001aAC\u0010U\u0017/\\\\(<GQ1m)b|\u000eUHxmkˁE\u0002U;\u0010\u0017\tknJwlG\u00173Q\r:SwJ.le?3eX\u0010uZ(\u001d/mX\\*ŷ`g;#x(\u0007\u0005DfAИ?>\u000bƜY\f41+d\u0016\u001b,\r\u001a,%\u001aMYz4\"*4\nsکE`rN;U\u001ci\u00134i'LOI>'\r\t&U61Тn+U\u0001[L#L\u0018&h,%2h,\r21Xldf!3\u00074\u0016\u001cఀ,\b\u001aga\u0011\u0003V\u000b3\u0015+'\"!tsW_rUs%Ԁ%l厃#s[6_s4}YʍN?\u001e>5ub]n0Ї\u001e<?G>{3kz{_}'Ϟy<{֜[x\u001f~gub~?=t_OUshy4\u000b?ⱇ_%Ԝ5Y;<Կ;ԼIc\u0018gy\u001a5=M\u001a\u000f߷n\u0015mj}\u000f7iL?CW2\\νrǞjz\u0013\u001fnZM+ژ\u0013/\tٯm\u0017\u001d|奷>g\u001bFb?FkF?x_>Շnt9+Vo~'E<k=g%D#B'Lo^bw?/B\u0003*\\bU#\u001f~\"Ƶ3;\\IZ$N\u0017Uhi͚jc/<˘tyuƤA@{ʕ1難yɈ(7\u00105\u001f\t6^zS\u0004cz(\"\"\u0013w\u0017O@\u0001q2t\u0010mLXՑ\u0014\r\"\b\u0003Q%z\rĠ@\u001b̿_ba媫z'?)%\u0015\nbz\u000fR*L\u0007\u00127zk\u0013Iu]y-ӯL6Sn\bܣMмRUVUl6Ȗi}Pt\u000eU{Nx\u0007LMdWPz2hy)˴=n)24zAW`ȩ2-^E|Cf\u0012<\rn[P \u0017n^O\u0001\u0019ǖgHI\u0003\u0003LePL_\u001eJh&\u000fk|3e!\u0017s\"\u0019;/a\"\u001bLg\u00074L%\u0017t\u001d(\u000fBq3|\u001dE}tnxf\u000f0d䡒U\u0018-GAuf+\u001f5_]b0e\u0016:\u0006v\u00005\u0019\u0000K\u0019ߜM\u0016q\fdיȆvu[N;\u0018SY_9yR02\u001dתz4\u00072\u0019\u0019&\u0014Z3w2vqLW(XRU;\nm8\u001bL\u001f*\u001f33;\u0002\u0013=-ÿe?>L\u000be7\\X\u0017$>1\u001e\\KumDk=\u000fXkwޙ_o\u000fo;^Л\u0003;w|+L^G_[_\tiΗ4CdT\u001d\u0015S\rCYͰP4l\u0006Q5KxUHp\u0017i?t7E\u001b}\u001a\\S=U಄iMm\tfYdk\f,^\nnF3Qm\u0017]ǡ.\\\u0000\u0010\u0018%\u0019\u00034\t\u0018.\u0013.\u0003SR n\u0014\u0012,ݐ0a`-eh\\\u0003\u0013{&c\u001b)&`;K4\u001cѼ&`y\u0010W#[ak2u\u0016vXF2(\u0001C3.zLp>wf\u0000\u001e\u000eb*Ã4\u0000\u0007L\u0006\u0019]PdT=4\u0000F\u000f\u0006i\u0000\u001f\u001a$ΖugJ.\u001d\u0013\u0005](dzp3\u0011e],\\\u0010\u0012/Nc@Why\u0018!C\u0019n+А\n[X9\u0010\u0012 \u0011\u0014h\u001b>\bq-6\u0014\u0003d0\u0000)۲*\"뢋\u0001\u0010LB-0Z0Fq\u000f\u00064a\u0011!33ϭs\u0005\u001eQiL\u0010?Vw\fe\"Ķ]֖+%x\u0002\u000b\u0004\u001b)\u0006@\u001b5`LVu\u000e$V6\u001cGxRшYu:[BϳFVSse \u001bZFU[HC~X\u0018\b{l\u0005e-\u0018\u0018䥦Rid^D1m|\u0000-ϓ\u0007e\u0018ᶰվi\fh\u0013Il\u0017<ÖZp\u000e\u000b\u0016\n!И\b\u0003\u001d\t\u0000%8Ex\u00024#@5B5#\u0010OD>c\u001aS$K\u0016ɣ:\u0004\u0011Ft*a֎X\u0002In/Eb@T\baVЙC\t\tcS~&<BO9:\u001c(\u0010\"iBhQ\r˲D\u001b\u0019/`rL\u0003[ыEn\nLd\u0004;bkip1\u0017\u0000q\u0006c\u0006-nlTSt\u0014\u0000\t\u0006\nх`5e\u0013^3(b\u0017D\u001c\u0019kTmy\u0011Rw\r \u0006NV +8[3꧋*u#Eo\u0011\u000b\u0015Q\u0010\\e\u0013r5\\\u0002odh\u001b7j\f]364zYH\u0005\u0016$,b.na\u0006:\u001cBXWgd\u0012yٜ6\u001c\bNDPx\u001b\r\u000b⠉F\u001e\u0006\u0007@'\u0015\u0017\u0007\u000e\t<R \u0003F਻\\\n?췒)L\u0014*q4¸/\u0001V\u0016\u001a\u00128~\u00182\u0017Yl\u000e!/C\u0015YA1v\u0017M[Ǯ%\u0015>v]K5\u001a\f]ŰF-\u0017\r6Zl\u0018\u0001!\u00104l˴,:!'A\u0018\n\u0012P\u0004\u0019Փ(YF]0\u0014\u00152\u000fɂ3\u000f0 1\u000bR=#D6?\u0017Jo|\u0002HX^&QLSP3/l-L\u0017׳,n\u0001.1;u\r=\u000e1ON6@\u0014qlbƦjS\u0005\u000bd\u0013\rFi|T`H|\u0003G3NLuYk\u0006Xxۘ\r\u0006\u001dKPt\u0007\u00038Όb\u0007:sT\\\u0017\r[Pvi\u001ep-,D'\\\u0019b;*y}<p!\reXAAjS58Q\rGcle4fQMSd\u001f%\fqvx\\\u0016Gd=,\u00077;+c\u0019D<'8Sp~̥ep<Kր\u001bu\u000b\u0005)ʡ90\u0001 b+\u0013!RB\t\u0004}g\u0017ʭ̲\u001c\n\f\u0014\u0001U4e]+O\\c4\u000f0{\u000emqCaԅfƜ\u000b\u000f ^ljb0f\u0007t]*OI\u001f Wa#ϝ`h\u001el˖\u0011ݷv\u000e,Z.b\u000e͇x\u001eX\u0010Z6o\u001bB\u0005Tu\bR\u0003\u001d\u0005??\u001a*ChTgG%\r-\u001dm#\u00003:7\u000f4\b\u0007Gx@m\u0004z\u0018#AyK\u0006s!\u001dG\\\u00014\u001dq\u0000xzȆb[Pm\u0011\u0010\u00038\u000b4;54$0Kݞ)uנa1\u001eZ9P#N$^z*w\u001d0!'\\ؑ_u{|L\u001d\b I8gTu8E\u001e5\u0000r\fдFN\u0004p8jh\u0012\u0006\u0002KJmyI֬\u0001,8 \u001b#3\f\u0019&00M&ҵ<S\u0002\u000fc\u0012zL8\u0010se]Uu&a5\u001d\u0011y9x┚<۠G\b~u\u0010\u001b\u000e3d\b0ބ*f:\u0018R.^`%=gf~.iŔ\u0000՘xd\u0013s:4Q<\u0005\\3T'XU{U~iÌ0o\u0015\\A٦Ռ\u0007\u0005\u0016q\u001c,\u0000CYIqlr8=V%e5\u0004\u0019Sb\u0012S\u0000\u001a0؃\"QW\u0000G\\\u00004\u0001h\u0006\u0006@=Bq\u0000\u001861\rM\u0002S6\u0016\u001a±lvv-?,\u0000\n\u0001\u00181\\vÐ_\u0005\\.\u000e\u0007B%97n\u0011Ye(\u000e\u0010=03-wt5\u0010U\u00062d\f<M3\u0006I\u0017/pO.J0p\u001b\u0002\u001aqR#\u0003{E']\u001c3\u000bZ\u0013QD{mmB\u000f\u0011=\u0000\u0017B\u0007\u0003^78x.\u001f\u0004w('\u00046/\u0002\u000f1'\u000efm=\u001e_̏\u000b\u0010uL\u001c$Y<4\"!D\u0004(\tL~1\u001cݲQ҂\\\u0014K\\Z\u0017÷<[%&\u000fY.\u0017yq\u0011A\u0015Pd\nL)\u0001X\u0006[\u0011\u000bS\u0015\\\u001d2+][\u00022\u0011\u0011eT\u0012\u0007\u000fs@BC\u0010Ǌl\u001e&\u00039bl\\\u0004i\fן\u001d\u0003K$*JT\u001a\u001dx=\u0002\u0003;\r<S3W:a'\u0010}H\n^\"(t6l-3U>Jٵ5SkS[V4ԋD\u0013<7{4y\u001fb\tMѫw嘑暭er̵t\u0013Q*\bfnf'A:feߕ= !\u001a)\u0014ˇO51?lr\u0018r}AY[ٜ_\u0000\u0017\\axA*&b@@\u001cu\"עaF\u000e\u001dxn] 6qanLׂcd\u0013`\u0018[xu\u0006\u001cFj0\u0005&\u0011\u001c<u\\\u0019C\u0005ב{h%#:\u001a\u0010\u0003+\u00001 \f:=K\u0014\u001a\u0011QzcIc\u000f$B\u0015.)IF/ɡs ۫0I\u001cX\rb5r\u001d\u0014V\u0003\u0003\u0000Yn1\f9YyiH*\u0018-@\u0015\u0002)ܒxfz-}4ٜ<.\u0018U5nL\u0013\u0017)a8B\u0003\rvDg8C\u00041#S>\tglQe5_eG\u0006\u0017\u0000Ȃ\u0019\u0010\u0012R\u0011h\u00155-oH| \r!\\;^G\u000f\u0014#lOJ/q:0\u0003߸웑\\<8)w\f\u0014+)e:_;}9ĮfxD\t)2SN)\u0007M(d\bմ}A!vl:M\u0010?\u0004aȱ\u0010Nm\u0007\u0007p\u001a\u0010j=8.f\n\u0014i+:DM\u0011?^T6|ԁ4\u001d\"'ۣE5Vt\biX8\u00005\u001f\u0012&\u001d\"^cۢ\u0018Q\u0012*\u000e\u0002v#$\u001c(\u0003nxBRܦh\u001ek\br5?ÇPJ⩚K\u0016Vxba$[쇊jD\u001a\u0016]:U\\䅤z,\bR] >Bvb\u0010р\u001a\u0014\t)\u00136ǵ@ȐZ\u0006\u0018P6/\u001a0c6ZEDm\u0001\u0015ֆ4W\u0010N\rM>x\u0005\u0010Y#]?[\u000e8|\u001a!f\u0003\n)}0\n)*4>6pl7XХwGp\"O &*JlQ\u000e\u0010ܔ]}|=}<ubw6G\u0006ړ\u0015րAٹJ\u001fo^r:syt)\tz4Y^LAOd@/S\f\r[5A\u0005\u0018r\u000e:\u001d%w8Z.\u00167+r:JL:k\u001f![sȟ e4ſOTe\u0011\u000e>xH&\u000f\t,\u000e򇲥\\\u0014¦NG՜\u001fm!D\u001c\b8@{, RTQc!2J\u00174x\u0016L4tL);WIJAB\u0018d2B؉l\u0010\u0007*/s(\u000b\u0014\u000b\u0010ۂmɅ\u0015\"aBOEV8M\u0006\u000bJ܀\u0006t\u0004:iN\u0011ærgu\u001f\u001c\u00152(\u0005\u0015@A\u001aAY\rܧGv\u0002\u0001Aw7/hz\"p\u0018㒥YYJ\u001a.#Tq2Ϝ\u0005\u001cw0ws\u0006v2\u001egEѸ#ҳO؉IdMKdMc\u0012<\u001dI\u0004N%\u0019͝\u0000jn_wo\u001a:]R_t[2\u0001\u0016\u0001+Btȟ,>~:\u0016\u001c\u001e*\u0012\u0010σ\u0017E+Ӄ\u001f~tё2{C\u0003~tw:S.\u0014!ui:\u001fFv\u001a}\u001c\u001ap\u0003@:͏\u0014=I\\ʖgr\u0017$\u0018=\u001f/LnN\u000fj&:-tzg<\f\u0018\u0019\u0014C2:\u001e/\u0011\u001d\u000eu'င˜t\u0018tBA\u0015QY<\u001a*ay:U({dJ\fm.6)̤3\rlܸ<i)+\u0002U3le^\"u\u0011n\"<nryVBZO.\\%W&&]P)XR\u000fRt\u0014H`UJ\u0016]\u001dXsBwy\u0019{^\"D^ub֮\u0005\t\u001ewWk<\u001b\u0016^\u001a\u0002ɢ>\u000bT\u0017e\u0007{o\u0001]vcHZao\u0007b+\u001d\u000b\u001dj\u001aB\u00028q\u000f=âGQ$Bda#\u001d/\u0014$r~-D\bOm\u0012|y`hB,`mDQ\u0019c\\\nT\u0002PCE\u0006Y\"#\u0015\u0015kB[A8lY\u0007\u0012}蛖֫\u001bc1\u001a\u001dkR TI&?\u0003oSxm#o;ˤ{=!+\u0015f|\u0010rw8ӐJz\u0004C\u0010k\u0013VJ*\f,\\!\u0005ܡ\u0018\u0010\r]_\u0000B\u0002wB1\u0011_47|\u0011o^ărD/GamQg\u0016W/3Np\u0006莧4\u00135\u001eU4z%dY\u000bk-P^5N\u000bn$?-=uv2In*&7\u0015MYvL>i^\u0017Zv¬vK5MH$\tYI`4kza\u0012tW\u0015\u0012@|;\u0010(\u001ḋ:0Rk\u0006\u000eGd:\u0000\u001dsiÅ`!>bKyTlkbӥA<'\u0017M8[䨫&r4\u001c=娙\u0001O0QnCIzC7E\u000brhùfX)Z\\K,J\u0012_\"(\u0014zpb䗡NT\\wUé\u0010o:ʔj\u0007\u0019[$J\u0017&JQl2zMJϺ.U\u0019\u001b1\u00122u袈j[\u0014LNhe.\u0018Ʌ$vAr\u0012\u001a8h \u0011Tjda\u0017TH\u001aH\u0019f`-\u0019\u001989HW7,]mG9-H\no\u001bFjm\u001c-|NoKF\u0003O.\u0019P\u0019\u000bf,\u001en\u001a\u000e}kUcO1}J8\n2Y=\\ILN?fk\u0018UXm\u0015\u0019yrc\u000fA\u0018umP\u0017;1%16Mo\u0013Ū[fG\u0019.\u001aEƋVc8V\f\u001b\u0005_ǖ^9\u0004G\"d{\ro,VC}!O_+?\u001e\f':#x!6\u001e}d,>=˯=N]L=-Yd;:!F&\u0002\u001c3\u0010V-\u0016hsĶ\u001c\u0005ZY\u001eby3KQ5%\u0006\u0007O>cC]l%X\u000bl<\u0000^Yc\u001dgъH\u0004'\u00195>fsjt67\u000eUUc#\u0002|s)\u0003\u0016.\u001azQUxtgb\u001ct=\b\riC \u0016\u001aB̜@⍼\u001e4f\u000bklp H#?H\u0018T%\f^N[q\r\u001c\u0002\u0000Á[,\u000f׊\u0010Wƀ\u000f\u001f\tv]\u0011:ˆ#H\u0006]%\u0003v3x%,A\u0013oa\u0006j<%Fl\u0012XYgs20U\u0007\u0018ن`L|\u001f-\u0019m ÷K\\l$\u001c\u0013y@=*gU\u0001ɟ\rD\u00112am\\l\u0007)\u0003U,\u000e/f ɭ3&Sa,s.X\u00112\bPġ*Q\fS\u000enrqnT\u001bS`#ߤk\u000e\u001bO9H/5\u0016b\u0015od&㘌(\u0001#]q,!K\u001dV_BD3\u0000\u0011Ņ\u0016\u0001Uʥ$\u001c4\u00149\u001a6D0\u000bɸ&b.^\u000f\u0004\t{Axp`#r\u001a$\u000er@S*\fXV\u0014.\u0014\u0001A\u0005*#8~\u0004\t\r7$lSAXBQخ 8(D5\u0013\t\u0018:\u001dpKG(f\u0004\u001fr@0WO\u0005&h\u0015Q\u0014u|!Aǵ\u0002'Η*$չj/gA@PW쿜,\u00041y\u001e%U<Ώr\u001e@{\u00123\u0015\u0014-0)':BqRp>\u0010\u0006HB0dC\u001a\u000el+F\u0015/GڲJX\u0003\u0010\"o\u0004.\u001b\u0005d)V\u0005\u0017,\t/6BJ\u0002\u0010By\u0003!v\u0010tWŖ50=<lǵw5U\\\u001dE1$ :FLI\u0017,\u0017:\u0018!\fd6Bc\u001ah0%zFЎ\u0001qR\u0002\u0016^tE\u0010 z*P\u001e,\u0001[Y\\X\u0013A\u0014]1\u0011G5j\u001a\f\u0004*t٨ta\r*k\u0019\u001b(\u000f&E\u0011? O\u0010O|\u0012\u000f[>@\u0011B]U\u001aN`<\u001a݀uԝHH<3j>\u00117\u0004\u000f\u00193|x8|Kh\u001c~i#Lm\u001fV`Jaڴ^8c14<\u0003\u0004\u001a\u0002\u0014*]=wH\u0000R:ſ\r\nCom6\u0014\u0006\u001bo\u000f\u0011¿q@Ȁٞ\u000bm3-\u0007 D~`srk\u0002\u0007sy\u001bFOM\u0015r09p\\o_JW}䮞1:\"YeN4go\u001eΤإ\u0017Haf\u0006n_LLm\b\u00107\u0006_B\u0002Wtƣ}%=ǳi_**<!\u0010\u00044E\f0+3e\u001f6=R!\u0018\"H\u0010\u001d\u00104\u000bn<*\"4/.\u0004*\u0014Ut.[b \u0007ӎg)\u0006£L\u00056\u001e\t8+r\u0012T\\J\u001a,2!ӕt.NZB8d28=\u000f\u0014+I|r:'_)f*ec_\u0004\u0002ޱ\u0004C,RT67^|joϦ|tS\u001fq,F\u0002Ԡ]^\u0013Ǥ\u0014CW'_1\u0016\u0006\u0017qV\u0006[.\u0010au^c8AT17B\u001cD0i\u0011=?\u0002m<WBk\u0012M\u0013U\u0017#w\u0018}ج\u000eM[L0LT.LV-\u001e\u001d(\u0007\f\u0004bqqF,\u0007.-Mhcmb6(岙NŶ\u001e\u000f68;{bNiDMd,2md\u001cMKy1fs\";^3#ްT\r\u00047g'rѲ\u0012!&4V ~?Q>X\u0012\u000f;j\"oP)f\u0001j'\n(L8拇7O<֏0K\u001c\u001aW64MlK}e\f҆x1\u0013`A\u0006\u0018\u0004:)\u0011+\u0010)\u0016tcy\u0016*eeX̰\u001a\u001a`<C\u001a4\u001f޶,j\u0018zQ4?.5Y3i\u0001S\u0004R\u0012!'i\u000b\u0013k#f\"zȊZh#hxW\u000e'ʮl9=e˧Į!kcxd%=+#\u0019ܺ\u001a&$F2\u0019f/TY;T\u0013]p!΁\u0003/\u001b\u001c\u0006S\u001bW\f)gO0\u001dg*C\u0006FEI 9+*\u0013\"9kX8\u0017g ZpHȊ\u0006FvCn+㪕;8\\6+e?3d+;I{̺\u001a\u0006ch\u001a/6\u000e/hew\u0017\u000e\u0001\u000fs̝B\u0017)\u001e&B6#4%J`U/aAa\b7[BX?\"OZ=L\u0014\u000b\u0013ٜ/5=W\t .h:+Z\u001a\u0019\u0005Eu\u0001;&(ЕbQy1O\u000b̃\u0007\nc)\"\nr\u0005\u00142n6CxI?suұ\u0018c[>HX\u0001;9NE\u000fdj+\u0019\u0012h\r#kx\u0019=%_\b\u0018S)\u0014JY\\\u000b&'\u001656\b89̉2ЦLŘd@fe94)*=\u0018,\u0006\btB=\u0017\\0}.\u0014j\"ԶKZf\u00175^-C3MyC@\u0019\u0015@xU\u0003e\u000e:3SLac6M\u0014n'}װE{dƕSP?(\u001fqg>!\u0016d=\u0001\u0003RL\u0015&\u001bɈ[\u001eڈm\u001c渁\b\nV;`&!V\u001cO\u00156khu+z9\u000eǊlw\tL.s16|ْ6lN\u0018urrX\u0006!֘?\u001e&C(O˩\\hK)\u0011ʨR*\u0017#\u0018\u0002k6A\u0006l(C\"z8פMNPFT+M\u0003aY\u0015YX\bSr3Uo\rH\u001b\u001b\u001b#N\u001a\u0014f2\u0006&S\r+MS\u0013\u000e&ݛ3pqH\u0012\bu:$v\u0010m\u0015%3Ӓ35Rǈ#Fָѻ\u000flr\\o\u0011\u0019f-[ՆX/~\u0016u\u0002O+;\u0017\u0017?G&؀>UI!恥r\u000e5\f5xX]\u0007\u00168,e.\u001f\u001b؃}\u0014=4\u0012N\u0013ӗHre\u0014cg6oY\fc5T¬-E*\u0002-\u0017NյRv2/%#A\u001a֎_\u0011iCKƲt\u0013!\u0004MYbmXF'\u0002\u0019!B2P\u0013T\rMZP\u0004{2\u001dxpTH\u0012u[Q7D\u001eYA0̥g\u000fޮ@կI<a2Pq-+UR\u000fQ\u00074KňfE]-\u0002tdq\u0003Æp$\u001fb4\u0016\"\"Fbj-\tatX)u\u0002\u0018m%c\u0012n\rD!ߌqU\u0015\u0003jЎHD-zVJZP^8b\bL+&5X\u001c.\tqo]\u0019D/\u001a?Z\u001e,v>L\u0005\r\u000b`m \u001fC9s\u000f\u001f׺f\u001d`葡G\u0017T0K;xb\u000e\u00185@x:_1N2뒃\u0000貼\n7MzW\u0005ź.Ca7Vw7r|P<6,Xs\u00114eV=\u0014H\u001c=!\u0005;X:!z=H!Ewv8\u000fHr##^Ov1A\u00119\u000b57q\u0005gr\u0015 2yb,@ÅYq\u0016&qى,ʒ\u000el\u0003\u00063\u0010T'q\u0017?dW͖q:RG\u00101WZc;$lX\u0018KӧbSU+0WSƬպ닓\u0018'$,\u0013Y0faf%\bHhL*q\u0000>uFKOW2`z\u001df&j\u001b\u0019\u0000Sp8'0iq<+\u001dK\u0004txn\rABJs\u000fm\u0011|bvz?M6?Jխfz\u0019H\u0013nی?*\r{\u0000J崠\u0003Rx2=Ogs\u0001l^1,=#òPrY4\u000eK\u0015k4{bzfF2`\u001b6\u001c-b!\u00035 ;q\r\u001e'Fֳ\u0014\u0018(\u001f+hV\u0001L<UeNIGw\u0011\"*9E\r3r\u0016g4r=ی\u0018$I\u0014WVi\u0010uFd\u001c\"Z!\u0004\u0010GG0!Hrb+qئt^\u0007=BL\u0000*uESJ!\u0006CN\u0015*\f1n\u0014L}\u0018pP\u0004-\u001bzv<Lt\u0013r\u0001Jy\\\u0014Y\u0011#\u0014u\u0002h\u00000\u0018=-O\b.\u001e\u0016&gKJ%\f\nAbkL1;\u0013O\u0010W\u000eDlP\u0015%@f\u000f\u000f\nu̝ʁ,:{֐\u000fX×ݻ*Ⱦz1wvo-\u0003\u0013\u000f\u001b;\u000ftw\u0017V7\u001fm^vv\u000f[ڽiӧb{u=umt]\u0007O\u0007\u001fnKj\rEpsd2G~Rcg6\u000fg\u0014|ovב\u0007_6ozEf>s'spw\u0004<\u001a\u001f/\u0003?ݗ\u001a3䗞u0ݑ\u0007&o[n?\u000fwmܳ9տ\u0015\u001a;g\u0003\u0006m\u0001k0[:\u0007RDԡ\u0012W\u001e\u000fw^q=K\u0001}jHs\bf5\u001d|{p-왩]cu_<TO\u0019/j\f\u001f~q:Y#6hb\u001b\u0018/KF\u0017H\u0017[)}h_\u001fp\u000e\u0015wiN4xmNڇ{O;75}6܏n1lޝ\u0013|\u001e\u0001o7\u0014Ҭ_\u0007(\u0005\u0004Ls\u001d/'cYln\u0007䛽\u0002l\u001dJ-\u0003/\u001d}k@J3p}\u000fd&ӓ|ۆn=vˮM{\u0019xc;Ʒ\u0001Q\u000f\u0012:qo:`taŻ\u001e;2w\rfo}Ƕ]\u001e|Iٶkx\u0001Pɜ>wl\u001dn-\u0017\u001dB};Gߖ\u001fN6:/5E%ή&v\u000fܶ\u0003f:kwVa\u0007w+wܻ~\u0003\u0006z?w|殍\u0003r@88}\t٫m;\u001d\u0001X}ÅJԶ]Ğ~ػcnojDˌoR)\r^E^ߗ^7~\u0003Cwf/W\u0006<ڲȺ-\u0007y{\u000eo+q\u0005؞#=\u0005W=mݛv[iˤ\u000b_\u0002mwo^Ȏۇ\u000etoзuot\bnEh\u000euOwKrwo5ZzT-q%'\u001d`r09眡Mi9k}%9\u001bۘ{|CcSJUJ(Q[i\u0019֙Š}J|[+'BT5JQcV^N?)\u0003-H\u0019\u0002;\fk;^e$R*2g7)\u0013\u0001cJʴQfj2\u0007|uV\u0016-4JdPִ>|٥lݖ}Q);sZ9\u000e(n˫\u001c\u0007ImV\u001f\r弻(HIMʍ\u0016)AZW<\u001d92?DYM*RQ\\e9a\u0013\u0015^\u0006UN{yT@A`o!U;*3*TaWU\u001a䪪R}Ts\u0000 R\u001bʱj\u0005#/yj\u0002\u0000P`Q\u001aGZ늮Ԇ4<9ZINO$T>~>թJ5لյAݥn-ڠS\u000f{zZ\u001eՋV((0Gr>i\u001aU5oi]i`GV\u001a`|D{&49gܢ):n͇\u0014tf`k4ӀY+frh\u0015S\u0006/a\u0005i\u0012f\u00062<\t\u000bU\u0011,/\u001bXvU_ab؀5\u0018Sws?k\u000f3԰kUΧ.n3k^@q\u0002f=iZsXYδS|~/}_c^,N{XtsV]\u001e\u001c\u0012ŝK6 \u0012untYuKOϤۖcy\u0013\u0002z{>;ә`W_\u0006RQkhK?/K\u0004џ\u0013EAX|\u0019lIS-\"d5d\u000ff\rBcE:\u0004\u0018\u000e>\u0011K\u001dLF6z1sm9fakwSco\u0018\u0019gӁq\u001eݸo2\u0018&o76\u0005s)59kꔻGTuL?etV}x\u0015Y?V'̎Lb\u000eYv}sY_'79_\u0013gڼm:\u0016_sc`\u0011\u001b-ʡc).w{L\u0006ecXY.ߟՔ藭\u001e\u001a[(b[߱K!uZl嬿_\f,\u001f\u001f3ovےV\rVad\u0003\u001dj\u0019CQ4\u001755NuYv,/)0b\rʞe{kug\u001da\u001dw8:#K:Q5Z\u000e`\u0013z\u001dZ4\u001aN0q&ݓM\u0014C&)}\\N\u0015W`.9irC^3\\]Z4'ɩ9M\u001bxUl2[e\u00071\u001a\u0013Q>y2\t[h=_iƁ\u001b\u0019ϲbێ86qgP\u001d_(Ʉ\u0019\tV|bǯ\u001c~ǢX'^\u0006/d\u000e\u0018׽z Q)̊f\u0003j\u001fX7)\u0005\u0016\u0014wAW2\tRS\u001aNA\u0017<ON\b׫ݡXg\u001do`\b\u001d%K#ƹ!\\㶦\u0018\u0017Έ9[<F©0R)\u001ag\u0019~dk\u0016Kr\u0013Thu_E\u0019s*zO1[5kŽN]ǔv+GM9y;,?*\u000bm~\u0012e(cbȪ\u0013I%\u00153\u0019w\"\\H.gvJӽSj*T԰r#mFhH\u0006xzm2)\u0013b̪SV\u00190no\u001b*`\u0010*g\u000f&1\\v享t$5~b$\u001f7\u0018~W2\u001e\u000bR,ԦB\u001a\u0016VEO]\u0004N\u001f\u001d{ؑP`.n,l#Dl\u001dDPY1yW'ݯtJe\u001b\u001ar&XMpGFWsZ>:ѹ\u001c./u_fWzL՗&Co\u001fQE?Va[h[c\u0018U\rR505}hY\u000br2~խD\u0018h}6bֱ\u0019ܴݣ]^E61$\u001a.\u0005։/[O\u001f\u001ctד\u001bt&})L\u0013\u001afaTN\u0014l\u0003mPۗ'c\u001eYd`\b)\u0007Il9\u0018rh*a\u0012\r[FikzGG=*?\u001a[[8{_ݕibp/}3\u0019_SM~6Fc3VkL/Z}\u0016fy6;\u001ag\u001f_ʹ\u001a'{kWO\u001eϼ\u001fv߰p\u0015p\u0016L,~3wZV;r9\u000egЎ7r\u0005W5۶\u001ck\u0010\\[R\u0002珧i\fL۟w>kv*ݜ~P]십lcv;rd\n:_\u0007_6<3{]!VHh}1w&eA\u001d|OUGӺ8ƬqlfO\u0006l\u0011T 8!\r\u0018^睙TBky=v{tR'ү)6&h'\t!\u0001OgG@|w*O\u0012~\u0001Lv++zu\u000b0U\u001b\u000e[91a޻7v\u0010K,Ȅ\u0004Y\u001d\\Z\">&!U]'k;\t\u0015Q6Z`\u0019*s$\b:Wɣ[\fd3\u001d\\[\"E&]-ÅKsz<vl;3cV\u0001i܁\f''o\b~M\"77].q84λDS\"E\nr%s1M\u0011e\u0012kvy\u00038ot3߸\u000bN*c\r\u0006%m'^\u0005G\u0016\u0003\u0011\fn/I8\\_L~\u001f\"$y\nqe>\u001avyjV\u0003Ҍh-\u0006pɍ8Oݘ=u\\\u000f\u0010\u0003\u0003d+z~Niia7ήNR@\u0003%WB.8\u000bNmՒ\u001dUOY(z]r=4V.Q\u0007bl\u0006J\u0003]9v|y3iGه].5R?o3\u0005GVc,dޟbæbHT8'sR,Z4p+e꾯*{`<o*\u0005sgp}Zt\u001b)Q_2)u\u0014Xj\u0017f4^ۮ\u0007f\u0016\u001f^`\u0018\u000bm2XdݚRfgK\u0005rsn`X+利6e/\u001dbC\u0001S>%Gߣ\u001d=\u0006e\u001b\u0016\u001f1t~Q`\u001f++8\u0018cN)Q1O\u0019C+\\\\vA\n~}M7ڔ^Vv6\u001eךI`=*\u0013XTg9\u0006x=\u001bbʩ<0\u0016mMr\u000ekqGNCJ\u0015Nm6n8y`MażHzk[b\u0005\u0012\u0016KCNw\u001euě܍L\u001fpC\u00046\u0005E<F5ܒA<E\u0012\u001bBf{^Cu9e\u0019\bG\u0007#\u0004\u0005*BML\u0014ꤋIszB\u0000s\u001cy@]\u0014͎T;LCOev0WMQK\u0002=!3\u0001>\u0001_Zwne\"5F'R.ϧ+LRK[Nug֪rq$\\}5W9t8ǽÞ\u001afN\u0017\u001aE\u0004rta~\u001ca]jH\u0011>\u0001ة\u0014Q\u0007;\u000eA\n,=\tW\u001d+PD\u000e\u0007llJ#>*\u000bg\u0013\u0010\u0002\u000b\u0017}&kO\u0005w\u0000\u0004g\u0005gUY8_QI\u0016ީ\u001e&c\u0007:ÿ{CrL18\u001e\u0016\u000e\u0013!A#\u000bvDm!$\u00039hMS\r5\u000eb:J3eۋy&9\u0014؃l\u00130=R3kü9(00E5`\u000b0T=N\"e-/|U3\u0014tUx\u0018\tOer}Z{k\u000e:cV\u0015\\\u0004[\u001f\u0006H^eSY\u0006\u001e\u00009\u0004O1{\u001eϷƤ\f\u0001`y;n槙U`!\u0013\u001eاͻ#\u0004`/栥\u0006@\f;%\u0004+\u0001\u0018?~F{i\u000e?2Z^OD8|\u001ckzdдsTQZu#\u000ed\u0006\n-\u0003ܿ\u0005`)}|4_\u001b\u0012W\u0018`\u0001՘\"a\u0013=%O9\\\u0012L\u00159K&v\u001bSo\u001fz\u001c\u0012\u0005\n\u0017]\u001b]\u001f٨\u0015wjà\u0019%d)\u0006?E\u0000b\u0016d.!D?\u0013P(&\u000fџFQO\u0000I]\u0000\u0015\u000fY2^%\u0018\u0010uE\u001e*\u0001_0pQx\\\u00101z\u0011\u0017A\nM\rM\t\u0001\u0005\u0013S$\u0016\f'\u0005ӄ\u0005\u00110f\u0014\u0004\"8eAџ$ \u0006\u00177A\u0014-#ʠx\u0019NwNI\u0012bټ\b6(0F\u0010b`e <q\u0011FbD葳\u001c\u0014\u0018w/#B$'%Ĕ'zUĠ̟\u0004\t\u0012\f/U1§Yb-\n\u0013+EC#̬\u0019\\\u0015B*S\u0015\u00180o4N\u0002\\\u0010QloSޠ0|Ǣ\u0018ήF\u0018E/CL\u0005X%HϰF\u000b\u000fHd\u0010\u001e\u0011XfA^\u0010C<Ұ#B\u0002\u0010-f\u0010m\b\u0010=\u0000g7T'\u0002Ju\t\u0004{_c]\u0004feqS\u0018f\u001b\u0005Ųc\u0013òM.u,\u0019X\u0010)Mv7G2eN\u0002~\u000fP2t\f\b\u0005`\u00135RLxt3E)o𳔉;7\u0002\u0003\u000b2!\u0007Av\u0005ܛT1zpGI\u0017F+8iSɦ>؞r*>\fE\f7\u000fj2Q6\fi]m9\u0001\u001e(¸+e\u0019\u001bW#\u001d\u0014>Rq\"\u0004 \rb\u000edrf-l=U\u0017G+y\u0012@m\u000f`\u001d=\u0007h]P\u0003\u0004bjY?5lZ\u001fC\u000eU_\u0019\u0012u\u0014\u0018\u0019b(\u0014.j&\u0019'?\u001e[pž}k\u0003D&^|\u0007'ga#Ҍm\u000e\u0019PI`MH\u0003\"o!J\fPwF&P+S/i[G\u0001rx\"\u001b@\f\b\u00039ރZ\u000e\u001f\fTAy8Y\u0013\u0011s*\u0011\u0019\u0006~g\\5QfQL\u0005M8Oe{%p\u000eܑu`JÀ\u00104S˖)\u000bt&0\u0004\u0007\"O\u0015\u0000?!F!FШΤ.\u0013\u0007\u000f5U*$\u0018XKo[!\u001dK\u000f+v&eS\u000f\u0018biq2ls\u0003%\u001a(\u0003Hv<(kh\u0005;h-&6e\u00130kKg\u000302Jl\u001ca%\u000e\u0004\u0017J\u0002D;'0G&,\nuֺ)ڞ\u001e\u0001XS\u0001q®\u001b\u000fؗ\u0011k)h\u000f\u000e\u0017\u0002\u0012=\u0000r,:]&@QFS\u0000yJY,YYA2W\u0015\\^j?fk\u0003\u0003\u0004~ \u0004Yh\u000f`(0of\u0014\u0018;f^60dG\u0014\u0017wx̵h^D ~\u0003J\u0018jL0EzC5D\u0019^>\u000blŽx\t%)\\R֏\u0005eF*Qedh\u0010\u0010eحSn0FS\u0016\t牜\\6\u0015&%h'jޑV#@q\f+Q8?\u0001?Niѳdi, )y4/\u0016\u001cen\u001d\u000bt3lP&|wL!\u001d2<9\u00047q=_`>žZBG]rwTYV1{ۿ&PtQMz\rSfj]\u0012wW37\u0001\u0002կlvYA6['\u001fǎ\u0016%^\r\u0003o\tvc\u00042o\bu\u0014\u0001)\u00192he?#r؂MV\u001c\u0005\u0000%\\L~\u0007\u0018cM\u0006#w0 h\n\\$~\u0012\u0013\tT{o^\u001a\u001e\u0017W\u0019E_B\u0004OK\n2Ʌg\u0013oįO\u001d:\u0016ц$\u0015\u0015W\u000f&U4ckPp\u0014\u000bd'fd;J[\u001eRxC~*QK:ƏJ<zF_AL\u001a&Z\u0001\u0015=&L}.o`oM\u0002shmd@!\u000f\u0002[.v!\u0006\u001bC\u000eg=&fkj5Xm\u0006\u000b =g\t^\u0005&g?lj\u001cbi%2JEE\u0010ԟ\u0003\u0011\u0002ɩ3\u0010|\u0017ȱclx\u0019?Ib\u000b\u0016E_`\n]%ܤ35M,\u0014w`a\u001f\u0015\u0000HltBSrK'kǁ\u000e(|\u0005\u001f\u001d<\u001dԆ\u0005T\u0003ש\u0006.§\u0001\u0011W;ǋ=5hX[}f\u0001f\u0007Rf/!wũ\u0005!pMOj/f5/MLO¡<z\u0001\u000f\u0002m*\u0016C6Ts\u001bLھg\u0002\u000f\u0015\u001d=M'G\u0012\u001elN姿ؕ\u0019\u0000n\u001fPZSż*\t%BK1YFi4ہ\u000bۂ;\u00008'\r>\u0016XQo Ko;ήb\u0018DB0oՠΤjF\u0006ۻp,cħE\f\u0002\u0018\u0003\u000bŽ\ru2\u000eB\u0016Ap\u00146\u000b\u0003RycMܥOl\b\u0005,dD;\u0000\u0018\u0013\u001dQJ8\f˦ \b0.s1[UlIS\u0011S\u001e$>:\u0005{HM\u001bA\u0016\u000e}^6\u0017Rf\bv?A\b:v'VNY\u0010j#\u001e.c4=\fra&<\u0016{\u0010Dԑ\tU\u0003Ecl/3bdD\u001a>7f%-:<VaYJ@q%_(\u001dgh\r֫xr\\+\u00141߮O@m%`̤-j \u00010VM\u0014>r\u001b5az:ɫ\u0012[)\u001acY\u001fJ\u0017un\u0003⻫B\u001cM\u0019\u000fW(Qh/EuI\u0000O\u0007x,\u001c\u0004\u0013??X*?S\u0005>\u0003AĹQwEQ+\u000b\u0017`_\u001b%!\u000b4c9;sn\u001c\u0003\rqrl\u000fZ\fTFKf2rl!9O6)\u0017\t|N\u00017}\u001cRW{s838Go\u001b'7025y/Nß\u0013\u0018\u0004iܥN\u0016eOg6\u0000\f\u001b;\u0019T0<\u00160dO\\@E/@|\flk[?pr<dbE3;\u0010xd|:˯}z\u001fԷۣ\u0002`D\u000e4I6/R;\u0016a\"5mԴ&\u0005\u0016yU)Q\u0000g6Pv\u0019Y$k؛g/\u0013L菽\n\u0015{\",\u000e9\r \u0016\u001a\u0019dEҁ\u0002@\u001f}QIRё\f\t\u001doG&Vm/\u001d\u0005{\fO\t{'!'\u001d \u000f)*{V\u0000\u0015\"+Ѕ͟2m_K*&>s\u001eBԮy\u001aD\fl\u0006W)<\t1\u0010%&UWz~p\u0001-\u0003\u0016߭ӣEh>\n'VC]\u0019`3/C\u001f\u001cܥ<\u0006wl0:]\u0007b9b\u0019g}\u0003ia>pCq\u001a\r\u000fR\u000b=\u0010z!;-4\u001cc88\u000bl©ầf\u0011\u001aøP\u0005\u0001sL\u0003p֓ܒ&;]|dC)>;91o\u000fL]Х.5v3g?}P͑l\u0011!T?֩\u0002\u0001\u0000\u001b?_TYLC\u0007dA\\ɑǣ`\u0004\u0019X\"\"I\u0016\u001ai\u0015ohD\u0018\u0000\u0003\u000bkz(+\u001fe\u001fpɌ\u0002GPGr\u0000XK[9\\U\u001a\u00113`\u0015v.\u001cSg. n_\u0017]\u0014\u0010=YWtmn\u001fjGS\u0014N\b7y{\u0005\u000ĕLe#0JN\n\u0003NA\u001e\u00049\u0001|&\bO݋O\u001dg48saŦ\u0003V\u0014لʧ_i^Ҫ4]\u0002\rM)-xف==\u001aޭL\u001aꮓT\u0006Km58\u0013>\u000f\u0010\u0013e \nc\u0002\u0006c$<B?E|Pǚ}\u0013O}fzL8\u001e\u001b?r\u0014nJZ\u001f`GlĂΒ_\u00036K\u0018<5 <ns5e03;2ch֎F2`C\u0014\u0002}\u0017S$Ԣ}Im/\u001d?/u/\u001dtp\u001c\u0007uAޑ;\u001fY\u0005\u0007\u001di*@se\u0006YLxАR<ٱ5r\u0004̠\n\u00193-\"W\u0016\u001e\u0019X\u0016\u001cT\u0003[G\u0003dTEhxI\fQcF<.6\u0004Ϫ?[̠(\u001e6k3kW\u0010\u001c\fhP@4wO{B\u0005\u000ekUk\u0015.'M`PFߪ\fP218bmA3_?)8)>t\r\nk\u001aRO:(42c\u0006}?\u0014\u001a\u0014\u0011fP0\nwW51(<73܇JUS\u0010\rA\u0015\u00185_*\"kuXUdJi+3ƨ7,A{\u0005_kɛ葃,zޠFi&\u0006M\u000f6\u0019J?cxv\u000b\rNݨ\u001e4,в\u0016\u001d4\u0019'\"\rx#8AEp2(\u0017ࠍq4(:he+$\u0006Om]'`UI}i|>A%NtV֖E*0\u0016\u0019\u0013\u00194jh:ࠝ(4(p8~ xզAxJ\n\u0019\u0005\u0007\u001du4(/kLڮؠ\u0019|\\?\u0007\f~\r\nFAæ,\u001e\u0011\u0004rN\u0005/\u0011NU,iK\u000e\u001aF\u0018p\\\u001b>:1~hA7~#Ohrō\u0006u\"\u001cwP]PA-̠`\u0014R@ʁړ\u0001NWp\u0013Fi3\u000fx#\u0006\u001d\u0003\u0005\u000ez\r-S0\u0017.QkQز[%\u000f\u00184s\u000fz\\G\r䠁\\+iChPgU*A(Z{֯A+\u0004WZU\\σA\u001dW\u0018L3$4\u00032*\r\n/Se\b\u000fLg}z\u001dȘXBO$Lnf4vlT՞ReBO0=w?w>OZeIE|A}\u0012~Zć\nd2/\"=J,rщ<-.k\u0001o\"WSa\u0016X\t{i~ѶtDiHN:1S\u001ac9\u0013\"ΙIOs \u001c\rN\u0007?q$ul\u000eβY5BV\u0000cCc_\u000fmJ\u001e\n<v\u001daٛ\u0011آ[ɜUՅpɫ\u0004bWVBO^\u000f[;\u0012j=O1>ޞC]Je\u0012\u001br^a\f<\u000f\u001bq:7ǷGB*i~sZvͼB\u0019۳wٕG\u0007%\u0006\r\u0017\u0006ϤR\u001c\u0003[\u0012?w\u001b0F\fǌl+t\u001d^e\u001eVm[g\u0006`ݱqQЅk\u0016*8vB_\u0012La}.@|PUfd\u0011\u001d\u0014$<UA=j%9cfXΠĠY[|lأ\u0007EY a}9s\u0019Pf\b\u001e\u0007u54lc\u001fAZ\u0019\u0014\u0012mUay\bԶ\u0017\u001e\u000f|\u001c\u000e|\u0007A7\t|ؠSA5\u0003kE\u0016\u001ei\fJX\u0017ܵ浼]Gȍ\\ޫ\u0017<\u0017ySU\r+ew7\u0018KZ5rRX\u0017ڬ7%v\nAS\u0012y\u0018\n4g\u001f\u0000e3O\u0014goP|\b.\u0007jZ \u001eu$9G\u0002L4&?j\u0004OV\u0014\u0006Q\u0003\u0018ya.2\u0003Oٍ\f|I`^$X\u0000d rM{^!K.\u001b?\u00188\u00069*)2sX\bd=۪?Ps]h</:&śm\u000e?\u0004>x\r\nx\u0019bxr\u001b\u000fO.X\u0012Z\u0002c\u00103v?g,?s\u0017\u000fA\u001a^!m(,k!K\u0002X[\u0015\frg/u\\b\u0018vF\u000bbx14g'i+\u0013==\u001f_\u0007={\u0000z\\ѣn(mO\u000fOY\u001aS\u0018٢4\u00042=%d\u0019g\u0007]p\u001etQHlsAtiNMXki\\-Fzj-Cb\u0013\u0017qY\u001582hѪhϼ窉\u001b\u000b\u00120Aʑ04\u001br\u001c_ԬZަHvp@hɏ!f\u0019i:M4f\u0016%$%}\u0019A\u0001`#3ǎwSU 魯\u000eQ4C$洙+0Y̜*턖\u0012wC?\u0014DAl\u0001ژvQڰv0o^\u0003\u00079\u000eħ HsB/`s\u0014-\u0001n\u001d%e\\ѓXM\u0011QLlF\u000e-γ\\RK\n.[O¼\u000f&?SJ#\u000bvsJ~d#ä\u0003bS/w\u0007EM:RȎ/:IL:wUguӴ\u0014\\`\u000eyq\u001101U\u0002q%\u0018J1FFHBs$=\u000bqAVIo\u001d3sEq~8s`\u0019r;'j^++\u0003[V=';\u0018^\u0012;\u001ce4z'Q\rߏ\u001dn\u001f\ri[^a'[\r#%rb\u0018&)\u00177\u0011R\u0012-) g\"|!b{j\"\f,)JtǮ|rH\u000eqsrH&\u0001tH\u000emS\u0006\u0010\tj\u0013\u001dCA\u001b\u0012\u0002kR\u000f\n\u0000X,\u0000\u0000/\u001aQԙ\u0015d38<;\u0018V\u0010\u0015`\u001e+@\u0017XOǗvUO\u0006}*n`,E\u001eKr?=[dLg\u001eC9f/\\dxݷK\u0005>EHb\tNHF~85\u0001\u0018(\u0014\b\u0016\u0018$\u0000^nx\u0003J~a%TR\u000f7\u0005|qt\u0014HLB\n\u0017\u00191:ō(S?\"F\u0014-h\u0018X\u0006`G,^ådD\u001a4LMƹtoJsd\u0018\u001e\u0004\rendstream\rendobj\r608 0 obj\r<</Length 46498>>stream\r\n\u0007qGc|ϤnY\u001c\\5bw)@\u0005R\u0007<PWyhg9e,H!ME{H\u0000`\u0014{\f1Bŵ\u0013e!v!ږ%13M\rnC魯K@\b?}>\u0001\u0016ޚNEƫ 0\u001c~!hL:\n$c˓vMBn:w̆9\u0013Gp@\u0004eٳd=p{,_\u0000\u0018.%9\u001fD\u001aw)w:a@<p\u0005UGÖ6ee~*0!hF\u0001ֺ_EH\u0000o@6j\u0016\u00000C\u001fJW<A\u001c[JI\"4T~KH=%P\u0002y^^sEbܲ!QF\r\u000b\u001e4PFmKr*:\u0000G.\u000f2rmQGZ<N!!KG\u0013\u0000=B\u0016񾨘~3Rwp)\r\u0014r`'an\u001brw\u0006t\n\u0004\"h\t^߄#9&i\u0002\u0002vgOJ\u0017\u0005W\u001bv9D:8 ]\u0007=\u001b\nc!\u0000&}\u0014Յ\u001c\u0002\u0000{:\u0004;<:\u0004X\u0019\u0003ԅOi}/\u0004E݄#K\u001bJBJLUe3ڐ\u000baJх(W/\u000f#wt!+SL\u001a-\u00005\u0012uG9D\\)\u001d\rRKd\u0000L\u0016Cʰt\u0001(b\u000f\u00142\\\u0014\u00026\u001d\u0011);?%a&%(Y\u0006{\u0014U@-DՒh<YT1N\u0012NH暸ҋR\u0006s\u0001O<HFrSޒ\u0000ԁZXr\r\u0004vM71&',v2IHɜ[I`\"&FjH\u0005\u0014\u00013TIɘTXXhLƀ\u0018H\n\u0017\u0018}7CUW?\rX\u0019WRZ|P\u0005\u0002{M\rt\u0005UЃ5t\u0015t|\rt\u0005T=5t\u0015tjk+\u0014kj+xՂ\u000fIW)IWС\u0017I^PC']Aǎ=SC']AGck\t\u0015f{!k[2\u0007^\u0012(vkJbޚx+q;<˨bY}Ofִ72BGz\u0001j䒋tfw:(\u0018$#=\u0000f~z}Ȃ]9'}[\"\u001bÜS\u0012|\u0011\u0006u\u001cY4'O,W@uG*\bb kQb&iY77ݸ\u0005\u0006)lĘ*v\u0013>{I7\u001eJ\u0005JK\u0018s]kz\rj\u0006B\t\u0005|֬{b\u00022eTՕNq`9\n\u001dW\u001b\u0011-2Ĕ[x۷\be1~vt\u001d&g\n\u001e;\u000bPh\u001dX,mNS'}u<yV4Øs\u0004K\"hAdJ\u0012P\u0004\u001eLJ<\u0007:YʁO\u0001\u001du|7kbĉSK\u0002k\u000fʔ{qʓ\u0018\u001bZQ݋$%ڣ\u0018\u0006~ǫDsĳ\u001et s7\u000b\u0018IV\u0017[J\u0018\u0000FV>6?7\u001cpb\u0014rЮ'rG#Si\u0001\u0001˰\u0004\u0016\bNإr\u000fɈ#^voCG`ݫp\u000b\u001dRKN\u0013\u0013yvcxYvdVU,Q1$YCU\u0013r(KI@N@WD\tC\u0018\u0012&7lAcx:岫tNqcRr?\u0000Ua'\u0004nUƉNW\fHLy\u0016\u0017.(NbJ;\u0017qj\u001b>L^T=V\u0011n\r3\u0011\u0019n\u0001{Q\u0004\"2Lv2#2\u0002Ղã\t콺H}>H\u001f\"V\u001c\u001b,J%\u0011\\\u0015\u0007yr}\u00155і]:c@ADኯ\tꠥ\ter52$9~\u0017e.,\u001f.U\u000bު/Q0C(7_Oq·\u0013DPq%UlJ\u0007FVxi;tF\u0016\u00147|E=\u001c\u000fs#,t=#_\u000f'\u0005z2TeP}Q=\u001cOsz8\u001bAE\u0003\u001fgCQ\u0013w\u0014\u0002{q=[\u0002^P\u000f\u0017vJߋ\u0004|1c\u001d\u0018IyW/& 9+mK99WY\u0012~z(dfBބ#\u0019,\u00179̆\u0010gk\t(~p\u000em֒\fIޗdC<X&]aBpK*g\u0006=\u0005-9\"rL\rӃ\u0003<k\u001c\u0005lۿ6`\u0004G\ry\b\u0013lȆ\u0002ɻn\b8·iYC`+fn݆\u0006uu[#\\\u0017Â4\u001cjVEj\u0015\u0015\u000b+R\u0001U\u000e\u000e/HܯHfi(*R\u0001&^L֭\"7g#>[*\u001ahK,ׇ\u0018D{:\u0001\r\u0003\u001b\u001b!/EʱA{fF\u000fw\u000fkKដ[.ϯ|\u0014w\u0007R8Kc23?\u0002\u0012O\u0004nc]\u0006\u000bΨ݃2\u0002\u0010\u0018\"'lى{}\u000bj&\bG\"u\u0001V]أ(nMI&E\u0002ꁌ\u0000ՉqL~Aw_zSv#f;'J(<\u000e7S\u001b\u0002K&lNJ(4RQS\u0019ML\u001e)[\u0003o꒙ 3w\"\u0014a\u0013p/+\u0016(vDٵX`\u0007$Rnv\u000e_qJ\"d'V\u0015:\u0012\u0015vȠ\u001e5l=\u0014+vQaw\u000f\nj\u000e\njb\u0019\u0015vb\u001a[\u0002ZMӃ`_\n;ANZE\u00073PMdP؏\u000fsUR\u0013bT#>hd\u0006ǇUؠ\u001f\u0012\u0014ۢ\u00029N2]\u0010\u0017\u0016Pnv\u0017c&=g\u0012G\u000bM|b\fe@4\u0005v4:{.!xI:\u0001ʹr˷`\u0001Z\u0006\u0019QJFҞ0Vg~I_%~s%>|R<\u000f{}Y'9>rw<I(եg\u000fWC\u0014\u0018~\u001eqn^d\u0013\u001by}/j\"'>o2suoNf\u0001HJɹKqew|tWy\rnEzﯦ{4\u000es_5\u001fD^UM'TK'|?3tB1A\u0001~yN;E3\u001f㡅_[j:!P7o\bNȩ辶\u0013:a\u0017U\tNF^PM'\u0014g\u000bj:X;㽾N➫\u0017V\tqsG_QM'NhJ\u0013?\u0005vy*Nh\u0004\u0006u\u0003t+tנ]j{\u0014cU\tyXW\t\u0001@/\u0013\u0002xy5iU\u000etBt|j:1+jj:!dpeNF%\u000bj$=\u0000F#r\u0000yžo\u00182\u000bĔ<\u000bW$[Z\u0010ū\tMIҺx_u!\u000fO7;r\u0012N</ðG\u00023S Z,<)\u0012\u0005EOBS\";2I(BJHi!{9\\\\Hy[\u00044k\u001cK7fM\u001d+y&m%LA6w\u0012\\\nd\t.L6{rA\u000bس-2ɉ(\u0016o#\u001aQht'V))措}'\u000fX4*䌶Lj5uվ:h.v\u0012XZ@t-Ͼ(+\u0017\u0003';*\\Hw]m,/(Ua(!*\r\"$hOr:l!\u0019y]OTۊ*:ỡ{`\nl벡\u001ăj̆\\e\u001bB\u0010\u0014\u0015}p\u001eSy\u001c/\ty\u0003\u0011\u0014\u0016\u0014م./(fq\\\u001bo\u0005,<q\u001f\u0002s\fg.QT,<T*aD@kϠ\u00064Es[w\u0012^\u0010ʗUlw\fi#ǠYs\"y}KC\b}\"}(~tU>w61t!Ý'2^\u00152\u000e7+SdS\u001dJ\u001ew\u000fUVN\u001aG=^Q2S\r)%uIb=^WuIr\u001aMFWu\fv;$\u0014v\u001aޫکj|\u0016V!v\t\fd8\u0017\u0014\u000e\u000eBsE7%tG\u0004Z\bJtn\u0011\u0017Zú\u0013RsW}\u0000G﹧\u0013E\rOǵX}/\u00012Gb7˘*}\u0011uܻO'c++L-i|Sn\u0011\u0013SZp\u0001\u0005]!Qj[$0LZ-<\u0010%2\rÞa.qMtW75\bYO.Z\u0011v-{bC`ߣ\u00002\u0004%\u0018|Ć߸y [v\u0013RyoK\rSg\u001aW{q[fl\u0011\u001a*3[$Ǩ\u001d#JQoO>3f3}sf!~%\t[\u0011q6~#K>lo_\u001eNⴾDz&%N=)U\u0015+sXHcdnxID\u00073D]hP\u0005FacW\u0007HYrĎĊ]\u001bݹRPO\u0017-M;^&v\"<1Pp9+u㮴/Uupbڿ]):X\u0006]\b\rJ}U]Q\u0004J?+2/i^\u001f\u0006eid5bMr\u0002\u0013Y\u0019}؃,.CxT%I1n{I2N\u001c\u0013vRi&v9^\u00173Nnn\n\u000e\u0019\u0011\u0012񒤃)\u0011\u0015\u0010\u0012+\u0015F\tʱ\u0017VSU\u0018HRMOAuBYR$\n7O>^v+C̃EO;\u001eq>ۓ'e֔)/.?K\u000bœJ\u0001wDVun,W\\YwW=3_p%<q5J={^rk\\\u001aF\u0017\r/\u0011БZ?\u0018Y玦_q\t-\u0001[/vkĳxI#3ǎ_5;U,W\u001cW22\u0019ќ94AN:\u000e]\t\u0010Ƥʠ!8\t\u0004۷.\u0011QO|P\u0015η{.$\u001b9`v\u001a[\u001b'\u001aKME\u0017^s \u001agO*OR@\u0017,s%^\nq,teжSl2ŭ\u0000v=\u0018G\"\u001dĘ\u0018s\u0002*\u0017\u000e\u0019~y\nPn\r ?\u00021\u0019'u\u0018eǲj\u0000?^\u0005?\u001a@V\u0003U5\u001cWb\u000fV\u0001HEü΃\u0015ۡg:\u0011\u0018{\n%\u00125W5Vx\u001eG~\nP|JX\t２ժxMpS>nw5\u0013*)lhGȺI)\u001f:I\u0003\u0003Mpo'\u001feM|)\u001f'\u0000'Ur\rD&Um*\r\u0016`_Trnq/lz VtTH꡾~<u{n(~_?騐'~g_?\u001d\"\ruo_?Yt_?\u0010Vꩾ~2*^׏\u0012\u000bɾ~K_X_?~\u000fu\u0000\u0011' \f\tn\u000f8\u0013\u000b\u001dGG,奄~Ҋ\u000e򼠯tW;o\u0012'dAO(kt?\u0017Լ'\r\u0005\u000bI\u001f2']8+PP_?\u0003\u0015\u001f;}]<SȾ~L]\u0013<M\bKzt5\"~~W\\=O\u001aTGgIZ\u000bR+I\u000eя[<{\u0010w5p_?#blI[D}*V~\u0002{M_?f~\u0016}=я$\r~|O_Cw{I?\u001bӊ'awUlGW\f=׏&/~To؝}̜\u0001/}ս>׏\"7c}˹\u0012x1<Տ\u001f}tw͓TW?['\"H3J=O:*`_?8-ɯy\nq}+\u001f\u0011\\W]\u001ed\b ﭾ~҆!}d_?XF#?O=P_?)#a^O\r\\_?NIVOZ9ܨOZ9\u0012<^Kbʄ^+76BB\u0014S\u0013e<92pOo\u001co!/$ L*\f\"X\u0011\r\u0017Ŧ+[%zt:\u001e\u001d},X@qtZmT[h_R\u0006e<aSFQ_[\u0016\u0005i\u000ecf^m&Uq+ܡݰƪmemK{5sT5Sp7}G\u001dNR[l\u0018Y\u0005\ro*#\u0007Ͷ\u0004y\u001fK\u001d@Mi\u001cfJGk\n~bx\u0006FL]\u0005V+q\u001d\u001c/3WfpJ2rH¾J\u001fn\u0012w|<}\u0017Ԑ+\u000bAD\u000b/ΩL\t_L\u000bH.q\u0010F֯X4N><\u0015eR4\tXeb\u0018X\u0005\u0013X-&|ז=&8\u0014l m?,L*(!dX\u0001TK$}&/'\n\t2ޚ`h\u001f6\u001e^\u0002\u0010Jw\u0012vv6L~̖H;r1]\u0010[x3p4|̓Â:VHLiѩJ$OzSʌ]2\\>oO\u0002!\u0005\\Omv9ۺ\u001bcq`:^\u00033\",@aw\u001bg\"lW3.\u0003\u0013`,\u0003\u0006LOtk\u0001|\u0011Cpt\u0000>95$36r\u0014\u0005K#w=Q37\u001f\u0018\u000f،~\u00003YZ9~\u001d^\u000fp\u0003&\u001eT\fhlI53\u0015\u0018zvd\u001fYXp\u0000\u000e*]a֞\u001cO\u0007\u0001{6hu\u0013lot-,\u0001ĢaV/O\u0012©xW$~}MmVnliӌ:\f\u0000\u001a\u00057h|㷁~(\u0016\u001a6I\u0002I\bTa^{\u0007\u0010mB\u0014\u0013\u0010q\u0016DM}\nZ'rU\\Op᳡T`$vW:ŋ΄!/2PK\rsrah\tv\bv>vS_U7@\u0000%.\u0011bvG0\u001d_i>X=b{+E\u001e1=X\u000bݮ\u0010\u0014*l}\u0014~2U\u0005ٞ5pH`6e\u0000U0D>\u0000&6[\u0013|j3\u001cDcv&\t\u001a\t\u001a.\u0004\u001b4\u0007r/\u0000k%\tyH\u0010\r\u0011\"s\n\u0005C\"@\u001e\fH\u0002\u000ff\u0006l\"+g\u0018-)\u000f`$:zMm{V\u0012R m璓M|\u000e,}|%\u001b0)\u00007>;qƧg[z\u001f*,M L\u0015OpD\n[ݘ\u0010n\u0014\u0018/Ԇ<EۺSp\u00181=\u0017\u001d\u00133\u000eL:sv<c$\faĀ*]\bFޱ͢Tɸ\n\f_ns\t\u0000\u00066\u0000:ɶE\u0016BR\u0013%<+\u001fڡ\u0019S\",iwF\u0006\u0018\u0004\f\u0000\u0017*moZ\u0006s K@$(Ӄũ\rJRf(\tc\u0019}\u0007lnx\u001a;\u0001ɟv}/hU\b:_\\B\u0001U\n>q\u000buVX8%\"\u0000VJ\u0018\u001fD\u0019+˿,GrQ2uk)S\f*\u0015~\u0012a,a(\u0016PnhU\u0003m&jT\u001f=\u0002\u0005SF\u0000upWi$0?:gLm\u0016\n\u0011\u0002wʃJ,`԰\u0010M\u001ev,KԀ\u000eѠ\r!pK\u0010\nm)\u0004\u0010:\r\u0004.\u000el&\"G bΖ&pL\f\u00123@\u000e\fz\u0016\u0016r\"DH\b\u0000I\u0014\u0004a\u000bB\f\u0001\u001e\u0003aq4?}0?\f\u000b\u000f0WJ޵\f\u0004cedH\nި#B d\u0000`̆g\u001b\u00020\u0002@_\u000e%,\u0002Bn-s x_z\u0019V\u0019z\u00124Z\u0002)'ʌ\u0000$AeRJ\u001d\u0019:$M\u001bM;\u001e5ƻ`~!\u0010R5\u00144&*ۍAc6듛c!2H\u001a\u0004?ɮ6;\u001eSe69(0Y8x\b\u000f\u001aa{\u001dS##g\u00168>1tX\u0013\"\n4/:#>y繸\u001cL7\b\u0018T`\u0003v+\u000bʁ[\u0002`4\u00040A3\u0012f,f2Ncow3Q#M&=Fbf\bٰ\u000e\u0012!Ӄv\u0012t~ꣃ\u0015qx1\n7\u0000\u0015'CuCR\u001bi?vJ#gYoEn\b\u0003\u001cF࿴\u001d#\u0000<Ig\u001a\u0019\u001e\u001cW_F̆ALΦɕ\n]\u0017ct\u0004>kA5U\u000f\u0016M(@\u0004xS\u001e\u0019#\u0011`O\u000194Wg\u0005\u0013\u001f\n=J\u0010gB\u0019݀`$}\u0004\u001c\u000eimZ)\u0017\u0003v+C@\"&NTˍ1t\u0011\u0002\u001bu==t$bK\u000eS\u0012<s\u0002ܑ3&88?;B=\u0019qj!/Gʞ-Ms\u001d\"\u0005\fe:\u000f U\u0015\u0004\"j`w\u0012y&9\u0002f$)R\u0018\u000bG\u001dkګ\u0016\u001f=ར(+\u0017\u001d\u001b69\u001d\u000bQ&H\fZ\u001e}vQ۠8L$''A21ź\u001dF3G\u0013A\u001b\u0015\u0016l\f\u0017i#bJXO~Y:>w$,\u0013π\u001e\n\"A\u0000\u0001pRy\u000e\u0011\u000e\\\u0012\u001a\u0007gV\u0010\tG&\u0019\u001e$-\u0003^y\u0004ԃ~0Bz\u001f\n@ fo#gf\u0003ټ`Dw\u0002\u0006s\u0005\u0019m)\u0018\u0018\rbr\u0019$쌀\u0017\tA|\u000bmW6af0A\u0003l\u0011r\u001c[ˈdD\u0011\f`^Ā\u001a\u0005q%e?]+\u0013J~x\u0010x\u0012\\g\u001dQ\tLB\u000f|\rD\u0004\"x\u0002l&[4SyXI^No\"\u001b~j*\u0002=u\u000bkVEH3@\u000fق\u0012 Y\u0017Jy\u0003Էb}6rDy\u0007ثԉ>!l /\u0010w\u0005y[4\u001cE!^\fq oF\u0014^nus>.c^cV\u0004\u0015xnowb\\sju.\u0004\u001b|N-v?\u001bKө/Np\u001d>#UH-MN\u0011x/3/\u0006g.\f\u000f?\u0014\u0014لʧ_i^Ҫ4]\u0002\rM)-x\u0001e`z\u0007=g2\u001d'>7qO.`D!\u0012J!V\"\\c>]q{љ.$_XqW?]=JwJe+JKY\u0003֎oDi\u000f/\u001fZ[\u0018+,\u0002ṡf; \u000et\u001ey\f莑̴P\u0006\u0019?$whf5P\u001aI\u001d]U苤\u0015Zr9+C\u001634ҳT\\\u000fP\u000f\u0002F^gԃ%l(EG\u0019+2Q\u000fJ,c\u0013Q#gcF\u0004 \u001a;aDJK6R@e8.&Rd[ks5iBB+d%ԓ.=??px\u001d3v\t_\baX\rh\u001eh{U+9\naw.FerT\u0013>Ehk!3ܔއM\b\u0002{\u001cb\u000bgqe+\u001cH[$\u0016fCD8\"->᫻|4yM;+Y*߳\u000f+҃4U\t\r\u0006P@:\u0001\u0007uhh\u0000)|\u001dn\u001d\r[\u00032\u001e1=}0CVr\u0006y?4\u001bM\u0001ٞ@ \b\u0015\u001eE\nRB\\.=sQ\u001f29r\u00064G?2G{;\"M¡)dCҊn7\f\bYul%\n(\tTL\u0017HUf%\u000fZ־^\u0011\u0000Õr\u0002\u0011p-\b[\u0010H\njlH\u001c<F+F>v )E\u0012b(J>\u00032PP\u0018[\u000e*4ͣ0\u0018;&hɞK©\"gW'D\u0005TGZyh+K\u001a\\5\u0004W\u00071GjʍT\u0006ga\u0001\u001f\u0005ҏ\u0013Qf\u0002\u0018\\\u0002p׆+,b\u0000o\u0000`Ƅ\u000b\u0015(qޘs'MH711kiǤl\u0003\"xыv_&C\u0004R)#p\u0017z\u0015\u0014mN0)\n\u000f!A*x\bvd\u0004LY\u0012By\n\u0014:b>\u001bcϒnٶM0\u000bϓ\u0001\u0012F(=n\u0005\u0003\u00047\u000eF)b0^cU?<@I%vj;\u001dـ#egB/c\u0016\u0017O<^t2U)`i\u0014/\u00021X|f\u0014\\fHCƉ\u0015fQ!0oо=k\u000eaLۿ>\u0012ĮL;\u0010,\u001c\u0001\u0018a^\u000ed\u000b\\\u001d,|^qj\u0002v%ǊUXe\u0010uS]]&-^4\n\u0018\u0003d\u001b`3ZZ\u0003}6\n?\r\u0005t\u001a\f\u000e4\u0017aSt`^zف\u00177`4\u0006FZgcOԞ\u001dk*(m+~\u0007\u0000\u0019ľQuB>C-Ԧ\u0013Q\"{RO:e\u0017\u0010n`:|Dw\\̲,%\b+}r~;==\u0002>Y\u0005#*u6\u0019v\u0018r\u0019(\u0017aθ\u0011ֽ\u0001mz\"X\b΄v`\u000bF\u0007\"Ls\u0002\u001ab֊C\u0011\u0016B//nݟbR]6XRt\u001d)H-t\u0005jgM\u0004ױ\\*0!E}5\u0001dM=\u0007q\u000bO\u001f!%(\u0019O\u001cn\u001e58\fџ\bmP\bA)Հ#^\u00066\rO9&Q5V'8\u0002z\u0011,\fD~9f\u0001FSƜ<R\u001aTY\"k\u001c2'\u000bkف\u0003|\u0013/\u000f8\u0010\u0000Ǐ\u0017\u0005@\u0019!g6\u000bd23/pRCmk\u0001}R\u0003C]|W=gD]3N\u001c\u0007R\u0000PbֲE\f\n\u001cK=:eٵBN\u0000dXvF[kvM\u0001 \u0007\u0019[\u000fJ#.+bz\u0011F\u0015^`\u0013l\u0006T(\u00051\u001b\u0004\u0003\u0004bxT!#\u0019\u000f/\u001dN\u0006\u000biaHTѵ\u000b2j\b\u0006y\u0004_~\u0000*j#\u001c>`{pq\u0012\u0007h\\\u00059ü2\u001c\u0006w\u001aٖ5d=\u0016\u001dFenW0\u0001䫛\u0004\u0011hvAJä\u001fAʸgP\u000fo4RP\u0003\u000b`\u0015iir\u0005jvm+Nӡ*\u0003~\r\u0001u#\u0000H;2W\u001cX\t~pqa#q\u000e22f*wL>T\u0001\u0017D\u0012(vtV\u000f%S\u0018a^?U}*\u001f,$#v]9:H\u0018\n-H$|K\u001bx>a|^\u0000\u0005\ni w?VAJ9\u0019Rt(lg\u001d\u001aCJ\u00031R\u0004Cw<\u0003\u0001\u0017\u0011\u0003\b\u0011\u0000\u0003\b=Q.\u001eĸ\u0012v\u0002~n\u001933\u0007\u0002cw/cux\u0000Z@*:H\u001f鎲r/\u001eO9\tS\u001b\u000b(\u0016ٻQ\u001d\u001f\u0003U]\u0017-NO?Ej(a+0y\\\u0011(w\u0014Ƅ\\ި\u001d\u001aEWo\u0000s\u0017\u0017c\u0001M;=l0ǹ\u00127Ә0Kxɫ[<\u0014I\bXo#\u0000\u0018]\\Q\\dȤE\u001c}*'9~~\u0004\u0011P9;\u001aA\u001d䰫Fޓ\tN\te_\u0013V,\u001an9?a\u0003%d9\u000f\u000322\u0010ًA\u001e&3&L\u0012bf\u001dy;c+D]/41\u0007d\u0003̂*'T;n\u001fDjIt'P\"ɠ\bP\u0018$[hD\n\u001a}\u001f]\t\u000b\t[r#\f/ȡ.0yṮ\u001bO8ϫsJv\bp<\"\u0015:\u0002h\u000fqͮbθҢU\u000eaOUi;\\\u00128+f$`\u0016'*\tܕH.D>:+W:9\u0016J(M\u001bN(ǶZZ(qǞ\u001ehCɖTVG7GtGV\u0006\u001b^euu\r\u001aQBg+0Y?\u000bU\u0004״|id\u000fω\u001dᗜC\u0016\u0004/n[#\b}\u000bS\u0011\u0019\nm\u000b3k=jt\u001eUʢ,L2(+wQ\u0016CW\n}E\u0015g]\u0015ػ(9ʊ¢\u0015=(2\u001fmy<?-\u0011w0j_+(\u0012\u0017-o&4❄f##W\u0011GL U!mw0DW\r\u0013a\b/<eK{) $\u0010]7\u0003OQ/Q\u0016M*=\u0004l\nM\u000e%_waxi6xe$%\u001b'4kp:\u001eA\":RߕE\u0017Ng9BC\u0011mo;\u0014u\u000e/J\u0016ݕM`\u001cY&3@=ɺ/\u0006>{P/==\u0002ȋ1 㫺>(*!.\u001c@V\u001dsfCEa1յ\fI='Bq\u001arF\u0019.#u_\u0013N\fQ(edNE:\u000e\u000bi2B|i2\u0012)NA\u0012\u001c&\u0014x ,.M[_/\niEFJ/\niEū\n(\u0015=\u0002xenkaqY\\A\u0019ʇ,J\u001ab\u001b\u0007e1t\u0005;ɿⒶrՔ\u0015%Ǟ-Ҷ\u0014,5\fe]6}xHY,`ݻ(+\"=\u0015o,nӁ7&^CY\u0004]Yl\"\u0011\u000fe1tE6\u0006bs\u000f)+=\u0015U\u000eʺz+J2E~\u0002\f]k\\7Q\u0016Q\u0016CW\u0004CY\f]ў7P\u0016IWjՙ\u00152k\tI,=bb\n.b芎\\9,}^HY|+DORّI)M@ch,/1O2Z\u001a38Zi{\u001bxy\u000f~z\u0017e1tԉ^z1t#k26*e\t\u000b\u001e,*-.x(3ߘ\u0011Az\u0003yψ04k3\"d\u0011xp?!#\u0002)\u00136##¼?x^.;A\u0005\t邷N~(O\u0017$/ƥx\u0004J\u0007\u0005\u001dN~ؕ\\bg\u0013QE\u0014\b\u001b(+U%xHF~\u000be1tŜD\u0014QFl2EY2NV&6O/,{(+\u0017{=eOyGY\f]!]&b!@Y);8BY\f])HY\f]7辅7\u001b\u0018B\\\u0018}ۍ2\u00128\u001eߋ)+P\u0016CWs(+\u0005>b8~\u000fe\r1e`@>\nӷr4f1£4f{-<Wbb\nE\u0015DY\f]}yb芺\u001d\u0015\u0011yQ\u00076*>*+->\u0010\u001e,V'Ch{\t\ry\bcx\b=Mhʔ7\u0011uu\u001eq\u001e#4ꮛ׉aOam\"\f\u0015u6\u00116N\u0011aF\u0011\na$X\u0001T\u0017a.U\u0016[*|\u0013e1tE;(+]Еc%\u0018@0e\u000es{GĽa;\"lFi]\u001d\u0011\u000f\u0014W]qGYB'<No|q\"!2\u000e<\u0003]\u000f H\u0013a\u0006ѻ(+:\u0002D=\u0015Yȧ\u0007\u0002b7\u0004\u0007i\u001fϥ0\u00034@(UƮ\u0002]\u000fF\u001f\u0014Nߚ\fM[\u0015N@t\u0016ˡ\u0002\u0002eq\u0004̛Ҙx?Ƥi\"~!\u001a;}\u001aV=5\u0006\u0015& +-\u0002־5\u0006ѕ\u0002,3%\u00038\u0007\u0002\u0013V\u0018,}4.^~\u0012/YڌlA\u001bG\u0006398ѧ<;4\u0012lF]3\bG6\f\u0000\u001dD{0ٞ+8o(l\rJ{&z=,Og\u000fK=\u001c\u0007c\u0007͏=odFX\u0007\u0001\r/,(]f\u000fy3\u0002(ߐ%\u000b8ߓ\u0016b\u0017LADU=7-_ޛ\u0016Ti\u0011T|i\u0011\t7\u00147\u0006\u0015ዽ1\u0006\u0015}\u0017\u000b(K<J/\u000f,ӧ>ucz\u001fyκ\\u\u0018y݈ޟuHY7}Y7\u0006RY7\u0001(b\u000f`7wt403\"\u0006K/FA*W\n\u0012e|x\u0007卿\u0018NF+[g_HY\f]W\u0006CW_)\u0016*J!ʲĝ\u0013g\u001eCb\u00162#!3'Gc'$?$ѠIbߓO\u0012a\u001bzXe\bC\u0013C\u0019mB\u0013!%9&\u001891W%UgB06\u0007D$\u001dOc{q$\\\n|\u000f۲h\u0002 ARrPc;`Y9\\Wo\nt{o{\f[\u0006I\u0010PUoU0aumӍ!7\u0018L\u001cE=?1{b\u001f\u0006ϗIsPVk's\u0014ȗ|od1\u00104K\u0006=p3\u001fuٸ9\u001b9|q=wG%u]uӸ\u001eU\u0012j\u001e'Lƪɠ5֗ޒR_;i?-M\u0005(~_V{\u0007\u0016}[yDEvϼ\u000e{yW/w\bܫϻzgs\f{y\u0017^}\u00057,׋c\r׿\u001fVg7yP?d@{{y>g&Rno?Yq,OYq,\u0013\u000f<=/ǳXoN4\u0014\u001a9\u0016?:0c\u0007\u0012'\u001a\f+'\u001a|BMs;P]\u00069\u000fioN\u001as}ۓ?aΨI?s\u0003[7'\r9Ã9IO3#v_Y\u001ex\u001d\u000ep\u0006|+VM9mڬ^ɷ\u001eLʽg\u0019Ё3Rl\tZ*&\u0016<6t96x&Dr\u00037V\u0012ލ79\u0007o=\u0014۽w \u0017,<\r\u001c(ۙ9̺[HUԀv0eWv\u0002#\u0011s\u0002NO\u0011xdW*\"FPmcc˗/\u0018\u0004qc)\u001b~{``dl>Vt;_oVJˋ-k`\u001dOm#D^6/c\u000b^{\u001a7Vf{5\u0016ɡo_\u000f[E~I \u0002yp2e\u001e<'Q\u001e쥌S(NrGuOb%\\u\u000e~)ˬʙ6w\u0016V<XhD/̓ 㭀'k,OQ0zO4Kl^h\u000e/vfm\u00129y~\u0007lb\u0010ϢM\u0012.|k&UtT&\u0018\fwc\u001d\"=,7.\u0014oM7\u000bc\u0015\u001a_쭢\u0000i$Ęs\u0000\u001b\u0018F#\u0010g})u\u001aw\u0017/#(l]>\u0001pѾ_iDQ\u001f3*,;G6;Hl:Rj\\ukO\u0019͠hueg4\u0019>\u001dXg,݈,Qs\u0011kt%?\u0003]F=\u001e6\u000fD?ڣG'h\u0013/oHҖptZjGލH)²ݴ+<oT^ڒj)qBZb8\"|v϶/GJa=ۖ􇕖\rqc#Gl62-P]ҧЧT\u0015ݤSC§\n\u0004\rkJ-Onjrl'.a)V\u0015)Tڶ<jҾ@#¡J;m񖰩ҥ2*\\z+~\u0016:>Ul-[-j/-a~Z!@\u0012N۞2'mT&*\u0012V\u000e5I4p{\u0015k<-mVQAC\bE!u\u001d̤i%s\u001c\fW\u0012HҬSVZ\bFiߣAt׺Eݚ#\u0016YHv=USܑ4.\u0012\u0003x\u0002mAM#h܄H{4AR߄~M:`\n\nh=\\/\u001eQv\u0019z\u0007\t([Bd\u000bk|η^@^B5\r\"UD=\r\u000eh>}\t^:=wԧp\u0018U4ӾZ4\u0017o[\u0016J\u0016\u0000uG\u001f6\u001aJz5EKuc22eYnEn%6\u0002P\"FJY\u0012e`XMVX\u0012 Ȁ8\u0007~wD~{\u000f}Л\u001f Gx\b!.b\u0003|\u0004/~Ћ\u001f%Ǹ\t1~B/~͏\u0014z\\\u0018_}[\u001f-\u000fq\u0016CS_\u001aI*I*I\f2\u0001bQ6\u0002\"5V\u00048\u0003\r\"9x\u0016`)\u0000ي\f@#יaa\u0018E\u001f\u0016\u001e-\u001cp.Q\u0002\u001c>a*\u0007\u0000S,\u0013RHH\u001ajZx/D\u000e\b\\|OP$P=\u0010A\u0012\u0016\u001cͱ%*7^\u0014s![8QKţ\u0015fdX\u001aK\u000fI\u001b^cvh{\\/5Z^K$d\nn-ѢθO\u000eWNO0;5\u0006؁R*\u0014F\u0006\rPU\u0006\u000b\u0019D\u001e(\u00112ϸˋWhs\r\u001b\u001a\\w0ʒN-6\u001804*,s,H\u0004*QD\u0010\\ۮaL\n\u0004\"2s,'ъ`9$d$\r\u0006R1䏀\u0013R]>\f\u0014\u001e%f6e-\u001ar\u0006\u0005x#!%YAL\u001ch}̭ $\u001cn&\t۰+&2@ŏ\u0012W2\u0003\u0012uT\u0014 D0R\u0002hˀa\u0010M\t2̚lT\u0001ʠ2maR(.\u001800u*F`5G\u000b\tܱy^XN\u0015\u0010\u00191C;iz05\u000f\u000b\u001c.p=\u0005@ck\u001e\u0015jD}H6\u000f\u001d\ft&4:`b̋J\u001f\u00190@ppIh\u000b\u000bBw\u001e\fɀ4\r5K\u0011%ƴXY=W\u0005:B;\n\u000b7;P\u001f\u001any\u001f0QAkf_\t0_4T\u0013H\u00024U᳴c\\\\\u0016\u0014(JD,\n<<3.\u000e&\u000bw\u001cn'?@\u0017\bğM&\u0001qB\u001eQ\t&%Ĉ].QpIO\u0012_\u0019*F\u0011S`9\bT\u0016-YAR\\s\u001aa\u000e\u0011,,O_hB\"\u001bHz\b\u001a\u0001̓(}W,l\u001dK\u00025j%\u00040&Sh)bG+\u001aק\u0000fkP)ڇy\u0012*\u001b\f(Q\u001a&qO\u0015<蟛I0MP+b\u0004&Rwo[\u001bn*\u0001x@61mGv {bq\u001a$i\u0014\nh\u0014t^I\u0012\u0003ĵJ,\u0017C2\u001c SD'+\u0004yϬ_R1>!q@PZ\u0006\f\u0005\u0013(X\u0007ڂ04\u0002ǔ\u0006\r(̘`k>i\u0000\"b)X#ڈsȂ9$\u000e?-2\u0011Tb\f$c!\\\u0017\u0007AP=`jɚ:d*\u001a\u001fk\u001a\u0001U\u000fT(6Иo,\u001aphZ[)f$6SXtDq\u0001\u0010R7i.AE h0_4\u0013=Iznbx\r8\u0000\u0004bv\u0003F]IQ5:r\u0015&1\tD`K$\u00144!tjP\u0013\u000e&]\u00078M&D#Kw\f\u0011\u00127_\u0001\u0017}x\u0015Ѿo\u001a\t\u001d;YF|pBd\u000b0JiDCf層2PYO8\u0006\u0012v\u0000*\\j\u0013D X\u001c7F\u001c0CR,\u0004%)\n.*i#7Ͱze[6\u0018K\u0019h7}\u000b5HG\u001aBȟ#r\u00197\u001a\u0005y\r$Er>\u001dݣ2\u001e2\u00076\u0014\u0016\u0018r|\u001b^.!&hd\r\t\\Cf|b1P\u00183c(ǵU<\u001aq5\u001a`z\u00025&&á`\u0001Mm8$YL%\u001e\t\u001f_\u00068\u0000h&e\r\u0005\u0001\nf\u000f\u001dJxm\u0010 \u00023%\u0010A`bh8}_\u0002%\\\b\u0004\r\fᄈ׾ф\b\u0017Q5\u0000h\u001c'^Q\u001e\u0013q,#.>XQ\u0012\\bf\u0012DhH#\r\u0014X0f\r\u000bV\f*\u0014\n\u000bfm\u001d0r\t\u0000o-5:\u0006\b0%2\u0012猝5\u0010a\u0007\"@!-\u0017\tQ@$qAؒ\u001f@J2\\`pq<3\u0006s\u0015\u0002&֞Z\u0012\u001a7i\u0004\u0000\u0013\n#\f\u001aQÊƘHYA\u0007\u0012\u001c\u0019}\u001eZ2\rΊD\u0010):\n\u001cs}\u00038\u001b1\u001e\u001d\u0016.\n\u0002&tc)s#y.\u0001ilv[\u001a\u0015eb\u0019v*R\r\u0004I\u001b\u00078=H\u0018]N%, H6\u0019l\fA4c\u0013`\u000b%\u0019\u0006lĳ,Kdg\\HS%\u0002+\t&X\\\u001dPϳ\rai\u00190#\u0001Ycl5\u0006A\u0013\u0012װZX\u0012f$M\u0000e \u0019\fAB\u0005\u0006ږ2\u0013\u001fxZ\u0007A\u0007\u001473t\u0006\u0010l@TBL@Iׂ\u0015\u00022\u0007i\u0011}B#yq'\t=(\u0002#\u0018\n\u0003s(\"HD\u0006\u0003=\";}?%Yϰ\r\n\"\n(\b\u0003\u0000\u001c@}d\\\f\u0006F#Gj2v\u0000p\u000f)\u0012<\u0006/067\u0014,[`ô\u0002&,p(I|+j\tS9=AhN\u000fY\"\u001a\u0000e\u001e8*!1\u00016=el#x@!&\u0000`1\\\u0000k\u0016,\u0015K\u0007\u001800+u|c>)<\u000e\u001bO\u001dkHkdgk7;bT{j\u0016^/G;\u0018\u001bcG\u000f!AK\u0015%Tҥ%U\u0005'O\ng[\u001bR$~\u0015-q?\u0005\u0013\u0011AjY]!D\"y?:tu\u001e5-?^4k/\u0003nvF,\u001cAA\u000br[.t\r:\u000b?\u0012޼ݎNjw\u0017/\u0017OMÛ\u0000\u0003\t\u000f\u00067;$}w/;:%ͯo?wL2e&<\u0017_jRvX:[=|H~?+ߋ+>7VYeW\n&|ЯTo1\u0010\bvO_\u001cwh0~<!a8?\u0011\rF\f\u001b>gԖX4Ww2P.rbn@(\bt`\u0016#\u001b\u0010\u001b\u0006!\u000bl\u0018c\u0014⊘\r\u0003uPrm\u0000xϠmB4x9u\u0011y\rlZY\u001aW(\u001e\fV\n\u0015{bʼ&xrg\u001cߖMhU\u0000l5i\b`\u0018GBECI\n3z3#ǖ!vcxxeAxA\u0013YLa\u00171\u000e!E3\u0002\u001a(\u0018ʅ'Yb]R}X˩k\u0003N\rf#)\u0015\u001eze.nK0b\u0017I}\u000ef\u0004QEaac\u0001h(7<iE!fy5\u000f\u0019P\fj5s\u0018QTG\nH)_B\t\u0014l!\"M?=%K\u0002\u001555\u0016͗\r\u0017\\\rg\u0016z`\u0011\\\b%Aŀ(m$\u0003p^}\u0001(Pffvy\u0014aCÁ\u0014\\[\u0011KU\rc#;\u000el\u001cOKҢ\"-t\u0012VQ]sX KB˱=cuIP\u0019\n\".@&:l\"\u001cu5\r4Z @ϸf-Qj\u0002AUg\r#\u001c8!*\u0011\f\u000fQ\u000f\u0011d0H\tt,۴\u0018H:]jT\u0017q4uy\u001eil4-*BlZ\"\u0000X#%\u001aA\nW\u001a;\u0004\u0015܃K\u0005Nze;08\u0006Mr\rv/06\u001aE\u001djǖL9\f:Nـ]\u0018]\u001ek&e\u000f&%/\t8ȫاptڣi-\u0006Α잠\rOf+8l3\u0001r?\u00050U\u00013g^HB+\u0006h\u0002軶vF\u00138($@OʜG\u000eACo~L@m\u00019\u0003t1C\u0000%\u0010^y\u0019F\u0014\u0002N\u001c\"\"$\u0017?&ŏI#zC\b\u0014!\u00041\u0004R\t\u001d\\\u0002fdB\u0007?&?%'˟PQ ʟR\u0003r\ns!I\u0005q1Yy1!0\nQ\bB`\u0014\u0002\u0010\u0018Xf#\\BѪN\u001a;.s\u0010\\|,bf\u0007\u001cuկఴm\nmn>[iibl9h\u000f\u001c\u001aMA\u001c\u0010*@F0uf\b \n\t^\u0014\u0007NTj\"\r\u000e\\4p\u000fk`\u001aFp\r\u0004ׁ>|\u0015\u000e9ļ9\u001eol&\u0013g1\u0011h$m۔\n+\u000f\u001c0u>2|\u001dB\u0018c\u0010\u0013\u000eP\u0000\u0000\u00128D9\u0001\u0016~\u0013\u001fRQq,\u0005\u0007¸\u000e-\\^\u001cuEs\r!\u0005A\u0003E\u000eV\u0001\u0016/!\u00101mɎ]\u000f\u0011\bֶ6`|8fӖ%G\u0018'gb̄\u001f@.!&\u0002Z|&b+\u001eIW{\u0015\b\u0015ĺ \u0006Ĉ@\u000e\u0011AO\u0011Qq\u001e\u0011{56Sk\u0016\f\u0014^3g+hXj\u0006\bI\u0003\b<@\u0016V<(\u0003%vN<G\u0011$=\rHdXE߆hw\u0014\"M|X 2]\u0010P<xm'\u0004+\"\u0005a6A\nqK%p\u0005ܟ(òA\u001c{\u0018\"A\nd\u00068bT\f\u001b4f\u0005)!Fv9F`.=n{\u001b\u0006q\u0004y`L0\b\b\u0004{BȑM\u001d׈U\u0018L.!\u0001,\u0011\rGur\u00194A\"Mm<W\u0019 \nkyF@e \u0010\u0010{$ix@Q\u0011h\u001fx$)3(\u0016\u0010ވ!&\u0014qA\bL&i`& \u0013}e@4Ѯ\rm\u0007:9Z\u0016\u0010kռ0m\u00111\u001fp!DC.B\\\u001abϬ@\u001f\u0011H\u0010,9Ng$=}&T`B\u0003Qm#5\u0011GzhZ$)ĽN/6\u0011rI7\u001b}S\u001e\u0002\u0014-L#6\u0002\u0010aڬ\u0018&\u000fK=wԄҚ@\t;bQ\u001eȘx\u000f\u0011\u000eH$q !\u001a:`X\u000e\t}j\u0012\u0007v$,\u0000\r!ZL&\u0006e\u000e\u00020\u0003;xkЀ%\u001cs)>i6\u0006hƞ\t!\u0001)!YM\u00116+w1Rhq|ZBﱻS!\u0005\u000e\u0007}0_hp-ћ1\"Q+\u0003Y\u0000d\u0001Q}\u0004]{Υ\u0011s\u000b\u001c5,bqo)C\u0002ׄKZ>h|lD}67S ~F-@B`\u0000\u0019N\"܁7\u001dcYB\u00030ẊH\u0018\u001aPF&\u000b4\u0006A\u0012_3\u0011\u0011Y-\u0013xĞz\u0014 KO|6\u0002\u001eR\b>\n\u001c3\u00012po;7\u0014u\rJ\u001c0\u001cgA\u001a\nk\u0017\u0016/SK\u0004[ ؈3\")>*\u001bB\u0000 \t2eъxNɕ\u0007\u001b\u0004\u0018BQB]r\u0002-ce2qb\u0016/pE\u001d;\u0014F\u0007\u0011\u0001sQC\u0014\u001c\u0016\u000e@Y-0\u0015\u000eh\u0004\u0007Ͷ\u0004l*%\b:\u0018JX\u0007zCzƃ%\u0002X`;\u0002f)\bXC\u0003$ٍ\u001eܗwlAWGL\u001b \u0003\u0015\u0017\u001e%\u0007@4ݢt\u0019e\u000eַ2P\u0012\u0012>+ƞ1\u001exP;A$,X!5Ӏk\u0018( 5Ɨ\u001c2Q;Tzg^#.\u001e\u0000K0<.~W(@a\u0010\u0012x\u000ep \u0002<CbĒ\u0002ћ~\u0018v\u0012\u000e-_r\u0003\u0014Ӎ\"dL\tP%6Q~`\u0000^ЖUOg\f\u0002\u0010݋%369\u0000C5-\u0016(\u0013l@\u0004\r⹎ck0\u00016\u000b\u0017lA\u0013\u0014BY$@\u0019cAem\u000b!$ī㚊3NC\u0011H'&\u0003t\u000fd\u000bpia\u00043f¶B(68Xk\u001a*`+>\u0018j\u0007큘4\u000e\u0011\n-H\u0002pA`U.S>댮歇X\u001b<X-%\u0001V\te\u0007e\u0018\u0017HSUf\u00072)̺sD\u0003C\u0016[.\u000fN\u0018[\b^\b\u0001\u001e\r\u001bľ`S'\u0010m-TWgm\u001aC.ka2\u000e\u0004Nh\u0004x\u001c.!YeP2o8k_\u000e\u0004?\u001cz\u0004`\rl]X&Kkl\u00192\u001e\u0002I\u0019\u0012\u0005\u000eQ<f$ϥ\u00065E\u00079\u0019\nv@ߑjb\u001b\u0001\u0019\u0012x\u0001F^\u001aam\u0011\f}\"O\tG\"ӕ>v\u0000Mu\"\u0011Da ,3\\[\u001eĻ\u001a9\u001b\f\u000b\u0016\u001e\u0007^\b|\u0001p`\\uT,I3f\u0017dq \u00006 \u001a\u0014,%\n\t*du\fllrͶCl\u0000A\u0000r\u000f\u0018qJwa3eNqh2\n\u000e6o%\u0004lO#,\t\u001e9ۨ<(\u0018La۠\u0002b^`U b.#K\u0006gŪ\u000b\u001b3\u0006\\苼E\u0015\\7AlF&֧\fP \u0019bDu\u0017o'(>h\u001c\b͆.\u00071,k}D\bIԁ\u0004k4:bvW6\\M̂\u0019\u001aCY\u001b\u001cm\u0001la\u0014W3\u001eO\u0011\f3\u0006PE('4\u001e-l\u0003Qp4\u001b\bB\u0013\u0016\u0011;CyX\u001d׾,\u000b\u0015t\u0001\u0000Z<8c\fX \n\u0006VGFIl\u001bsh%6\u0001\u001dB\u0010_dU\u000b\u0010AhH<+k\u0007*n\u0006L\b%\n%Ba5ԉ\u0012#|a`\fnb\u00043I\u0011\" :\u001b\bh`5\ro\u000e\u000bIޔ\tNgH\u0001`8F\u0017\b\u0018)b!,lFKFgP:.N\u0000I0\u001d~ \u0005װn` L\u000e8\u001b\u0019\u0013ۇl(\u001eoQ&Ym\u0019\u0005X!\b\u0004C$uֶ}]\u00181o%ȇ\b0\u0005d\u0019p-Yl.\u00183\n{l@\u001dLj\u001d\u0018$c0L.|6hzѰ\u001d\"\u0010Tɛ8W\u0017.p\u001bl\u0011TL\ncM\u0007\u001c\tL$\u0007\u001c|\u0000\u0006Y\\)\u0003y5:\u0019)\u0019F\u0006혰c\u0007'\u0010,a;'.nspk6_w*Ӈ\u001a\u000b\u0007R3\be[\u0003c\fy\u0003lVk=jm޷m\u001e6\u0016HJkĖ\u001f}xXF\u00177ƐD[aV@L/\b\u0016\u001e\u0003_R2\n3𐋎fm\u0004g\"\t\u001a1Ya\r\u0006E,hYlbs\u000e\u000bV^o\u0019\u0005\u001egfQ2=y\u0002\u0018v`\u00156\u0006;FTWtEU$#J*\u0013wl\bc\u00180F)Q\nc\u0018!(}\u0006\u001d\u001f#\u001btld2/\u001bt4\u0014wl5NnN<KG\u001cr8F \b\u0001\u0010\b\u0002&l֠c+#\u0003\fRl,)\rr\u0003'q4\u0019\u0004o7JVR\u001a\t`3M뙵JVf\u0018<@+\u0001$н5<\b\u001a\u0002oR\u0001\u001em\"ؗm,q&-\u0000@6Q`\u0001k}v\t\b\fʤ\t\u001e43~2\u0011`v8V\u000egq\u0003ܱE\u0002KTb\u0017ߍFT\n^bj\u000b|zy\u0001jx\u001dy\u001cI!)\u001d\fHL_ \u0014nم1\u0019޽}ۑˑ\u0001\u0017pֆ!͵\u0001\u001db^\u001a\u0012V\u0019g\u0004,06SP$\u00199\t}\u000f/qҀ\f\u00106ga\u000bϞ\u0000Ǩ0g6;\u0014 7j\u00164w\u0012V\u0004[v~_c\u00018A\u001aIc\nv\u00030'.cC\u001c\"\bJ\\\u0006dK!1y\u0000v\f:U&\\1\u001e2RhE8z+XoSp_ݘ}֢i\u0018\u001f M\u001fI$2i|Nš(a(\u000b:[eX\u0004`sf\u0007o\u001b\u001craC\n\b\u001cI@D\"6\u0011\"\u000f\u001aHv]\u0019y\u0010\u001a8;\u000f8naJ8\u0016\"}\u0013\t\u0004m\nne$dVe6\u001b9\u000bir\u0011r9I\u0004Wx٢AsL4\u0016\u000feJ\u001bm\u001a\u0010V\u0019)`n5Q䷜1M\u0004\u0018Bhb/1;\u0015a2p)\u000b\u00198-9YL0Oy0$+\u000bb'쒬#*\t\n\u001c\u0013 +E\u0004.X?\u000143)Lb4vx` \u0017r\u00156☠Dp\nd\f\u0019}\u0018ė09A\u0005'aI\u0000\u0006ju8*Se~Aop:\u0006_Lݥo)1t~QT0p1w\u001cm\u0010=\u0005ԿLH8c\t\u0007_\u0011pj\u001c,\u0012l\u0014q\u0001j\u0010Hօ@6pfG\u0014+ʤ\u000e*D\b$\u0010.6\u0005|\nBo\u0017\tHcä\u0007mG^;ɰ\u001c\u001bdC:Ds\u001aB3\u001c/f<?BZ&Q\"\bJ9Ap#׀Q\u0011H\u0013kə.z\rR1Կ&u:|Xȃy7b\u0007h\u0011\u0012g. \u0015d?&Q[\t\u001eRA~n_\u001ae@SHe\u000bԊ8\u00128mMdڤj\tƀ!\u001dryZR\u001e X8}8#C$\u0003\t\t8\u0013 b\"*\u000e\"\\㜂\u001d[{O$*AZ+\"\f㤘P`ls\u000e\u001d\u0011k\u0012&rl\u000f\u00028+A\u0016SLFW\u001fN9C\u0002i 9\u000f\u001c\u00170\u0000Z/b_:k\u0004γ7ӤQDEMVieϝL\u0007m\u00106AWq2D\u0019\bCB l\u001bA\u001ac\u0015\u0004GځBYeȑ\u000e\u0000 $\"\u0013 .k\u000e\u0011|\u0005C_ɒ\u0006J\u000f,\u0005d mz?FޯI\b\u0000\u0012\u0001\u00170;NaYQ&\u0014\u0010\u001f\u0000r\u0004\u0012\u0006\u0000sfKf\u0004o\u0001\u001dV}߈ұ\u0010\u0007P/\u000e\u001c7\u0011^7}.49a\"3\\ߍÚ`tΑ\b\u0015dαa)퀴愡D\u0018.6\u0003A\u00014͊{'MY\n\u001c8\"wc#qZ\u0003I\u001at[Y}j^wG+>\u000fФ\u001c8h+\u001f웬Á+\u0012c_\b\u001b\u001d]\u0019\u001a8Ͽ\u0004-IY\b{Et4_\u00027cŞ\u0006B;\u00004qFUP/MAzy\u0001\rW\u000e y\bύ]z\u001f6&T\u0014oƒ\u0012:I^ޟg*|ha+|taos۹\u001e۪.\u001fF\u0019^;clG?6\\Qd\u0004\u0018+Jۿ\u0007G^GЗv\u001f\u001cH}\u0011ӻfJhuy\"=\u000e\u001a\u001d~?:Owط7מhF\u0014m\u0005\u001bd ƃ~t\u00003=;\r\u000f\u0007F&DWn-t\u001aͯjNJͻ=2;\u001cy?_.|ٜ]Jji~SW:ѣDyl*7j\t}땙rf$::t,1u^^y)H.\u0016Wre/\rv{Ǭ&,\u00128>&\u0012Ƿ}ag$\u0003[wqD3ѸuX)U%\u0012\u00177z\u001e\u001b\u0003CUr*D1BcBz{h6)\u001a3\u000b8ҙ:ةZ\u001bU^mQ\u0014MnZ=g\u001d'e'R}Tݔi6\u001bNix漣r3EzMMҧ'\u001cbZsH)}>0v_\u000b!ݘO1ɽ\u001b\u0013Dr})*7rP?dNgssmsrٳԸW\u001d[b,;K%\nJSOɻQon뽆(߇]r\u0007I:]Y?.O&GR:'ZZ0\u00078܌Vٌ9쭲\u001de%x}\u0005.M1ݹ3Wru[B\u0005K\u0004]\f\u000b1n{\u000e\\KX{jꗕJZ\u001bG@dⱒVˇăz\u001aJb.{\u001ck'n\b[gȗ}e\u0010sL]N5bYqk%c4\u0015s/\u001d\u001aGt\u001c+\u0016M4=s\u000fNDו0o܅\u000bWJ\u0017|\u001b\u0012\u0006<Wjm\u001aZM\f9%f/Ѓ'\u0011<b']<'\u0006/\u001e'\u0017A_'S_|zG\u0007nQ+\u000e\u0006j:-Q<8!(@;.~iM+O6Ft3_3Sup\u000fE\u0007\rj!5f(GЫ\t\u001b\u0002\u0017rt'<|]L܃;X껋K/]\u001b\\Ps_\u0006I\u0004#Q5=P \u0015]{\u0005UǼL\u0010-7xAAf\fTˍKuc\u000fvu\t%K\u0016.Il}Q>^ƱSRe7c\u0015.\u0012ES$\ty֨8@=%՚|Lp\u001a1E\u0018\u0015|^\u0015B\u000e7\\+YZxDhFK|seu2g.S0w9/d\u0012Jg.mKLxN[OwӥH4|^l_gݍZF/lcg3%\u001f:k_`D\nb8R\u0015k)/eۗR1w)zaKs7w\u0016TrvK%-?Zr(I\u0004_ڈ\u001d\u00146sR5Rl_H\u0013,\u001cHlӫ'\"˵D+\u0019Tږ5-ܩJ>1ͺ$ʗ\u0018i[>)NL\u0014:Q;{*\u001cc,Um^~Ew'}e\\\u001a&\t[\u0013uR1rec\\vy̮\u000e\u0007\u00140\u0007\u0014\u0007.ƨ]\r\u0014͂;ur$JAR{ݖvsrFgkihpnd!\nv\"9V=9\u001eǙލg=.oA챨/^\u0000\u000b.,/qo6\nn/ͯ.\fXo-\n}$net4S\rpS{oQ+<\u00122Q\u001c\u001f|c~'\\y\u0017ccbzeQ+-EZ\u00161\\'[\u0012;L5[\u0010y[VNSV{sL&\u0019M.{v7=_\u0013[U;>\u001eiDUaһw\u0003뢾SS3~:Gg\u0016ʍB~+VH\u0012ùzM>_wܕ77?\u0018fQ>|<]\\7;%,UXo^_\u0011@gG}\u0007'FF{5s-է\u0003KC\u0006QQpiX/\u001c\u001cu\u001ae9Vs>\u0007G5gBr\u0000GrpU2Q!\nqTB\u001c\u0015\u0010G8*Q&sjB-\u001f|MNJ7Y<d,\u0017lZ=5ɉ~w[Ѽ\u0012ק}k9;/g'j:\u0018\u0018\u0002r~K\u001ceP\u001eQ>6%!ӟ;Q2~k\u0007p,\u000fk:Q!\nqTB\u001c\u0015\u0010G8*Q&EY^*:{,۱{%x&\u0016k]h&B?\u0011tK#CQ,FSPƢM\u0019}Q\u0013Wa([\u0002)/ .B\u000e?\bHMXɋ\u0004 e*\u0004i!\u001d%\n\u001cR3\u0017\u0006R@5R+K{ޙD*e4^N0ٳgju\u00121\u0007-\\\u0010tȇ\\\u0019|ʜ?\u000eW\\~z/Vś%S9Z;=ϞtRkR+'KElsotVZ[*7n\u001eF\u0002Kߞlu\fK\"߯L:VN&\u000bI~ama$CavU^\u00146\u0016\u000b\u001e\u0014\u001aZ/ϐ/\u001fJ̺xIj1%\u0016R\u0015G\u0015&&gI_=\u001e<kjT# \\Rʦ$4<\u0015&\u001a\\Rߨ0?dH.\u0012h质?\b,\u001ehV\u0013g31HRLg,0aNa!nW\u001bOޞfS|VTw$\u000bzEnEgEcaœ\\)|N\u001a)qtՄѲˈ\u000e)5yY;Tk3êm\u000b%\u0007L\u0019qxFV\u000e\u0017Hgy`|Q]\u0019d,eSCbk.^\b\u00024|(*(\f)\fţ&V\u001eooLq\u001e8y\u0019CЛ@_޻\u001b\u000b\u000f%Xk'\fiN\u001a\u0012uQu\u0016\u001c0MA<\\\u001bQ)Ǽye\u0011\u0003Qnr_<\u00104@\t4EbI\u0015c \\\u0000Hy\u00195]뢞Tpƾ  s{\u001dГ^Lҫ\u0016n;Mr&0W]Xǿ2&7弹s݋pX4#O^Ƽ|H\u0004ot/kzfd\u0005o5\u0000\r{r8}ZHpG2p+q\u001bO\u001b\u0001\u001d0\u001bΓV\\^%C#ь\"_Ilم뛵e*kNGs3k4\u0011\u0012=\u001e^qX_r+O78PuOYI&\u0012dekFH}I_Ӝ\u001emP_s\u001fW\u0013ܗ\u0004C\u0005<ui\u001e\u001f_[\u0016rBܫ7Ch3L䛱紓>*[\u0005@4\u0014_c-@46g*\u0001a@\u001f\u001aJVlxǅduRQki\u0005\u001b+b<<eeXRy.DI\u0019q2zGtnėKAN;\u0002遫Ao;qܓ\u001b3H4|dM\u000fɸrrg.n盝xG\fC+[xLn̒6:=ݍ9\"׋t*߼Cq<ީ̅6\u00074eOl+\\ȘWW\n7y}s&W3soP\u001fN\u0001\u0016ő$\u0005R,.ێޗNڗ\u0007\t\u0017\r\u000ee\u001aōmbM\u000f$ڋKZ$WN7uf\u001e'&Tp\"buy,mcG*T\u000eʒ<락_G\u00120`<W\u0005'\u0014);Oq\u0016\u001fRO*\u0000N PYP*6}E`\f(%+k\\>O\u00124V/\f>'PCT\n}RO*I>'\u0015BԿ蓪Dee;hG]mXiZ˱\u001d繹>;ԕWEs-\u0012ɩM܏\u001dDմ.^vrۦ9\u000e'[nBvxΜ\u0007R8+sI@*=}53M|Z$t:@*ue-\u0010\u000eJG\\\bB \u0015\u0002\u0010H@*\u0004R!\nT\bM u5&N\u0002ikyke\u0016ɚ-˶ζ<ߟ1l\u001axjK4r{\u0007l\"_WM5#Ϛ{\u0007\u0000R\u0004R\u00066\u0001 \f\u000e]\u0004ib->#&\u0011!x\u001f\u0017dHe#\u0019uwT5u\u0015\u0002\u0010H@*\u0004R!\nT\bB \u0015\u0002\u0013HvdڽT\u00133_\t4kV4S' zL(\n\u0013\u001dy\\$WB:^۹[Q,$\u0012iVO\u0017HWC\u0001R\u0004R\n\u0007h\tsǥ\u0011\u0000rKJO \u0017\u001eHUr>a\u0014F9`\u0004z4~y<VZ\\.Gfgg\u0012Uu.PʽҠܫf=|m-1eASfܪ-Pfk\u0012Wh\u0000se\u0017[FV287\u0017]ŠzrXݪ\u0014\u000b\u0004Eޤ\u000f+e꽑`{&*L\u0010_J}+\u000e5\u000eG\"5}|\u0016,~%AWJ\u0012C@U\\Kq')6)XY\u0019KY|oϗ\\\u0004>Z)Ҟ\u001e㎹B#\u001bYڇFU\u00130o̅\u001d?\\mB-H\u0018\u0015<$8)eηe9\u0007:f9C݌KWF'\\HG\u0004?,\u001a&\"\u0016w\u000bb\u0018\"\ty4\u0018ۜD/cMmS=T٦eWieɣbcS;$S\u0017YCcGHETf!C\u0017\"\\iVПmI̥.}oz{;wJ,}Z\u001eS6\u0015vIG\\m1Dq<!\u0018i]0v<&}U{\u0005}\u0017SC\\\u000e\f\u000bu\u0001%o\u001e\u0015\u0007H$\u001d\u0011{\u001cG4{$#ǩkEnzz1\u0000\u0006C[/\\-M_/e\u0016W\u0004e`dM}UK\u000f\u001bX\u000b7/3tw\ta+46\u001fa\u0007z\n{,̐$\u0010-$\u001cĮ$iRBN\u001e(\u0015@\"d[Ž0\u0006,mvCvi\\ld]sg:w=Ne0oܺT=3\u0001s[T\u0004\u0001k$#\u000f= q<\b\u0015[-.\u000es'\u0001hwO1هs\u0003`\u000eʶ7+,xW\u0016\u000b.)v{EZ\u0014-ҝ5\u0012\u000ewF\u0000|5LrǛ\\n\\D\u001ccS˾W\u001b/l\u001c\\2\u0016ß\u0015~9M/\u0015sI\u0003ٓis.חy\u0016dgb}7ؿ՘pl\u001f\u001bk)^\u001e\u0015*x㙆8\fC\u000fꅛs\\$ŨKjTWK\u0000\n,/\u0004{n_ZN9eW׺Xk7jn\u000f\u0003\u000fYYA#fn948-\rKK/\u0012b\u0014\u001a*\r|J\u001ew\u001f\u0007vX\u0016f\\\u001fl;bW\u0019\bq2f2{^4tzF\u001e|\u0006+LoTʢ55\u0012-^O\u0015p6GlfY%\u0007:w\u0017K{Y;nC@h?r+k'X?n\u0010_8\u001f5cSyד3ߦ/]gqO\u0015srRO]J2o>]u|\u0011;\u0001X%~GXe\u0011=>Rơø?\u0002S_SRґ\u0005.%T+RM_\u0018S}R\u001b9\u0015:BT\nSs*tNΩ9o:^eſiY+MlڗM\u0015\\ƣ\u00172t<w7ԅ_b~pRgk!2Θwe\u0019s-Q\u0014&qq\u001fHi߷՟\u0005bWU{\u0011sN\u001c\u0015Bz&\u0003y'd(?\u0017嗎!\nT\bB \u0015\u0002\u0010H@*\u0004R!7T\"a\\\u001a\u001f5źLLd<rg7\nז&\"UuQ?#\r~v\u000bU9.^φq6{\u0002)Mb\u0000Hy:(  \b\u001c>#z.\u0012\u001a?⑚\u00169\nCN@p>\u0010\u001d\u001e]\u00016z7v.Knr;CN>\u000b}\tG\u0012}\tIDJ!'DW\u000e\u0017!'D?CNn(9>Wj\u0010\u001d_9qd\u0010\u0013r\u000f5!:\u00033#QN>#QECNΑG\u001bCN>\u0012CN\u000eڥ!'D\u001frJ&Dg}\u001fHrE/|[+ne%DNn%$D\u001frJ\u001fMnV\u0007V+\u001b2Z+\u0004Nڤ*eisoGg\"{'\"/D9\u0015iB(\\w#\u0016w֣<ώNBg[)BO\u0003\u0011~\u001d[?\u000bO\u0011:\u0005UT3\u001cSɩyS\u0018a_1%۟HFNɹ\u001bo]\u0019MMM^N) a\u001a\u000eoT'g\u001a殩\u001f+)L+)E}\u0019^N+)2RR4RowM\rkT\u0014pJw6ެ!\"n9RR\u001cA>RR\u0006\u000egT\u001fӀ\u000fkTHtx{;\u00026RR#\u0011\u001b^N)\fk)\u0015=~O+yc\u0006{_a\u0015\u0014핂MTѽRةTQR}|y>r\u001fE#\u001a)ů\u0017rR-55{C\u0018ZMv43~ֶZȒX\u00133IJU}R;)\u0003\u001c\u0000L\t'aP*5}%s4\u001b\u0016J͑q\u0019Ya#EIP7K=t*ga_\u0018\u00171~a_\u0018\u00171~a߿\u0018W[x)+sSi¦\u001cm^\u0011,\\ܸj߷e¿iT,Bo\u000bD'MIgG-ǻsH\f!O0@#;\u0000l\\\u000f,5)ڵ>d>#ƏQ^>)>ժgÉyHE\u000b\u0007\u0007\t@ \u0015\u001eՀB*\u0005>,H\u0003R\u0010 \u0001R\u0007\u0003/\u0001\u001a\u001eb \u0015A*|\u000b\u0007zLjx\u0007xB\u0005:\u0004L\u0001UÃT=\u001f.\\oCT#w}D\fF}P5<H5\u0012탪A*d삪A*D#tA H\u000f\u0007h,OZ\u0001HK\u0001Fཇy\u001dO\u0015&n~\nRD 7񑵴1'Rw;[\u0010SSNo+ם\\\u001fMh>&c;kXrv\u001a2<}$_Ţj߇T\u0000\u0012R1 Ҏ;\u0016JN_9+[s3ɇg̞p>5Z;\u001eLٗI%󛝕oW-<T\u0011 =\u0012#9\u0012\u0013V|u2\u001eۘav?1R'l@Բ\u0017mKO$,\u0014\u001ex5vA`g\u0004#ht=7킽^ɺM_oUJ涌J)u9;\u00132P*l\u001a\u0015tLD>]䛴P賝[qzuBrPL|-o\u001ea~a_\u0018\u0017a~a_\u0018\u0017a~\u001f\bK\u000eJx߼#Ua2{&K\u001am]#ss*+'\u001bUhbv\u0007<wZz/\b瘒u\u0019ڒ\b\u0010\u0013Lyi@\u000e\nGg{ޟ\u0005&TPSm4\r쵦/;\u0013N\u001a\f{x`\t6\u0003\"\u0010c'8Ht'yv\u0013\u0018b\t\u000f\u0018N\tN>aN\u0019b\tN>y\u0019j\tN>A\u001cf'\u001c\u0014CN?C\toPOp\u0000SCM?'B5\u0013l\u0018V\tN>AXL?'\u000f7DpՐOp\tpOp\tR~O\u0000\u000e5\u0004' 05\u0013&C*i\u0010\u0013\u0005Z#c;_Y_)ͅe_Op菦;vUk]$NkO4eel7]kÉ3o=8OW}\u0005\u001fhyOƢUwt{wO<ɣǉÏP%2I\u000f@)\u001e\u001fg*6}R3Li^Md$/Y\u001b@!Sa:0_/L\u0017\u000bt~a:7>\u001dF:__oEc|&TV\\~~h\u001d\u001f:w-k~TP\u0005bZ.J!{!cا%\"$==r\u001fo*9}\u001a#$Vz\u0016}E?7Ka='z|\u000f\u0010L`*\u0004S!\nT\bB0\u0015\u0010L˹/^UC$3Ro\u0012<\u001c\u0015yZ9r]FoF.;ͱ[Cy\u001b2~-#WW+j2v?`J`KK0T\u001fLyvZDYx*Ax*3'5uT\"be$\u001e&\u000b\u0013\t~aB0_/L\u0017&7\u000f=~QŅ̝<W'p5ᤣ.עh]ku6ŵ\u0012o\u0011:$tn-fMhzjH&ۈ\u001c6a$~K Eu`^tO+Oa\u001bbWՕ\u001c̸s\nOhQ|?T:φ@*\u0004R!\nT\bB \u0015\u0002\u0010H@\u0004RX܇IXfcS%]t3k\ty\u001evv^wi_\u0013\u0019l]\u0012@Hy.\u0016ܙ35}<\u0004 E`7\u0004R&?mQu\bCި 0%=#0TK{m݇3W\u0019\b-#D\u0019T2\rѻ4{;էg\"SU\u0012jmaY!ԛą%&^\u001a!}G,l^\u0010Ѥ\u0014?P$t\u001e5\bzҽG8\u0007\u0005LՙJr\u001ewU9׾pkHr{0\u0003! \u0019\u0012Fǜh(\u0002\u0007\u0010w:]'\u001bgR\u0018xt6R,tu''ףy$\u001c̃C,rxw3ϡH'e=\f`}\u001ayD/C\u0003uK56KY/ˣ!Shh\nwƒcB\n^70)A8b\t\u0001L}x&1$\nx&:CXu!J/\u001e\tn͕6'P\u001bKȟHuwsqThMզQT\u0006Xx[Rb\u0006y\u001eNjs\u0014q\u0007#)\u000b=cѾP\u0010dm$E-\u000eK0Q\u0016ͼic_j\u0019BX Jь_]0/mAs7\u0017'\u001f}s\u0019%%L`\u001cv\u0007$bBf\u0012aY&\u000bL\u0001t?ӈBs\u0010\u0018OR_i\u0004]p\u000f\u0004jdm|[m]sh1Am?BaNϮg\u0010உ\f\u0012ǈ2,MN@gDb\"H{\u0002\fEpᬜ*IZ+\u0005\bs\u0017_\f~{1кD\u0003\u0003cr\u001fإ\u000fKˋkop\fI\u0000\u001c<ky@%Ore@\fKO\u001bWoak5qq\fpqno\\#B\u0018\u001d)׭JFLJafeB;\u0019wvZ]j3P5բh^:\u0010z3\nnB\u0016\u000eƲº]t\u0000E5;H[^S뛯\u000fP\u0003&-aM_xnce\tm]&۲A[\u0004\n\u001d}xi\u0015`M:5G:\\6׹'eԜ\u001b;\u001b\"\ns\u000f5Ԛx2\u0010\r\n`V,<Aً  ̻?RҺ\u0019\u0018z\\\u001cgs\u0011\u0015v؋#[y{\rZ\n;_T&o*]wZg++_rYk_O[vK\u0012\u001a>96Y\u0012:۞H\u001dBKv\u0018MR7\u001eϨڻUBA\u0007\"\u001dj\u0012%\fռҝݖUÞ76\u0016)|-ʲzmt,G\u0011MGN\u001aM֢\u0000\u0018\f\u0010A\u0003-Ln\u001fBi_Y\u0000*6}5WCgd\u0013Hܩ\u001fqBC\u00153\tz}\u0013*tBN\t\u0015:B'T\nP\u0013<יu^;Yؕm9\u0012Ob!}~eګ2z@\u0010nKOVd}<іeB4kO\u0000suzqt\r5u4\f'[(J[RPS Z_)K2̏eӫ~\u0010F0*Q!\naT\bB\u0018\u0015¨\u0010Fa0r\u001e՝tYMWYKO\u0013Z|ۋS8pqW46\u000fOhj\b軥_\u0003:\"\u0018U<\u000erF9w{\u0014\tl\u0000D9N\u000b\u0004iڹ\u0002(O,.<\u0012\"80\r˞;_\\(^{WF\r%\u000f!o\u0012GBmt/\u0012ؾ1\u00137>6:\fF\r%d\u001e\u001b\u001bJl\u001f\f\u000eF\r%τ?\u000eD\r%\u0003\u0013\u0007\u0012\r\u0019E\r%Ϭ辡1\rF\r%\u000f MtPb8o0o(}#ѿ@6\u001a\u0007辡aD\r%fmtPb\bD\u001bJl_\u0010^ߏ\u001bJl\u001f\u000ey?#}GB~\bC/b+\u00177\u0012&c,kśnzgX+O}nTĔ=Z:#z\u0007YLH\u000bYի#-z>Ob\u0012OQJkmQiWRYi\u001f\u0001RW_\"5>\u0001Ph9'\n$\\J$i\u0007TzTBT\nRW*J^+\u0015zBԿbI4SP\u001dWu&\"+ۈ|&i]4֊Ndx$$\u0012ӪxX|\u0010ޚ~\u001aW-Q\u0014&G\u0001 XnZHH9\"$\u0007*iW맥<'<OF+;[8U%\u001e\\vc\u0015vAaW-\u0012G\u0017\u0011\u000ewb\u000b%FJsj\u000e7[X2EÖ=<,8`mj%ssޅUn9a,W=\u0018\u0010`{&*L`]^O\u001a\u001bHM\u001f,/'pׯR|1ý|+$*RIMZr|oϗ\u001c2RHaz5H\u0016l'\u000fŚ\b~yg.\u0018ߩ/l\u000fOۂ$P3\u0007\u0016',G\u0016@\u0011,gHqIj(\u000b\u0011`EJB&\u000bs\u0011\u000bc9Ebh5]g\r19韛W_ƚf\u0017\u0000Y}ݞ_\u0003\u0002\u0010\u001b!A\u0015\u0005kZJqgFL4-0?RM\u00144ߥ\\\u000f]4}oNܼO3TK#qզiX\\P\u0001*Dq1m46\u000e\u001c_\u0014\u000bn`LX+F\u000f򂯤S;%Л`_޻P70%\n\u0003$ӈ=z=Q\u001f\u0016izZ\u0000\u0002\u0018\u0018\u0002sJ1/4,\u0011[T\u001fǃG_=n7\u0013$jw8\u00104B}e\u0001e~.^..i<q\u001ezm\u0006\u0016xGIǡ_i8I\u0005˗\u0003\u0005\u00022\u0013]x<\u001at<l/G|Xp\u001a{zGyD\u0004\u001f,4\u001a(\"1No\u000er*\u001e-d{zh5[\u001ez8\u001e\u0007i[I\u0017ݓnL1\u0000CM\u0005H~b\u0007>'E\u0014-ҝ5\u0012\u000ew(6ft&e.7.h\"^)eR\u0017R1\u000e.\u0019\n׹ʤAze9eUӞݑhPИp\u001c5xԡ%nxyTg\u001aQ[\u0018ʞVP/\u0014底|\u000eM\u0012?#MrZJ\u0004wgy!8)\\xu\u000bv\u0006\u001dӰl\nqZ\f[G}\u00100\u0004\u0016\u0013V1m0SؿA\\n\u001blPwbW\u0019\bY7fpva8\bQs#S\u000ew*`JY\u0013߭<{Xjg\u0003=\u001d;@,M-|/:\u001b\u0017G$ٿ\u001eXtL,K-YlfZ;Z=י\u0013_܍خXwdez<ُsϙI%>EEl\"W]ED\u0007\u001dANH{RK+Ox\u0016>>Ga\u00040Etq߂Xl~}Ԑ=j\u0012>Z:q}sMҺVS1kvOMvp͉+Ѭɶ,7\rZV̥׾\u001c:O+gUZbUS\\=<e{ia\u0011:Ԥp۟J?\u0017׽⩤J.\u0013wME\u0013}`\u001fK \u00197\u0012};:É~6ҏ53H^P#@\u0019\u000b\u001bj\u001fzP#8\u001c釯\u001c!G1}\u001c!8t\u001af\tSC뺿\u001b7\u0012O4H?!Ga/FD\u0005Ì#\u0004X!GD9o~N6H??үwH{x0qH(X\u000fDzl-KJ~\u0016Dr\u000f{\u0016iU/\u0003/\u0003}trNذ޾&\\ۋ+ݮ\u001f'# OhӛH?KۚzG\tBA9\u0018❪۾,?NM\u0011*\u00126_\u0019M\r;uީ;\u0015zBT\nSw*Nީ;{O-5\u0011?pBR49HJZYJ޹N3p\"y:K7es\u0003>VũSVkwPG8\u0019\u0017))S\u0001<i)(H_Y`Sr\u001e*j\"~딗_gxIlL)(\u0014\u0014a\n0\u0005E\"LA\u0011\bSP)(󥲶vOS5eyHm]\u00116ڹ֙~MӘX?f.\u001a'M$FS;s뛳-י_\u001eB\n\n@&w\u0010HiO8\u0002R\tS\tS!\nT\bB \u0015\u0002\u0010H@*\u0004Rk@ʳ-w3*]y>3,+ue,:f-ﶱ>Wݍx:?! /D1BSA3Q{\u0018{\u0002)?(-\u0006\u0014aek̗X\fBsV,D-oaT6I=w%Z3\tx\u0007QAb*J\u0000\u0019QP\u0007I\u0011\u0004g{W`\u001fۭ7V!yۻvQN]>Wϕs\\>Wϕs\\?+'zJ\u0003\u001d\u001di\\up\"B\u0002޵Z\u001bz\u001e\u0017,J_+ܧtQn\u00010;*\u0000\u0012\u0005?ZψlRLS\fj+\u00157D\u0004u)-1}\fퟐC\u001fK}4%58\u001dKIKIKIKIԟ4/Z\u0017|\u0007(3r*D=!m\u001f&SR8_\u0015vH\u0001Qґ\u0014X\u0001z8y{v\u0012D\u0001j\f8J'B\r)&K\u0006\u001c.<\u001fq\u0004Kl\u0014l\nؾ\u0014*F\u001d\fǐRPMdpnspJ\\R%\\R%\\R%\\R%\\RϒRܑ\u0016\u0002x\u001cWLaQ\u001fEw(=yRz\"ApT.֝\u0007t.,=\u0003\u0016h@ٸe؇RgS6z\"\u000bxr\tZx51MLE.1\u0012S.1\u0012S.1\u0012S.1\u0012S.1'-4\\\u000fxjB$⻹\u0003h\u001dC#\u0018@/h@vq\u0007\u0014}\u0001սE#X-\u0016Z\u001dSw\u001e O\t\u00006\t\u000b@Jjrk\u0001)׶\u000f\u0017gIq^l:;\u0005 ?0;\u00056S\u000eS\u001efb)&\u0014et² ',;I~av\nRA~av&\u001cf\u0010\u0016\u001f٩xq)avj\u0006=\u001deq$d<>\u001b@8NA!?0;%!sB\u001b;NAYrOβS8w\u0002\u000e;,*i[*~O)-S0TC)\u0018WϲSPcO\u0012;O\tK\\SI\u001a+f\u0011\\BUN'Zԫ{I\u000bk8\rexKjtYakQ:Xo29:\u0015KIa-c/ڽ]v}JP%!.\u0016@\u0015犦k*ibj%\u001f{\u001fq\u0005eb*=0T\"`vJ\u0016B;.;S.;S.;S.;S.;'٩\b?+i\u001fIf\n\u0007u{x6d\f[46+y\u0003\f:'BhnV\fvϕJU\ro\tv~J \u0005iX\u0000R\u0001\"_Lmʵ-Cv\u0001@\nzC?0\u0002Sݩm\u0016\u000f\u0007j[qoo3\u000fk\\X\t̚nG͊\u0012\u0001T&b>T0\u0019@0{5q\u001b\u0000vN|\u0016RG2ήo%EepD\f\u000ft#\u000fх%1X][1^8|hama-.9KɣO\u001eNrc\"\u001e@i\ruۛH\u0017͔?I%\u001cGxX\u001c*x3`\u001eo\u000b{\u000e%HD\u0007B(`m\u000b\u0010<VIݡN><`\u0012zM\u000e\u0001U\u0011\u000eSt8\u000e/_1\u0019: O]\u0018P\u0014'\u0018@8[݀ػZX֣8PL\u000f'<ЧwpۡQ\rO))<]NO)i\u0010\u0011lFe]]~b^\u0014\u001a\u0003D5I\u0001@<\u0013\u0003=XxOb\u0001/Lf\u0004\u0006Nb\u0015\b)/Ȇ¸U6.|C*x\u0010M\u0004U\u001cYc\u0019lE䝣GdK,\u000bND\u0010BW\u0002ޒ]\u0000\u001b\fMۖ\u0002M@ؼKi\u0015X>\"kD\"eb\u000b),\u0001\u0018en\u0014\r=}\u001fm]T4tK9/\"eý8r:~NI,'oph{\u001ap\u00065\u0011Zu6'\u0010\rD*%\\\u001e2\u0000\u001f\u0013A( \r\u001dv\u0019\u001bPK,=\u0005;\u0016Ҷ\u000f\u001e\u0010*ΡܑyhΙn7\n\u001f$\u0013\\fkva\u001e1<r_`bv/&Վ?\u001d;O={z\u0007>ωyi;l\u001a@7[Sw}\u0016fk|J%\u0015_oYDP\u001c\u0015\u0017<\u0019\u0004L-d\u0013\u0013;/\u001ca\fw$q\u0000}\u000bh7DS׫1>xVg$\u00162 Eff[${:\u001a\"܀=V\u0010>s]^?krT)j\u000fɥ;c\u001dT\u000bГˮw\u0000Hxwb\u000b63G\u0012\u000f\u001e@VMA6\nD\u000b[6Og\u0013\u001bˍZ[kfp&>,ѦhKs\u000f0\u0014ʻؓ9ƾ\u0013\u0019\u0011㻇\u000fO!&wRi\u0015\u0007?<Վ\u001f\u0004$bq'{U\u000bc3\nA0,&\u001f\u0016\u001eHpǙN\tin\\op#^\bjcqFC\u001bzMKN/G\u0012HP-|p\u000bT1WY:\u0012zF8lK*\bo>-\u0018D\u000b߀SS)\u000b<SB1\b<|)8%-Lei>|\u001fZ\u0002p~ca?ia<ka\\^\\^\\^\\^R.j1:\u0017'{\r\u001e|\"-KWEUڤ#iT\rZ\u0003=01VՃLFUqr\u0004/~N %\u0014\u0019k~- ژ\u0006Rn\u0005R.r\u000b\\ \u0002)\u0017H@\u0005RT/ư֦\rV@\u0012n\u001cj4F\u0006\"K>Z|_\u001a\u0001 {wulgI/\u0004\"g\u0004Rq)\u00154.e\nyM:U\fп\b\u001c.([\u001fyIlX/\u0018\u001fE\u00070NÙq/>)ݮGKuV` \u0013ӽt,.u6\u0007G<\u0017x]Zۗ8)_Q%\u0012鬔\u000b\u0004sPmpx Rq\u001af,/Sd\n$\u000e}r\tIe[zWk'j)仑oWvUʯ\u000f^\u000eb\\&\\Y>¹o\u0002\u000b18r\u001f\u001a\u000ebRfV./M^.\"]z\r|\u0017\\H#[p(]%SOп|#\u0004eL2C2,e@a@hֻgR6\n[k6pO\u0012\u0019.Ҙ߫\u0016\u0017w\t/\n\u0003\t\u0006.Ү#\u0006\u001a\\TNլ- t%\u0012a\u0019݋jr.\b\u0010O)\u0015\u0005sk\u0019.6`#؍6ū\nM\u0019\u000f8\\eĮ\t-TUKm\u001aT\u000b:\u0011Bʸ[ypAoB=1\u000eD,7]wbY9PpdO&\"l\u0017\u0012\u001a{]w-\bm\u001a6?\bE\u0014f{t\n,GJ\u0006w\u001aɿ^*#C[vH9^\u0016ٜI\u0007Б7I|d\u0011d\u001c\u001cc\u0015@\u0017\u0014n(p\u0012˻Ne\b)J\u0010>)(nJ5C1DLY80\u0010\u0016)\u0003\u000b\u0015>\u0013GGהwLy\u001bmD@'ή'1f\u0017٭\u001f?\u0005\bNW?\u0019'םl\u001e\u0002,}ew8\u000ew \\. |֊\u0012S|\u0015C^ߘ#\u0005\\-6\u00135K\u0014ˤ\u0007(`s\t|\fn\u001fw\u0014y4\\6v&4\u001d\u0017%6'W*KvO'ŸH?s2(?(^\"a<uyh\u0013ځ}ۖt_\u0005\u001c#-\u0006m*\u000fPo9*gZ)=ngkj\r\n\u0001C\u001fvJa&d}\u0018$Dx\n.|\u0016uuvU\\3\n`8]a<\tB-2\u0001wC+X)yx]\"0\u001dM\nm\u00189\u0018\"\u000e+>lI8w,KE˓Ȓ\u000fI\u0019I]\u0012Y\u0014G\u0018eIk3\u0011\u0017#\u0000?AL|ܕ\u001bqN7Aoom\nytշ\u0007\r\u000f[\u001c\u0007\rBtNsj쒥Z'uZɭ=ssLC-t2j+~7Oq4w\u000bnvi.ĒaH+\u001fק\u00062>%\u0012\fa.)\u0019Z`O7۷92X#hEK;\u00123ΉV7\\oD\u0007SV&/֍INR0u\u001dgxU^J\u0012,\u0003a^jFI9Ka*ԌqTnR\u001apy)L\u001cd\u001f[\u001c䁱\u0004INR\u0016%\u001c楦5R\u001e߷\t^\n\u0007y)T/,7}$/\u0005\u0010)y)L9Kt\u001b|\u0004/ey\u0006זTvY\u0018R\u001ed~Z5x\u0019mB|p\"N䎆60oH\u000734G\u001aջ\u000eK\u001eyWd47=ZKQ?ħDS\u0016vbh+TBSRS*WҔM4'>\u0000MYzaY>\\4)\u0017MhES.rє\\4\u0007T\u0016%:GE\u00146\u00034(P\u001a(=\u001e66]*_®ÍNh갪\u001eN.a.9g9QC'\u0014h\n@\u0014CkS4\u0013\u0017䦪I4\u0011h\n\u0004\t_lX]\nt\u0013pS\u001fp߷h*2)\u001dkvՃ\u001fQ/R'g\u001a\u000fɞ_Efn׏ح\t]A\u001f۽(\b>\u0016a\u0004G-\u0012?_ujx\u000e5~Dp\u0006O\u000bzS:\n/7GbV.Ƈz\ntw\f\u0002[|\u00028ޔ\u0018.\\)Wo՛r\\)Wo՛r\\?7ؼE\r+uY-I\rlkh8\u00000^Qg1|X:ly\u001b9t&)h;6ޔ)\u0014@'\u000b~N\u0015X̯\u00056X2\u0018, !wGi?a\r\u0017!~P;:\u001e߄z^D4/T\u001eߜr\u0005bS9Rb7NnY*v}F8R񲰍t<s,<Hy*X*h\u0019O\u001cKeqS\u0017ΰT,6O\u001cK0^\"αT2\u0015rB6婜cfs\u0001J\u0007X*\"<s,\u0015nڧ<s,7穜c`}TαT.39ra\u000eTc\nSQ'wXwX*ZRA\u001fTRi\u001fiWB\u000ebwps\u0004Ux[wڮ\u00010%JG\u0013\u0010.R\u0017FG\u001a\u001fnwTRO\t,\u0018(ǩ\"*\u0016Ö_ƥ#HW5k&\u001fT\u0000\u00129)sHb`\u0004K\u0016C.KT.KT.KT.KT.K\u0007o;H>\nUfvgTbⲄv|<ӶI\u001e_ze1K\u001eaɕ\u0003J90ϊ@\bC\u0001~J0\u0005Љ\u0013\u001d2\u0015Q+VC2\u0011Wg\"\u001c؏J7B\u0012<-\u000f08=j\u001a\u0015k;JPIz\n\u0004`\u0019r\u0018Ԩq\u0011HIJ\u0016?r$$=%uΜ$e\u001cTX*\u0007\t A%)t\u0014\u0002CG\t\u0006\u0004<>\t*IOA8KPIz\nkQJS\u0012T\u001c&\u0007؏9KP\u000fx$YN\u001cA]\n*R}]\bԨN~IeJFq\u0014U4w{\u0003xwqC38M7Ic{\u0000+cu\u0015j,ү\\-h\u001f\u0007_\u00002kBC.!\"\u0013SI\u0004E\u00170\u0014оح\u0014\u001dV'~r\t*r\t*r\t*r\t*\u0004'0\u0007̟[\u0003Tk\f\u001a<d%%'/\u001dZa#i=LjV\u001fQ47^Z[;p\u0000A~J0%bX\u0000S\u0018_\u000bL:Uf\u0003Տ{mS|_,Lj'J\u0016g/.r\u000b\\0)\u0017L`\u0005S.`lt\u0016:g#\u0007}Z\u000b\u001fHGmz\u001epXgx\u0002\u0016{qRҸQA'\u001f߀O\u00053l9\u0011x0e~F,q\u0003^BihBW\f\u0005\u0015N\tEpT7\\L\u0007iA>\u0006G`@\u0002Ge>@O⨈uK(6)aSZpv?5\t_953<ͩ95IS\"4)iqJ6ũ\u0011-lNIS2\u0015'mN#lNI`4\u0017u攴8e\u0019rYS\u0012x|\u000eۜ\u0016`w\u00149ksJT9%-Ny|\u000eۜa\u001eFdlN=\b\u0007؜Bm\\\nڜ21`?.ۜ\u0016i,iPvct6ZɎ/dOtY\u00047l&x!衫\u001ej\u001d\u0012.Wn'\u0000w\u0000F-[]nst~)12s\u0006tT\fnj_\u000bFm<\u0000n}l_*-\u000f\b\"\u0000{R 0,Nэ'c]\u0014\tȹ\u0016\\S)kqʵ8Zr-N\u0016ũ-}\u001fq<\u0012bD\u0014V\u000f2}!8^=s#jj;kWQ\rX&\u0013\u0019<V۷\u000b?? '\u0016˫\u000f8%>#A`\u0018&\f\u0014@|:\u0017PbF0R[\u001f\b$\"Grs`9}\\N\\N\\N\\N$'u\u001e*+A\"Z}ko\u0006{zG葋++7HTW[tBxo\u0000q^\u001e77\u001e\u001fn\u000b>|#J(gÎ\u0003\u0014w\nF3\f7/ԕ\u0010GU\u0006;\u0015U\u0018\u000fn\u0018\u0000\u0016^I\u0015/\u000f\u0019`2j=/ᯢ\f|ɨ!*߇\u0004Dۑ3SIV\u0018\u0015Ax!\u0016u9.S\u001b>\u000bEB\u0010s!>8K(\u0016Y|5\u0006\tf]mh\\g]LTL3\u0004fQ̽|3.pԜW|fVfAd6K\u0017Y|5\u0004*SJUW\u0011h̭\u001dƧ>pn\u0012jn,g8KOV@o`ʭ|֬T1-\u0002\\ZcZ>p̎\u000fa:\u000b3z&f}'sk`3+X\u001aơ\u001a]iƴYv\tecYn'1\rg<JdJr0Vd9ͭ\u00142v>ͭQ[\b7M$S\u0005:\u0015ߴg\u0012/<Y%wjX\\\u0011Y\\|#Y#Vj2FdEiӏ9\u000f'\r\u001b>蒩΂cgybG\u0010[s8\u0016P8_80!\u00144=\u001e/\u0018\tW\u0015\u001b}@-\u001ba.WȾ\nJǿ3\u001fo#0Q\\|\u0013ʚ\u001e=\u001a\"SVe~\u0003h0MΈV\\8vUlnҨ].\u001e/\u0018Ӓ.Ǔ=ħ)ija\u001c\u0007\u0015ôr\\\u001a,\u0019s[˞9诘\u00051(V\u001cE\"T}o8[><\u001fCtt5f\u001cOVFp2n\u0006V/\u001e#\u001efIwR\u001d\u001b6\bX.dV+@@MM\u0010\f\u0004@1\u0006qy\u0012]\u000bt-DC\u000f^kE[9\\WW\u001a\u0018\u0002[UX=W*N\u001dE</EWLMV\u000e\u000b\u0002̳\u0003_C}b?K\u00067Rdo=<%V\\ݗC/)u7I}C\u001f\u001b쾐\u001aD\t:\u001a<'vi}OwZ|Uz1bݪO3mG17;\u00187 \u0001j.KF\u0019\u001f\u000f6\u001fl?<_\u0001\u001cI9)Y2N\\K\u0019X.o3}`\tRy\u0007wKۡ:\u001b*ǪlR@r,,*\r<\u000ekbfU|W\u0017%\u0013؍D\u001f]OH|7h3uZH\u00193=liP\u001dv~#\u0000\u0000I>\u001aA4\u001bq<(^u3U\u001d\u001dD&\u0013,C\u001eD͏`0\b_q\"\u001cI?Q0@\u0004ftԆ0!\n:ͼ\nK8nA`\u001c\u0018z&\\\u0007\u0010ًJ}V/C-Vǋ%/\u001a\u0002*w\u0002}\u0018p\u000eB&\bO\u0005!l\r1?-s~Z6h~̑\rbY\u000e\u001f ڷFT\u001e֬Eѻ#w:ܚ!\u0002\u0019۲bL/b4,\u0019z0\faɆZ8bö!wV'Rc\t:n\u001dE;A@,s\u0018\u001bǪV9\u000b]!dZ]\u0000V;w$I\nvmپݬ\nnbsj\u001f/Al}M@H\u001fJ,\u0006v-\u001c/[\u000blNÆ0K::Rwscz?\\\u0007\u001f\u000f\\!{8_\u001a,~l\u001bD\u001eBט\\/CSŤ#O\u0007dH\u001ah\u00163\u001e\\\u0018\u000beZ>IGm\u001cmgH%\u0012#B,)f\t=2\u0015z9oF\u0011׽o$_<K\u001f\\aҦ'ڼ\u0011ZkFq\u0005\u0001t+\r\u001d7J\f\u0011\n,LuϿ<LH$^o\u000f{L\bR\u0019=J׵zH%\u0007F1\tS\u0019\u0007mz{T`\u0015íy(i]ZG$ |\u001f\u0017p\u0003r\u000fW\f4\u0012a~\tz(\b\u0015=\u001bg7s'gRއf{Dc5&\fxnAtq~L=mRz&S\u000f^oن@{ǒ\u0006ɗ|y\b_F:}ƒ]\u000e{hKo.\\CZ`=sOmʋWfǅŽynF\u0017>\u0006dc\tӂJv\u0013&DPK6\u00066tg`e\u0012{هm؈nmǇ\u001dK\u0006Q.\u0002F`Id\u00027rxZmK~;1]D\n2|\u0016^I1<R\u001e\u0006RSȢ;?\f[<.m߱\u0012M.i5mlow-z\u000e(MGURyϙB\u0003\u0005~Ms]m7_ړW>:4S\nfiuy|B/\u0011\u001fD_\u001e\u0019P$hƹt1[`<\"\u000ba%\u001f~S{!:UTB\u001cDQ]Sn/\u0006`\u0010\ty-\u0001\b\u0010լᶧ\u0018DmSbG^ v9B\u000b\r7&Xo3\u0017oݠ|x9)w\u0003 ]8#w7܍\u0014 \u0019\u000eDn\u001cۯpRf&\r\"َH\u0001wX\u0006S0nd\u001f[\u001c&I\u001bK9,w3\u0005x|l\r\u000f\u000eݠ̿\u00045x|\u0017N6\u001a%o\u001c䍣r7=ݾ#nLsMkKSA0\u0006K+_\f|\u000e\u0007+L\nK><\u0000bݐFuZm=K\u0001t+$x\u00048\u000eXj#3\u0016\u00120x\\z_!C/!+-\u000e,1*ڿa1>gya\u0016H\ffB e\\e\\e\\e\\e\\\u0013ţVr+I\u001eeW\tv@\u0003jNh\u001fo:GkZ=߿y]\u001dDmޟau3Lק4\u001c\u0019t@\u0014GmsJ/\u0006HXN56[3 \u0012p,\u0015ew7W''}\u0006qdj4(V\u0011A\u000e3\u0016+\u0007\\[\u000f弎\u001eIl\"e\u001b\u0004f\u0013Ho\\jxܞ[@`M7֢fP2쎌vJ\u0012y=漪\u0013,\t4IC\u000bfm\u0013lǽOqFΣ&\u0006j2zȓ7legX_޶\u000ec^T؆2O\u0014*\u0001r\u0018Iy|}N!\u0016D\u0006B\u001cFR\u00169,,Ga$\u0005uR\u000e#)ܮA8\u0010D\u0001r\u0018I!ٵ\u0002:\r\u0011P9⯡;`_/!$I,0\u00038\u0000vKÜERh\u0007HX9$%a=*1\u000eI`KR\u0001$<'Y\u0006$\u0005k?]$I,\u0013H\n\u0015\u001d\u001cVa\u001bF{~6ܯ꣇K'H\u0015օ4\u001akd\u000f2D5\u0006\u0013| \u000f\nX7\u0014?<G/\fO\t_P\u000f=\u0012\u0000T:241L3M\u0012\u0014%b\u001a\u001cި\\a\u0006+\u0003P}\u000bX*:RNG=3_{\rv[}־G;\u001cz4g)M5LJ\n%K| LP]\u0007Jtn\u0007]3Q\u0013\fR\u000e\u000f}\u000e+\f-UBW*\u0014c\u001e\u0018i\th*̘=yQ5#\\԰\u0018\u0019Gx@Ґ5TT\u0010'\u0001ِL\b\u00018\u0018TA1\u0006MF\u0006pb+\u001a\\\u0011\u0006d\u0013\t\rV\u0004W(\u0015`@\t\u0007\u0015\u0014Ī6Uk\u000e\u000b\f\u001fUQ5\u0006M\u000e\u001e(4\u0015\u0004:&& 1.\u0014NLi\u001ae\ba\u0001z&3B85D=TNdѠM5h\u001djBOL\u0018D&\u0004\u0017*\u0004\u001c\rA-4\u0000S\u0004\u0014\u0013j\tsb\u0010<+0(ju!\u0018$*҆l7\u0015۶,zZ\u000bu\u0013ΩJr49~9N:+۸r>\u0018<\u0007d\u0017Axu\u0002s2\u0015,N\u0005\u0017i\\@w\tAUF`E\u0018 cU]Esͨ^(\u0013o6\u001e1'\u000bj&\u0011g#*7/o&_ˉG\bhDsz',ydk\u001f70\n=됌P\u001eP\u0005\u0006<#J:~J4U\u0002I'T!4Nq\u0019L\u000e\u001f\u001dpE6Uq`\u0002͉o\b\f_j֓s\u0005\u00130UfM(\u0014xk#dL;%`\n\u0018.X|9e\r\u0014P3kiD[ѡ\b\u001d﯀(\rUX40aCa4bz0ݨ&L`8p\u0002D;f\u0006q\n\u0007\u0013\u0006>\r:\u0013ʲ\u0007cZ3\u000e̓\u0014'\u0002c[m$\u0006)SLdz\f/@!4\u001b+0d\u00144}'v|T>7G?͕`R4e=ja3\\\u0019w\u00067\u0010d\u001e<\u000b'l\rendstream\rendobj\r783 0 obj\r<</CreationDate(D:20080601123009-07'00')/Creator(Adobe Illustrator CS3)/ModDate(D:20080718182725-07'00')/Title(Web)>>\rendobj\rxref\r0 789\r0000000003 65535 f\r\n0000000016 00000 n\r\n0000046524 00000 n\r\n0000000004 00000 f\r\n0000000006 00000 f\r\n0000059667 00000 n\r\n0000000007 00000 f\r\n0000000008 00000 f\r\n0000000009 00000 f\r\n0000000010 00000 f\r\n0000000011 00000 f\r\n0000000012 00000 f\r\n0000000013 00000 f\r\n0000000014 00000 f\r\n0000000018 00000 f\r\n0000046575 00000 n\r\n0000059428 00000 n\r\n0000059459 00000 n\r\n0000000019 00000 f\r\n0000000020 00000 f\r\n0000000021 00000 f\r\n0000000022 00000 f\r\n0000000023 00000 f\r\n0000000027 00000 f\r\n0000046646 00000 n\r\n0000059312 00000 n\r\n0000059343 00000 n\r\n0000000031 00000 f\r\n0000046718 00000 n\r\n0000059196 00000 n\r\n0000059227 00000 n\r\n0000000035 00000 f\r\n0000046790 00000 n\r\n0000059080 00000 n\r\n0000059111 00000 n\r\n0000000039 00000 f\r\n0000046861 00000 n\r\n0000058964 00000 n\r\n0000058995 00000 n\r\n0000000043 00000 f\r\n0000046932 00000 n\r\n0000058848 00000 n\r\n0000058879 00000 n\r\n0000000047 00000 f\r\n0000047003 00000 n\r\n0000058732 00000 n\r\n0000058763 00000 n\r\n0000000051 00000 f\r\n0000047074 00000 n\r\n0000058616 00000 n\r\n0000058647 00000 n\r\n0000000055 00000 f\r\n0000047145 00000 n\r\n0000058500 00000 n\r\n0000058531 00000 n\r\n0000000059 00000 f\r\n0000047216 00000 n\r\n0000058384 00000 n\r\n0000058415 00000 n\r\n0000000063 00000 f\r\n0000047287 00000 n\r\n0000058268 00000 n\r\n0000058299 00000 n\r\n0000000067 00000 f\r\n0000047359 00000 n\r\n0000058152 00000 n\r\n0000058183 00000 n\r\n0000000071 00000 f\r\n0000047431 00000 n\r\n0000058036 00000 n\r\n0000058067 00000 n\r\n0000000072 00000 f\r\n0000000073 00000 f\r\n0000000074 00000 f\r\n0000000075 00000 f\r\n0000000076 00000 f\r\n0000000077 00000 f\r\n0000000078 00000 f\r\n0000000079 00000 f\r\n0000000080 00000 f\r\n0000000081 00000 f\r\n0000000082 00000 f\r\n0000000083 00000 f\r\n0000000084 00000 f\r\n0000000085 00000 f\r\n0000000086 00000 f\r\n0000000087 00000 f\r\n0000000088 00000 f\r\n0000000089 00000 f\r\n0000000090 00000 f\r\n0000000091 00000 f\r\n0000000092 00000 f\r\n0000000093 00000 f\r\n0000000094 00000 f\r\n0000000095 00000 f\r\n0000000096 00000 f\r\n0000000097 00000 f\r\n0000000098 00000 f\r\n0000000099 00000 f\r\n0000000100 00000 f\r\n0000000101 00000 f\r\n0000000102 00000 f\r\n0000000103 00000 f\r\n0000000104 00000 f\r\n0000000105 00000 f\r\n0000000106 00000 f\r\n0000000107 00000 f\r\n0000000108 00000 f\r\n0000000109 00000 f\r\n0000000110 00000 f\r\n0000000111 00000 f\r\n0000000112 00000 f\r\n0000000113 00000 f\r\n0000000114 00000 f\r\n0000000115 00000 f\r\n0000000116 00000 f\r\n0000000117 00000 f\r\n0000000118 00000 f\r\n0000000119 00000 f\r\n0000000120 00000 f\r\n0000000121 00000 f\r\n0000000122 00000 f\r\n0000000123 00000 f\r\n0000000124 00000 f\r\n0000000125 00000 f\r\n0000000129 00000 f\r\n0000047503 00000 n\r\n0000057918 00000 n\r\n0000057950 00000 n\r\n0000000130 00000 f\r\n0000000131 00000 f\r\n0000000132 00000 f\r\n0000000133 00000 f\r\n0000000134 00000 f\r\n0000000135 00000 f\r\n0000000136 00000 f\r\n0000000137 00000 f\r\n0000000138 00000 f\r\n0000000139 00000 f\r\n0000000140 00000 f\r\n0000000141 00000 f\r\n0000000142 00000 f\r\n0000000143 00000 f\r\n0000000144 00000 f\r\n0000000145 00000 f\r\n0000000146 00000 f\r\n0000000147 00000 f\r\n0000000148 00000 f\r\n0000000149 00000 f\r\n0000000150 00000 f\r\n0000000151 00000 f\r\n0000000155 00000 f\r\n0000047578 00000 n\r\n0000057800 00000 n\r\n0000057832 00000 n\r\n0000000156 00000 f\r\n0000000157 00000 f\r\n0000000158 00000 f\r\n0000000159 00000 f\r\n0000000160 00000 f\r\n0000000164 00000 f\r\n0000047652 00000 n\r\n0000057682 00000 n\r\n0000057714 00000 n\r\n0000000168 00000 f\r\n0000047727 00000 n\r\n0000057564 00000 n\r\n0000057596 00000 n\r\n0000000172 00000 f\r\n0000047802 00000 n\r\n0000057446 00000 n\r\n0000057478 00000 n\r\n0000000176 00000 f\r\n0000047876 00000 n\r\n0000057328 00000 n\r\n0000057360 00000 n\r\n0000000180 00000 f\r\n0000047950 00000 n\r\n0000057210 00000 n\r\n0000057242 00000 n\r\n0000000184 00000 f\r\n0000048024 00000 n\r\n0000057092 00000 n\r\n0000057124 00000 n\r\n0000000188 00000 f\r\n0000048098 00000 n\r\n0000056974 00000 n\r\n0000057006 00000 n\r\n0000000192 00000 f\r\n0000048172 00000 n\r\n0000056856 00000 n\r\n0000056888 00000 n\r\n0000000196 00000 f\r\n0000048246 00000 n\r\n0000056738 00000 n\r\n0000056770 00000 n\r\n0000000200 00000 f\r\n0000048320 00000 n\r\n0000056620 00000 n\r\n0000056652 00000 n\r\n0000000204 00000 f\r\n0000048395 00000 n\r\n0000056502 00000 n\r\n0000056534 00000 n\r\n0000000208 00000 f\r\n0000048470 00000 n\r\n0000056384 00000 n\r\n0000056416 00000 n\r\n0000000209 00000 f\r\n0000000210 00000 f\r\n0000000211 00000 f\r\n0000000212 00000 f\r\n0000000213 00000 f\r\n0000000214 00000 f\r\n0000000215 00000 f\r\n0000000216 00000 f\r\n0000000217 00000 f\r\n0000000218 00000 f\r\n0000000219 00000 f\r\n0000000220 00000 f\r\n0000000221 00000 f\r\n0000000222 00000 f\r\n0000000223 00000 f\r\n0000000224 00000 f\r\n0000000225 00000 f\r\n0000000226 00000 f\r\n0000000227 00000 f\r\n0000000228 00000 f\r\n0000000229 00000 f\r\n0000000230 00000 f\r\n0000000231 00000 f\r\n0000000232 00000 f\r\n0000000233 00000 f\r\n0000000234 00000 f\r\n0000000235 00000 f\r\n0000000236 00000 f\r\n0000000237 00000 f\r\n0000000238 00000 f\r\n0000000239 00000 f\r\n0000000240 00000 f\r\n0000000241 00000 f\r\n0000000242 00000 f\r\n0000000243 00000 f\r\n0000000244 00000 f\r\n0000000245 00000 f\r\n0000000246 00000 f\r\n0000000247 00000 f\r\n0000000248 00000 f\r\n0000000249 00000 f\r\n0000000250 00000 f\r\n0000000251 00000 f\r\n0000000252 00000 f\r\n0000000253 00000 f\r\n0000000254 00000 f\r\n0000000255 00000 f\r\n0000000256 00000 f\r\n0000000257 00000 f\r\n0000000258 00000 f\r\n0000000259 00000 f\r\n0000000260 00000 f\r\n0000000261 00000 f\r\n0000000262 00000 f\r\n0000000266 00000 f\r\n0000048545 00000 n\r\n0000056266 00000 n\r\n0000056298 00000 n\r\n0000000267 00000 f\r\n0000000268 00000 f\r\n0000000269 00000 f\r\n0000000270 00000 f\r\n0000000271 00000 f\r\n0000000272 00000 f\r\n0000000273 00000 f\r\n0000000274 00000 f\r\n0000000275 00000 f\r\n0000000276 00000 f\r\n0000000277 00000 f\r\n0000000278 00000 f\r\n0000000279 00000 f\r\n0000000280 00000 f\r\n0000000281 00000 f\r\n0000000282 00000 f\r\n0000000283 00000 f\r\n0000000284 00000 f\r\n0000000285 00000 f\r\n0000000286 00000 f\r\n0000000287 00000 f\r\n0000000288 00000 f\r\n0000000292 00000 f\r\n0000048620 00000 n\r\n0000056148 00000 n\r\n0000056180 00000 n\r\n0000000293 00000 f\r\n0000000294 00000 f\r\n0000000295 00000 f\r\n0000000296 00000 f\r\n0000000297 00000 f\r\n0000000301 00000 f\r\n0000048694 00000 n\r\n0000056030 00000 n\r\n0000056062 00000 n\r\n0000000305 00000 f\r\n0000048769 00000 n\r\n0000055912 00000 n\r\n0000055944 00000 n\r\n0000000309 00000 f\r\n0000048844 00000 n\r\n0000055794 00000 n\r\n0000055826 00000 n\r\n0000000313 00000 f\r\n0000048918 00000 n\r\n0000055676 00000 n\r\n0000055708 00000 n\r\n0000000317 00000 f\r\n0000048992 00000 n\r\n0000055558 00000 n\r\n0000055590 00000 n\r\n0000000321 00000 f\r\n0000049066 00000 n\r\n0000055440 00000 n\r\n0000055472 00000 n\r\n0000000325 00000 f\r\n0000049140 00000 n\r\n0000055322 00000 n\r\n0000055354 00000 n\r\n0000000329 00000 f\r\n0000049214 00000 n\r\n0000055204 00000 n\r\n0000055236 00000 n\r\n0000000333 00000 f\r\n0000049288 00000 n\r\n0000055086 00000 n\r\n0000055118 00000 n\r\n0000000337 00000 f\r\n0000049362 00000 n\r\n0000054968 00000 n\r\n0000055000 00000 n\r\n0000000341 00000 f\r\n0000049437 00000 n\r\n0000054850 00000 n\r\n0000054882 00000 n\r\n0000000345 00000 f\r\n0000049512 00000 n\r\n0000054732 00000 n\r\n0000054764 00000 n\r\n0000000346 00000 f\r\n0000000347 00000 f\r\n0000000348 00000 f\r\n0000000349 00000 f\r\n0000000350 00000 f\r\n0000000351 00000 f\r\n0000000352 00000 f\r\n0000000353 00000 f\r\n0000000354 00000 f\r\n0000000355 00000 f\r\n0000000356 00000 f\r\n0000000357 00000 f\r\n0000000358 00000 f\r\n0000000359 00000 f\r\n0000000360 00000 f\r\n0000000361 00000 f\r\n0000000362 00000 f\r\n0000000363 00000 f\r\n0000000364 00000 f\r\n0000000365 00000 f\r\n0000000366 00000 f\r\n0000000367 00000 f\r\n0000000368 00000 f\r\n0000000369 00000 f\r\n0000000370 00000 f\r\n0000000371 00000 f\r\n0000000372 00000 f\r\n0000000373 00000 f\r\n0000000374 00000 f\r\n0000000375 00000 f\r\n0000000376 00000 f\r\n0000000377 00000 f\r\n0000000378 00000 f\r\n0000000379 00000 f\r\n0000000380 00000 f\r\n0000000381 00000 f\r\n0000000382 00000 f\r\n0000000383 00000 f\r\n0000000384 00000 f\r\n0000000385 00000 f\r\n0000000386 00000 f\r\n0000000387 00000 f\r\n0000000388 00000 f\r\n0000000389 00000 f\r\n0000000390 00000 f\r\n0000000391 00000 f\r\n0000000392 00000 f\r\n0000000393 00000 f\r\n0000000394 00000 f\r\n0000000395 00000 f\r\n0000000396 00000 f\r\n0000000397 00000 f\r\n0000000398 00000 f\r\n0000000399 00000 f\r\n0000000403 00000 f\r\n0000049587 00000 n\r\n0000054614 00000 n\r\n0000054646 00000 n\r\n0000000404 00000 f\r\n0000000405 00000 f\r\n0000000406 00000 f\r\n0000000407 00000 f\r\n0000000408 00000 f\r\n0000000409 00000 f\r\n0000000410 00000 f\r\n0000000411 00000 f\r\n0000000412 00000 f\r\n0000000413 00000 f\r\n0000000414 00000 f\r\n0000000415 00000 f\r\n0000000416 00000 f\r\n0000000417 00000 f\r\n0000000418 00000 f\r\n0000000419 00000 f\r\n0000000420 00000 f\r\n0000000421 00000 f\r\n0000000422 00000 f\r\n0000000423 00000 f\r\n0000000424 00000 f\r\n0000000428 00001 f\r\n0000049662 00000 n\r\n0000054496 00000 n\r\n0000054528 00000 n\r\n0000000432 00000 f\r\n0000049734 00000 n\r\n0000054378 00000 n\r\n0000054410 00000 n\r\n0000000436 00000 f\r\n0000049811 00000 n\r\n0000054260 00000 n\r\n0000054292 00000 n\r\n0000000440 00000 f\r\n0000049880 00000 n\r\n0000054142 00000 n\r\n0000054174 00000 n\r\n0000000444 00000 f\r\n0000049949 00000 n\r\n0000054024 00000 n\r\n0000054056 00000 n\r\n0000000448 00000 f\r\n0000050018 00000 n\r\n0000053906 00000 n\r\n0000053938 00000 n\r\n0000000452 00000 f\r\n0000050087 00000 n\r\n0000053788 00000 n\r\n0000053820 00000 n\r\n0000000456 00000 f\r\n0000050156 00000 n\r\n0000053670 00000 n\r\n0000053702 00000 n\r\n0000000460 00000 f\r\n0000050225 00000 n\r\n0000053552 00000 n\r\n0000053584 00000 n\r\n0000000464 00000 f\r\n0000050294 00000 n\r\n0000053434 00000 n\r\n0000053466 00000 n\r\n0000000468 00000 f\r\n0000050363 00000 n\r\n0000053316 00000 n\r\n0000053348 00000 n\r\n0000000472 00000 f\r\n0000050436 00000 n\r\n0000053198 00000 n\r\n0000053230 00000 n\r\n0000000473 00000 f\r\n0000000474 00000 f\r\n0000000475 00000 f\r\n0000000476 00000 f\r\n0000000477 00000 f\r\n0000000478 00000 f\r\n0000000479 00000 f\r\n0000000480 00000 f\r\n0000000481 00000 f\r\n0000000482 00000 f\r\n0000000483 00000 f\r\n0000000484 00000 f\r\n0000000485 00000 f\r\n0000000486 00000 f\r\n0000000487 00000 f\r\n0000000488 00000 f\r\n0000000489 00000 f\r\n0000000490 00000 f\r\n0000000491 00000 f\r\n0000000492 00000 f\r\n0000000493 00000 f\r\n0000000494 00000 f\r\n0000000495 00000 f\r\n0000000496 00000 f\r\n0000000497 00000 f\r\n0000000498 00000 f\r\n0000000499 00000 f\r\n0000000500 00000 f\r\n0000000501 00000 f\r\n0000000502 00000 f\r\n0000000503 00000 f\r\n0000000504 00000 f\r\n0000000505 00000 f\r\n0000000506 00000 f\r\n0000000507 00000 f\r\n0000000508 00000 f\r\n0000000509 00000 f\r\n0000000510 00000 f\r\n0000000511 00000 f\r\n0000000512 00000 f\r\n0000000513 00000 f\r\n0000000514 00000 f\r\n0000000515 00000 f\r\n0000000516 00000 f\r\n0000000517 00000 f\r\n0000000518 00000 f\r\n0000000519 00000 f\r\n0000000520 00000 f\r\n0000000521 00000 f\r\n0000000522 00000 f\r\n0000000523 00000 f\r\n0000000524 00000 f\r\n0000000525 00000 f\r\n0000000526 00000 f\r\n0000000527 00000 f\r\n0000000528 00000 f\r\n0000000529 00000 f\r\n0000000530 00000 f\r\n0000000531 00000 f\r\n0000000532 00000 f\r\n0000000533 00000 f\r\n0000000534 00000 f\r\n0000000535 00000 f\r\n0000000536 00000 f\r\n0000000537 00000 f\r\n0000000538 00000 f\r\n0000000539 00000 f\r\n0000000540 00000 f\r\n0000000541 00000 f\r\n0000000542 00000 f\r\n0000000543 00000 f\r\n0000000544 00000 f\r\n0000000545 00000 f\r\n0000000546 00000 f\r\n0000000547 00000 f\r\n0000000548 00000 f\r\n0000000549 00000 f\r\n0000000550 00000 f\r\n0000000551 00000 f\r\n0000000552 00000 f\r\n0000000553 00000 f\r\n0000000554 00000 f\r\n0000000555 00000 f\r\n0000000556 00000 f\r\n0000000557 00000 f\r\n0000000558 00000 f\r\n0000000559 00000 f\r\n0000000560 00000 f\r\n0000000561 00000 f\r\n0000000562 00000 f\r\n0000000563 00000 f\r\n0000000564 00000 f\r\n0000000565 00000 f\r\n0000000566 00000 f\r\n0000000567 00000 f\r\n0000000568 00000 f\r\n0000000569 00000 f\r\n0000000570 00000 f\r\n0000000571 00000 f\r\n0000000572 00000 f\r\n0000000573 00000 f\r\n0000000574 00000 f\r\n0000000575 00000 f\r\n0000000576 00000 f\r\n0000000577 00000 f\r\n0000000578 00000 f\r\n0000000579 00000 f\r\n0000000583 00000 f\r\n0000050521 00000 n\r\n0000053080 00000 n\r\n0000053112 00000 n\r\n0000000584 00000 f\r\n0000000585 00000 f\r\n0000000586 00000 f\r\n0000000587 00000 f\r\n0000000588 00000 f\r\n0000000589 00000 f\r\n0000000590 00000 f\r\n0000000591 00000 f\r\n0000000592 00000 f\r\n0000000593 00000 f\r\n0000000594 00000 f\r\n0000000595 00000 f\r\n0000000596 00000 f\r\n0000000597 00000 f\r\n0000000598 00001 f\r\n0000000599 00000 f\r\n0000000600 00000 f\r\n0000000601 00000 f\r\n0000000602 00000 f\r\n0000000609 00000 f\r\n0000074725 00000 n\r\n0000074801 00000 n\r\n0000075002 00000 n\r\n0000075965 00000 n\r\n0000085088 00000 n\r\n0000150677 00000 n\r\n0000000618 00001 f\r\n0000059544 00000 n\r\n0000050604 00000 n\r\n0000052962 00000 n\r\n0000052994 00000 n\r\n0000068138 00000 n\r\n0000050676 00000 n\r\n0000052844 00000 n\r\n0000052876 00000 n\r\n0000000622 00001 f\r\n0000050753 00000 n\r\n0000052726 00000 n\r\n0000052758 00000 n\r\n0000000626 00001 f\r\n0000050822 00000 n\r\n0000052608 00000 n\r\n0000052640 00000 n\r\n0000000630 00001 f\r\n0000050891 00000 n\r\n0000052490 00000 n\r\n0000052522 00000 n\r\n0000000634 00001 f\r\n0000050960 00000 n\r\n0000052372 00000 n\r\n0000052404 00000 n\r\n0000000638 00001 f\r\n0000051029 00000 n\r\n0000052254 00000 n\r\n0000052286 00000 n\r\n0000000642 00001 f\r\n0000051098 00000 n\r\n0000052136 00000 n\r\n0000052168 00000 n\r\n0000000646 00001 f\r\n0000051167 00000 n\r\n0000052018 00000 n\r\n0000052050 00000 n\r\n0000000650 00001 f\r\n0000051236 00000 n\r\n0000051900 00000 n\r\n0000051932 00000 n\r\n0000000654 00001 f\r\n0000051305 00000 n\r\n0000051782 00000 n\r\n0000051814 00000 n\r\n0000000658 00001 f\r\n0000051378 00000 n\r\n0000051664 00000 n\r\n0000051696 00000 n\r\n0000000659 00001 f\r\n0000000660 00001 f\r\n0000000661 00001 f\r\n0000000662 00001 f\r\n0000000663 00001 f\r\n0000000664 00001 f\r\n0000000665 00001 f\r\n0000000666 00001 f\r\n0000000667 00001 f\r\n0000000668 00001 f\r\n0000000669 00001 f\r\n0000000670 00001 f\r\n0000000671 00001 f\r\n0000000672 00001 f\r\n0000000673 00001 f\r\n0000000674 00001 f\r\n0000000675 00001 f\r\n0000000676 00001 f\r\n0000000677 00001 f\r\n0000000678 00001 f\r\n0000000679 00001 f\r\n0000000680 00001 f\r\n0000000681 00001 f\r\n0000000682 00001 f\r\n0000000683 00001 f\r\n0000000684 00001 f\r\n0000000685 00001 f\r\n0000000686 00001 f\r\n0000000687 00001 f\r\n0000000688 00001 f\r\n0000000689 00001 f\r\n0000000690 00001 f\r\n0000000691 00001 f\r\n0000000692 00001 f\r\n0000000693 00001 f\r\n0000000694 00001 f\r\n0000000695 00001 f\r\n0000000696 00001 f\r\n0000000697 00001 f\r\n0000000698 00001 f\r\n0000000699 00001 f\r\n0000000700 00001 f\r\n0000000701 00001 f\r\n0000000702 00001 f\r\n0000000703 00001 f\r\n0000000704 00001 f\r\n0000000705 00001 f\r\n0000000706 00001 f\r\n0000000707 00001 f\r\n0000000708 00001 f\r\n0000000709 00001 f\r\n0000000710 00001 f\r\n0000000711 00001 f\r\n0000000712 00001 f\r\n0000000713 00001 f\r\n0000000714 00001 f\r\n0000000715 00001 f\r\n0000000716 00001 f\r\n0000000717 00001 f\r\n0000000718 00001 f\r\n0000000719 00001 f\r\n0000000720 00001 f\r\n0000000721 00001 f\r\n0000000722 00001 f\r\n0000000723 00001 f\r\n0000000724 00001 f\r\n0000000725 00001 f\r\n0000000726 00001 f\r\n0000000727 00001 f\r\n0000000728 00001 f\r\n0000000729 00001 f\r\n0000000730 00001 f\r\n0000000731 00001 f\r\n0000000732 00001 f\r\n0000000733 00001 f\r\n0000000734 00001 f\r\n0000000735 00001 f\r\n0000000736 00001 f\r\n0000000737 00001 f\r\n0000000738 00001 f\r\n0000000739 00001 f\r\n0000000740 00001 f\r\n0000000741 00001 f\r\n0000000742 00001 f\r\n0000000743 00001 f\r\n0000000744 00001 f\r\n0000000745 00001 f\r\n0000000746 00001 f\r\n0000000747 00001 f\r\n0000000748 00001 f\r\n0000000749 00001 f\r\n0000000750 00001 f\r\n0000000751 00001 f\r\n0000000752 00001 f\r\n0000000753 00001 f\r\n0000000754 00001 f\r\n0000000755 00001 f\r\n0000000756 00001 f\r\n0000000757 00001 f\r\n0000000758 00001 f\r\n0000000759 00001 f\r\n0000000760 00001 f\r\n0000000761 00001 f\r\n0000000762 00001 f\r\n0000000763 00001 f\r\n0000000764 00001 f\r\n0000000765 00001 f\r\n0000000769 00001 f\r\n0000051463 00000 n\r\n0000051546 00000 n\r\n0000051578 00000 n\r\n0000000770 00001 f\r\n0000000771 00001 f\r\n0000000772 00001 f\r\n0000000773 00001 f\r\n0000000774 00001 f\r\n0000000775 00001 f\r\n0000000776 00001 f\r\n0000000777 00001 f\r\n0000000000 00001 f\r\n0000071475 00000 n\r\n0000071512 00000 n\r\n0000068252 00000 n\r\n0000068648 00000 n\r\n0000060267 00000 n\r\n0000197228 00000 n\r\n0000068910 00000 n\r\n0000074161 00000 n\r\n0000074211 00000 n\r\n0000067924 00000 n\r\n0000001203 00000 n\r\ntrailer\r<</Size 789/Root 1 0 R/Info 783 0 R/ID[<E16AFFFAB5D043639E40977A665C544A><218D9257ADCA41849C96DA42A790832E>]>>\rstartxref\r197363\r%%EOF\r"
  },
  {
    "path": "pylons/docs/en/_oldtemplates/genindex.html",
    "content": "{% extends \"layout.html\" %}\n{% set title = _('Index') %}\n{% block body %}\n\n   <h1 id=\"index\">{{ _('Index') }}</h1>\n\n   {% for key, dummy in genindexentries -%}\n   <a href=\"#{{ key }}\"><strong>{{ key }}</strong></a> {% if not loop.last %}| {% endif %}\n   {%- endfor %}\n\n   <hr />\n\n   {% for key, entries in genindexentries %}\n<h2 id=\"{{ key }}\">{{ key }}</h2>\n<table width=\"100%\" class=\"indextable\"><tr><td width=\"33%\" valign=\"top\">\n<dl>\n{%- set breakat = genindexcounts[loop.index0] // 2 %}\n{%- set numcols = 1 %}\n{%- set numitems = 0 %}\n{% for entryname, (links, subitems) in entries %}\n<dt>{%- if links -%}<a href=\"{{ links[0] }}\">{{ entryname|e }}</a>\n  {%- for link in links[1:] %}, <a href=\"{{ link }}\">[{{ loop.index }}]</a>{% endfor -%}\n  {%- else -%}\n{{ entryname|e }}\n  {%- endif -%}</dt>\n  {%- if subitems %}\n  <dd><dl>\n    {%- for subentryname, subentrylinks in subitems %}\n    <dt><a href=\"{{ subentrylinks[0] }}\">{{ subentryname|e }}</a>\n    {%- for link in subentrylinks[1:] %}, <a href=\"{{ link }}\">[{{ loop.index }}]</a>{% endfor -%}\n    </dt>\n    {%- endfor %}\n  </dl></dd>\n  {%- endif -%}\n{%- set numitems = numitems + 1 + (subitems|length) -%}\n{%- if numcols < 2 and numitems > breakat -%}\n{%- set numcols = numcols+1 -%}\n</dl></td><td width=\"33%\" valign=\"top\"><dl>\n{%- endif -%}\n{%- endfor %}\n</dl></td></tr></table>\n{% endfor %}\n\n{% endblock %}\n\n{% block sidebarrel %}\n{% if split_index %}\n   <h4>{{ _('Index') }}</h4>\n   <p>{% for key, dummy in genindexentries -%}\n   <a href=\"{{ pathto('genindex-' + key) }}\"><strong>{{ key }}</strong></a>\n     {% if not loop.last %}| {% endif %}\n   {%- endfor %}</p>\n\n   <p><a href=\"{{ pathto('genindex-all') }}\"><strong>{{ _('Full index on one page') }}</strong></a></p>\n{% endif %}\n   {{ super() }}\n{% endblock %}\n"
  },
  {
    "path": "pylons/docs/en/_oldtemplates/layout.html",
    "content": "{%- block doctype -%}\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n{%- endblock %}\n{%- set reldelim1 = reldelim1 is not defined and ' &raquo;' or reldelim1 %}\n{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}\n{%- macro relbar() %}\n    <div class=\"related\">\n      <h3>{{ _('Navigation') }}</h3>\n      <ul>\n        {%- for rellink in rellinks %}\n        <li class=\"right\" {% if loop.first %}style=\"margin-right: 10px\"{% endif %}>\n          <a href=\"{{ pathto(rellink[0]) }}\" title=\"{{ rellink[1]|striptags }}\"\n             accesskey=\"{{ rellink[2] }}\">{{ rellink[3] }}</a>\n          {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>\n        {%- endfor %}\n        {%- block rootrellink %}\n        <li><a href=\"{{ pathto('index') }}\">{{ shorttitle }}</a>{{ reldelim1 }}</li>\n        {%- endblock %}\n        {%- for parent in parents %}\n          <li><a href=\"{{ parent.link|e }}\" accesskey=\"U\">{{ parent.title }}</a>{{ reldelim1 }}</li>\n        {%- endfor %}\n        {%- block relbaritems %}{% endblock %}\n      </ul>\n    </div>\n{%- endmacro %}\n{%- macro sidebar() %}\n      {%- if builder != 'htmlhelp' %}\n      <div class=\"sphinxsidebar\">\n        <div class=\"sphinxsidebarwrapper\">\n          {%- block sidebarlogo %}\n          {%- if logo %}\n            <p class=\"logo\"><a href=\"{{ pathto(master_doc) }}\">\n              <img class=\"logo\" src=\"{{ pathto('_static/' + logo, 1) }}\" alt=\"Logo\"/>\n            </a></p>\n          {%- endif %}\n          {%- endblock %}\n          {%- block sidebartoc %}\n          {%- if display_toc %}\n            <h3><a href=\"{{ pathto(master_doc) }}\">{{ _('Table Of Contents') }}</a></h3>\n            {{ toc }}\n          {%- endif %}\n          {%- endblock %}\n          {%- block sidebarrel %}\n          {%- if prev %}\n            <h4>{{ _('Previous topic') }}</h4>\n            <p class=\"topless\"><a href=\"{{ prev.link|e }}\" title=\"{{ _('previous chapter') }}\">{{ prev.title }}</a></p>\n          {%- endif %}\n          {%- if next %}\n            <h4>{{ _('Next topic') }}</h4>\n            <p class=\"topless\"><a href=\"{{ next.link|e }}\" title=\"{{ _('next chapter') }}\">{{ next.title }}</a></p>\n          {%- endif %}\n          {%- endblock %}\n          {%- if sourcename %}\n            <h3>{{ _('This Page') }}</h3>\n            <ul class=\"this-page-menu\">\n            {%- if builder == 'web' %}\n              <li><a href=\"#comments\">Comments ({{ comments|length }} so far)</a></li>\n              <li><a href=\"{{ pathto('@edit/' + sourcename)|e }}\">{{ _('Suggest Change') }}</a></li>\n              <li><a href=\"{{ pathto('@source/' + sourcename)|e }}\">{{ _('Show Source') }}</a></li>\n            {%- elif builder == 'html' %}\n              <li><a href=\"{{ pathto('_sources/' + sourcename, true)|e }}\">{{ _('Show Source') }}</a></li>\n            {%- endif %}\n            </ul>\n          {%- endif %}\n          {%- if customsidebar %}\n          {{ rendertemplate(customsidebar) }}\n          {%- endif %}\n          {%- block sidebarsearch %}\n          {%- if pagename != \"search\" %}\n          <h3>{% if builder == 'web' %}{{ _('Keyword search')}}{% else %}{{ _('Quick search') }}{% endif %}</h3>\n            <form class=\"search\" action=\"{{ pathto('search') }}\" method=\"get\">\n              <input type=\"text\" name=\"q\" size=\"18\" /> <input type=\"submit\" value=\"{{ _('Go') }}\" />\n              <input type=\"hidden\" name=\"check_keywords\" value=\"yes\" />\n              <input type=\"hidden\" name=\"area\" value=\"default\" />\n            </form>\n            {%- if builder == 'web' %}\n            <p style=\"font-size: 90%\">{{ _('Enter a module, class or function name.') }}</p>\n            {%- endif %}\n          {%- endif %}\n          {%- endblock %}\n        </div>\n      </div>\n      {%- endif %}\n{%- endmacro -%}\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n  <head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n    {%- if builder != 'htmlhelp' %}\n      {%- set titlesuffix = \" &mdash; \" + docstitle %}\n    {%- endif %}\n    <title>{{ title|striptags }}{{ titlesuffix }}</title>\n    {%- if builder == 'web' %}\n    <link rel=\"stylesheet\" href=\"{{ pathto('index') }}?do=stylesheet{%\n      if in_admin_panel %}&admin=yes{% endif %}\" type=\"text/css\" />\n    {%- for link, type, title in page_links %}\n    <link rel=\"alternate\" type=\"{{ type|e(true) }}\" title=\"{{ title|e(true) }}\" href=\"{{ link|e(true) }}\" />\n    {%- endfor %}\n    {%- else %}\n    <link rel=\"stylesheet\" href=\"{{ pathto('_static/' + style, 1) }}\" type=\"text/css\" />\n    <link rel=\"stylesheet\" href=\"{{ pathto('_static/pygments.css', 1) }}\" type=\"text/css\" />\n    {%- endif %}\n    {%- if builder != 'htmlhelp' %}\n    <script type=\"text/javascript\">\n      var DOCUMENTATION_OPTIONS = {\n          URL_ROOT:    '{{ pathto(\"\", 1) }}',\n          VERSION:     '{{ release }}',\n          COLLAPSE_MODINDEX: false,\n          FILE_SUFFIX: '{{ file_suffix }}'\n      };\n    </script>\n    {%- for scriptfile in script_files %}\n    <script type=\"text/javascript\" src=\"{{ pathto(scriptfile, 1) }}\"></script>\n    {%- endfor %}\n    {%- if use_opensearch %}\n    <link rel=\"search\" type=\"application/opensearchdescription+xml\"\n          title=\"{% trans docstitle=docstitle%}Search within {{ docstitle }}{% endtrans %}\"\n          href=\"{{ pathto('_static/opensearch.xml', 1) }}\"/>\n    {%- endif %}\n    {%- if favicon %}\n    <link rel=\"shortcut icon\" href=\"{{ pathto('_static/' + favicon, 1) }}\"/>\n    {%- endif %}\n    {%- endif %}\n{%- block rellinks %}\n    {%- if hasdoc('about') %}\n    <link rel=\"author\" title=\"{{ _('About these documents') }}\" href=\"{{ pathto('about') }}\" />\n    {%- endif %}\n    <link rel=\"contents\" title=\"{{ _('Global table of contents') }}\" href=\"{{ pathto('contents') }}\" />\n    <link rel=\"index\" title=\"{{ _('Global index') }}\" href=\"{{ pathto('genindex') }}\" />\n    <link rel=\"search\" title=\"{{ _('Search') }}\" href=\"{{ pathto('search') }}\" />\n    {%- if hasdoc('copyright') %}\n    <link rel=\"copyright\" title=\"{{ _('Copyright') }}\" href=\"{{ pathto('copyright') }}\" />\n    {%- endif %}\n    <link rel=\"top\" title=\"{{ docstitle }}\" href=\"{{ pathto('index') }}\" />\n    {%- if parents %}\n    <link rel=\"up\" title=\"{{ parents[-1].title|striptags }}\" href=\"{{ parents[-1].link|e }}\" />\n    {%- endif %}\n    {%- if next %}\n    <link rel=\"next\" title=\"{{ next.title|striptags }}\" href=\"{{ next.link|e }}\" />\n    {%- endif %}\n    {%- if prev %}\n    <link rel=\"prev\" title=\"{{ prev.title|striptags }}\" href=\"{{ prev.link|e }}\" />\n    {%- endif %}\n{%- endblock %}\n{%- block extrahead %}{% endblock %}\n  </head>\n  <body>\n\n{%- block relbar1 %}{{ relbar() }}{% endblock %}\n\n{%- block sidebar1 %}{# possible location for sidebar #}{% endblock %}\n\n{%- block document %}\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n      {%- if builder != 'htmlhelp' %}\n        <div class=\"bodywrapper\">\n      {%- endif %}\n          <div class=\"body\">\n            {% block body %}{% endblock %}\n          </div>\n      {%- if builder != 'htmlhelp' %}\n        </div>\n      {%- endif %}\n      </div>\n{%- endblock %}\n\n{%- block sidebar2 %}{{ sidebar() }}{% endblock %}\n      <div class=\"clearer\"></div>\n    </div>\n\n{%- block relbar2 %}{{ relbar() }}{% endblock %}\n\n{%- block footer %}\n    <div class=\"footer\">\n    {%- if hasdoc('copyright') %}\n      {% trans path=pathto('copyright'), copyright=copyright %}&copy; <a href=\"{{ path }}\">Copyright</a> {{ copyright }}.{% endtrans %}\n    {%- else %}\n      {% trans copyright=copyright %}&copy; Copyright {{ copyright }}.{% endtrans %}\n    {%- endif %}\n    {%- if last_updated %}\n      {% trans last_updated %}Last updated on {{ last_updated }}.{% endtrans %}\n    {%- endif %}\n    {%- if show_sphinx %}\n      {% trans sphinx_version=sphinx_version %}Created using <a href=\"http://sphinx.pocoo.org/\">Sphinx</a> {{ sphinx_version }}.{% endtrans %}\n    {%- endif %}\n    </div>\n{%- endblock %}\n  </body>\n</html>\n"
  },
  {
    "path": "pylons/docs/en/_oldtemplates/modindex.html",
    "content": "{% extends \"layout.html\" %}\n{% set title = _('Global Module Index') %}\n{% block extrahead %}\n{{ super() }}\n{% if builder != 'htmlhelp' and collapse_modindex %}\n    <script type=\"text/javascript\">\n      DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX = true;\n    </script>\n{% endif %}\n{% endblock %}\n{% block body %}\n\n   <h1 id=\"global-module-index\">{{ _('Global Module Index') }}</h1>\n{% if builder == 'web' and freqentries %}\n   <p>{{ _('Most popular modules:') }}</p>\n   <div class=\"modulecloud\">\n   {%- for module in freqentries %}\n     <a href=\"../q/{{ module.name|e }}/\" style=\"font-size: {{ module.size }}%\">{{ module.name|e }}</a>\n   {%- endfor %}\n   </div>\n{% endif %}\n{% if builder == 'web' %}\n   <form class=\"pfform\" action=\"\" method=\"get\">\n     {{ _('Show modules only available on these platforms') }}:<br>\n     {% for pl in platforms -%}\n     <input type=\"checkbox\" name=\"pf\" value=\"{{ pl }}\" id=\"pl-{{ pl }}\"\n            {%- if pl in showpf %} checked=\"checked\"{% endif %}>\n     <label for=\"pl-{{ pl }}\">{{ pl }}</label>\n     {% endfor %}\n     <input type=\"hidden\" name=\"newpf\" value=\"true\">\n     <input type=\"submit\" value=\"Apply\">\n   </form>\n{% endif %}\n\n   {%- for letter in letters %}\n   <a href=\"#cap-{{ letter }}\"><strong>{{ letter }}</strong></a> {% if not loop.last %}| {% endif %}\n   {%- endfor %}\n   <hr/>\n\n   <table width=\"100%\" class=\"indextable\" cellspacing=\"0\" cellpadding=\"2\">\n   {%- for modname, collapse, cgroup, indent, fname, synops, pform, dep, stripped in modindexentries %}\n   {%- if not modname -%}\n   <tr class=\"pcap\"><td></td><td>&nbsp;</td><td></td></tr>\n   <tr class=\"cap\"><td></td><td><a name=\"cap-{{ fname }}\"><strong>{{ fname }}</strong></a></td><td></td></tr>\n   {%- else -%}\n   <tr{% if indent %} class=\"cg-{{ cgroup }}\"{% endif %}>\n     <td>{% if collapse -%}\n       <img src=\"{{ pathto('_static/minus.png', 1) }}\" id=\"toggle-{{ cgroup }}\"\n            class=\"toggler\" style=\"display: none\" />\n         {%- endif %}</td>\n     <td>{% if indent %}&nbsp;&nbsp;&nbsp;{% endif %}\n     {% if fname %}<a href=\"{{ fname }}\">{% endif -%}\n     <tt class=\"xref\">{{ stripped|e }}{{ modname|e }}</tt>\n     {%- if fname %}</a>{% endif %}\n   {%- if pform[0] %} <em>({{ pform|join(', ') }})</em>{% endif -%}\n   </td><td>{% if dep %}<strong>{{ _('Deprecated')}}:</strong>{% endif %}\n     <em>{{ synops|e }}</em></td></tr>\n   {%- endif -%}\n   {% endfor %}\n   </table>\n\n{% endblock %}\n"
  },
  {
    "path": "pylons/docs/en/_oldtemplates/page.html",
    "content": "{% extends \"layout.html\" %}\n{% set page_links = [\n  (pathto('@rss/' + sourcename), 'application/rss+xml', 'Page Comments'),\n] %}\n{% block body %}\n  {% if oldurl %}\n  <div class=\"docwarning\">\n    {% trans %}<strong>Note:</strong> You requested an out-of-date URL from this server. We've tried to redirect you to the new location of this page, but it may not be the right one.{% endtrans %}\n  </div>\n  {% endif %}\n  {{ body }}\n{% endblock %}\n"
  },
  {
    "path": "pylons/docs/en/advanced_models.rst",
    "content": ".. _advanced_models:\n\n===============\nAdvanced Models\n===============\n\nPylons works well with many different types of databases, in addition to other database object-relational mappers.\n\nAdvanced SQLAlchemy\n===================\n\nAlternative SQLAlchemy Styles\n-----------------------------\n\nIn addition to the declarative style, SQLAlchemy has a default more verbose and explicit approach.\n\nDefinitions using the default SQLAlchemy approach\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nHere is a sample :file:`model/__init__.py` with a \"persons\" table, based on \nthe default SQLAlchemy approach:\n\n.. code-block:: python\n\n    \"\"\"The application's model objects\"\"\"\n    import sqlalchemy as sa\n    from sqlalchemy import orm\n\n    from myapp.model import meta\n\n    def init_model(engine):\n        meta.Session.configure(bind=engine)\n        meta.engine = engine\n\n\n    t_persons = sa.Table(\"persons\", meta.metadata,\n        sa.Column(\"id\", sa.types.Integer, primary_key=True),\n        sa.Column(\"name\", sa.types.String(100), primary_key=True),\n        sa.Column(\"email\", sa.types.String(100)),\n        )\n\n    class Person(object):\n        pass\n\n    orm.mapper(Person, t_persons)\n\nThis model has one table, \"persons\", assigned to the variable ``t_persons``.\n:class:`Person` is an ORM class which is bound to the table via the mapper.\n\nRelation example \n++++++++++++++++\n\nHere's an example of a `Person` and an `Address` class with a many:many relationship on `people.my_addresses`. See `Relational Databases for People in a Hurry <http://wiki.pylonshq.com/display/pylonscookbook/Relational+databases+for+people+in+a+hurry>`_ and the `SQLAlchemy manual`_ for details. \n\n.. code-block:: python\n\n    t_people = sa.Table('people', meta.metadata, \n        sa.Column('id', sa.types.Integer, primary_key=True), \n        sa.Column('name', sa.types.String(100)), \n        sa.Column('email', sa.types.String(100)),\n        ) \n\n    t_addresses_people = sa.Table('addresses_people', meta.metadata, \n        sa.Column('id', sa.types.Integer, primary_key=True), \n        sa.Column('person_id', sa.types.Integer, sa.ForeignKey('people.id')), \n        sa.Column('address_id', sa.types.Integer, sa.ForeignKey('addresses.id')),\n        ) \n\n    t_addresses = sa.Table('addresses', meta.metadata, \n        sa.Column('id', sa.types.Integer, primary_key=True), \n        sa.Column('address', sa.types.String(100)),\n        ) \n\n    class Person(object): \n        pass \n\n    class Address(object): \n        pass \n\n    orm.mapper(Address, t_addresses) \n    orm.mapper(Person, t_people, properties = { \n        'my_addresses' : orm.relation(Address, secondary = t_addresses_people), \n        }) \n\n\nDefinitions using \"reflection\" of an existing database table\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf the table already exists, SQLAlchemy can read the column definitions \ndirectly from the database. This is called *reflecting* the table.\n\nThe advantage of this approach is that it allows you to dispense with the \ntask of specifying the column types in Python code.  \n\nReflecting existing database tables must be done inside :func:`init_model` \nbecause to perform the reflection, a live database engine is required and this \nis not available when the module is imported. A live database engine is bound \nexplicitly in the :func:`init_model` function and so enables reflection. \n\n(An *engine* is a SQLAlchemy object that knows how to connect to a particular\ndatabase.)  \n\nHere's the second example with reflection:\n\n.. code-block:: python\n\n    \"\"\"The application's model objects\"\"\"\n    import sqlalchemy as sa\n    from sqlalchemy import orm\n\n    from myapp.model import meta\n\n    def init_model(engine):\n        \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n        # Reflected tables must be defined and mapped here\n        global t_persons\n        t_persons = sa.Table(\"persons\", meta.metadata, autoload=True,\n                             autoload_with=engine)\n        orm.mapper(Person, t_persons)\n\n        meta.Session.configure(bind=engine)\n        meta.engine = engine\n\n\n    t_persons = None\n\n    class Person(object):\n        pass\n\nNote how ``t_persons`` and the :func:`orm.mapper` call moved into \n:func:`init_model`, while the ``Person`` class didn't have to.  Also note \nthe ``global t_persons`` statement.  This tells Python that ``t_persons`` \nis a global variable outside the function.  ``global`` is required when \nassigning to a global variable inside a function.  It's not required if \nyou're merely modifying a mutable object in place, which is why ``meta`` \ndoesn't have to be declared global.\n\nUsing the model standalone \n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou now have everything necessary to use the model in a standalone script such as a cron job, or to test it interactively. You just need to create a SQLAlchemy engine and connect it to the model. This example uses a database \"test.sqlite\" in the current directory: \n\n.. code-block:: pycon\n\n    % python \n    Python 2.5.1 (r251:54863, Oct 5 2007, 13:36:32) \n    [GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2 \n    Type \"help\", \"copyright\", \"credits\" or \"license\" for more information. \n    >>> import sqlalchemy as sa \n    >>> engine = sa.create_engine(\"sqlite:///test.sqlite\") \n    >>> from myapp import model \n    >>> model.init_model(engine) \n\nNow you can use the tables, classes, and Session as described in the\n`SQLAlchemy manual`_.  For example:\n\n.. code-block:: python\n\n    #!/usr/bin/env python\n    import sqlalchemy as sa\n    import tmpapp.model as model\n    import tmpapp.model.meta as meta\n\n    DB_URL = \"sqlite:///test.sqlite\" \n\n    engine = sa.create_engine(DB_URL)\n    model.init_model(engine)\n\n    # Create all tables, overwriting them if they exist.\n    if hasattr(model, \"_Base\"):\n        # SQLAlchemy 0.5 Declarative syntax\n        model._Base.metadata.drop_all(bind=engine, checkfirst=True)\n        model._Base.metadata.create_all(bind=engine)\n    else:\n        # SQLAlchemy 0.4 and 0.5 syntax without Declarative\n        meta.metadata.drop_all(bind=engine, checkfirst=True)\n        meta.metadataa.create_all(bind=engine)\n\n    # Create two records and insert them into the database using the ORM.\n    a = model.Person()\n    a.name = \"Aaa\"\n    a.email = \"aaa@example.com\"\n    meta.Session.add(a)\n\n    b = model.Person()\n    b.name = \"Bbb\"\n    b.email = \"bbb@example.com\"\n    meta.Session.add(b)\n\n    meta.Session.commit()\n\n    # Display all records in the persons table.\n    print \"Database data:\"\n    for p in meta.Session.query(model.Person):\n        print \"id:\", p.id\n        print \"name:\", p.name\n        print \"email:\", p.email\n        print\n\n.. _multiple_databases:\n\nTalking to Multiple Databases at Once\n-------------------------------------\n\nSome applications need to connect to multiple databases (engines). Some always bind certain tables to the same engines (e.g., a general database and a logging database); this is called \"horizontal partitioning\". Other applications have several databases with the same structure, and choose one or another depending on the current request. A blogging app with a separate database for each blog, for instance. A few large applications store different records from the same logical table in different databases to prevent the database size from getting too large; this is called \"vertical partitioning\" or \"sharding\". The pattern above can accommodate any of these schemes with a few minor changes. \n\nFirst, you can define multiple engines in your config file like this: \n\n.. code-block:: ini\n\n    sqlalchemy.default.url = \"mysql://...\" \n    sqlalchemy.default.pool_recycle = 3600 \n    sqlalchemy.log.url = \"sqlite://...\" \n\nThis defines two engines, \"default\" and \"log\", each with its own set of options. Now you have to instantiate every engine you want to use. \n\n.. code-block:: python\n\n    default_engine = engine_from_config(config, 'sqlalchemy.default.') \n    log_engine = engine_from_config(config, 'sqlalchemy.log.') \n    init_model(default_engine, log_engine) \n\n\nOf course you'll have to modify `init_model()` to accept both arguments and create two engines. \n\nTo bind different tables to different databases, but always with a particular table going to the same engine, use the `binds` argument to `sessionmaker` rather than `bind`: \n\n.. code-block:: python\n\n    binds = {\"table1\": engine1, \"table2\": engine2} \n    Session = scoped_session(sessionmaker(binds=binds))\n\n\nTo choose the bindings on a per-request basis, skip the sessionmaker bind(s) argument, and instead put this in your base controller's `\\_\\_call\\_\\_` method before the superclass call, or directly in a specific action method: \n\n.. code-block:: python\n\n    meta.Session.configure(bind=meta.engine) \n\n\n`binds=` works the same way here too. \n\nMultiple Application Instances\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf you're running multiple instances of the _same_ Pylons application in the same WSGI process (e.g., with Paste HTTPServer's \"composite\" application), you may run into concurrency issues. The problem is that :class:`Session` is thread local but not application-instance local. We're not sure how much this is really an issue if ``Session.remove()`` is properly called in the base controller, but just in case it becomes an issue, here are possible remedies: \n\n1) Attach the engine(s) to ``pylons.g`` (aka. ``config[\"pylons.g\"]``) rather than to the `meta` module. The globals object is not shared between application instances. \n\n2) Add a scoping function. This prevents the application instances from sharing the same session objects. Add the following function to your model, and pass it as the second argument to `scoped_session`: \n\n.. code-block:: python\n\n    def pylons_scope(): \n        import thread \n        from pylons import config \n        return \"Pylons|%s|%s\" % (thread.get_ident(), config._current_obj()) \n\n    Session = scoped_session(sessionmaker(), pylons_scope) \n\n\nIf you're affected by this, or think you might be, please bring it up on the pylons-discuss mailing list. We need feedback from actual users in this situation to verify that our advice is correct. \n\n\nNon-SQLAlchemy libraries\n========================\n\nMost of these expose only the object-relational mapper; their SQL builder and connection pool are not meant to be used directly.\n\n`Storm <http://storm.canonical.com>`_\n\n`Geniusql <http://www.aminus.net/geniusql>`_\n\nDB-API\n------\n\nAll the SQL libraries above are built on top of Python's DB-API, which provides a common low-level interface for interacting with several database engines: MySQL, PostgreSQL, SQLite, Oracle, Firebird, MS-SQL, Access via ODBC, etc.  Most programmers do not use DB-API directly because its API is low-level and repetitive and does not provide a connection pool.  There's no \"DB-API package\" to install because it's an abstract interface rather than software.  Instead, install the Python package for the particular engine you're interested in.  Python's `Database Topic Guide <http://www.python.org/topics/database/>`_ describes the DB-API and lists the package required for each engine.  The `sqlite3 <http://docs.python.org/lib/module-sqlite3.html>`_ package for SQLite is included in Python 2.5.\n\nObject Databases\n================\n\nObject databases store Python dicts, lists, and classes in pickles, allowing you to access hierarchical data using normal Python statements rather than having to map them to tables, relations, and a foreign language (SQL).\n\n`ZODB <http://wiki.zope.org/ZODB/FrontPage>`_\n\n`Durus <http://www.mems-exchange.org/software/durus/>`_ [#]_\n\n.. [#] Durus is not thread safe, so you should use its server mode if your\n   application writes to the database.  Do not share connections between\n   threads.  ZODB is thread safe, so it may be a more convenient alternative.\n\nPopular No-SQL Databases\n========================\n\nPylons can also work with other database systems, such as the following:\n\n`Schevo <http://schevo.org/>`_ uses Durus to combine some features of relational and object databases.  It is written in Python.\n\n`CouchDb <http://couchdb.org/>`_ is a document-based database.  It features a `Python API <http://code.google.com/p/couchdb-python/>`_.\n\nThe Datastore database in Google App Engine.\n"
  },
  {
    "path": "pylons/docs/en/advanced_pylons/creating_paste_templates.rst",
    "content": ".. _creating_paste_templates:\n\n========================\nCreating Paste templates\n========================\n\nIntroduction\n============\n\n`Python Paste <http://pythonpaste.org/>`_ is an extremely powerful package that isn't just about WSGI middleware. The related document :ref:`entry_points_and_plugins` demonstrates how to use entry_points to create simple plugins. This document describes how to write just such a plugin for use Paste's project template creation facility and how to add a command to Paste's ``paster`` script.\n\nThe example task is to create a template for an imaginary content management system. The template is going to produce a project directory structure for a Python package, so we need to be able to specify a package name. \n\nCreating The Directory Structure and Templates\n==============================================\n\nThe directory structure for the new project needs to look like this:\n\n.. code-block:: text\n\n    - default_project\n        - +package+\n            - __init__.py\n            - static\n                - layout\n                - region\n                - renderer\n            - service\n                - layout\n                    - __init__.py\n                - region\n                    - __init__.py\n                - renderer\n                    - __init__.py\n        - setup.py_tmpl\n        - setup.cfg_tmpl\n        - development.ini_tmpl\n        - README.txt_tmpl\n        - ez_setup.py\n\nOf course, the actual project's directory structure might look very different. In fact the ``paster create`` command can even be used to generate directory structures which *aren't* project templates --- although this wasn't what it was designed for.\n\nWhen the ``paster create`` command is run, any directories with ``+package+`` in their name will have that portion of the name replaced by a simplified package name and likewise any directories with ``+egg+`` in their name will have that portion replaced by the name of the egg directory, although we don't make use of that feature in this example.\n\nAll of the files with ``_tmpl`` at the end of their filenames are treated as templates and will have the variables they contain replaced automatically. All other files will remain unchanged.\n\n.. note:: The small templating language used with ``paster create`` in files ending in ``_tmpl`` is described in detail in the `Paste util module documentation <http://pythonpaste.org/module-paste.util.template.html>`_\n\nWhen specifying a package name it can include capitalisation and ``_`` characters but it should be borne in mind that the actual name of the package will be the *lowercase* package name with the ``_`` characters removed. If the package name contains an ``_``, the egg name will contain a ``_`` character so occasionally the ``+egg+`` name is different to the ``+package+`` name. \n\nTo avoid difficulty always recommend to users that they stick with package names that contain no ``_`` characters so that the names remain unique when made lowercase.\n\nImplementing the Code\n=====================\n\nNow that the directory structure has been defined, the next step is to implement the commands that will convert this to a ready-to-run project. The template creation commands are implemented by a class derived from ``paste.script.templates.Template``. This is how our example appears:\n\n.. code-block:: python\n\n    from paste.script.templates import Template, var\n\n    vars = [\n        var('version', 'Version (like 0.1)'),\n        var('description', 'One-line description of the package'),\n        var('long_description', 'Multi-line description (in reST)'),\n        var('keywords', 'Space-separated keywords/tags'),\n        var('author', 'Author name'),\n        var('author_email', 'Author email'),\n        var('url', 'URL of homepage'),\n        var('license_name', 'License name'),\n        var('zip_safe', 'True/False: if the package can be distributed as a .zip file',\n            default=False),\n    ]\n        \n    class ArtProjectTemplate(Template):\n        _template_dir = 'templates/default_project'\n        summary = 'Art project template'\n        vars = vars\n\nThe ``vars`` arguments can all be set at run time and will be available to be used as (in this instance) Cheetah template variables in the files which end ``_tmpl``. For example the ``setup.py_tmpl`` file for the ``default_project`` might look like this:\n\n.. code-block:: html+mako\n\n    from setuptools import setup, find_packages\n\n    version = ${repr(version)|\"0.0\"}\n\n    setup(name=${repr(project)},\n        version=version,\n        description=\"${description|nothing}\",\n        long_description=\"\"\"\\\n        ${long_description|nothing}\"\"\",\n        classifiers=[], \n        keywords=${repr(keywords)|empty},\n        author=${repr(author)|empty},\n        author_email=${repr(author_email)|empty},\n        url=${repr(url)|empty},\n        license=${repr(license_name)|empty},\n        packages=find_packages(exclude=['ez_setup']),\n        include_package_data=True,\n        zip_safe=${repr(bool(zip_safe))|False},\n        install_requires=[\n          # Extra requirements go here # \n        ],\n        entry_points=\"\"\"\n            [paste.app_factory]\n            main=${package}:make_app\n        \"\"\",\n    )\n\n\n.. note: The list of available classifier strings can be obtained from: ``http://www.python.org/pypi?%3Aaction=list_classifiers``\n\nNote how the variables specified in ``vars`` earlier are used to generate the actual ``setup.py`` file.\n\nIn order to use the new templates they must be hooked up to the ``paster create`` command by means of an entry point. In the ``setup.py`` file of the project (in which created the project template is going to be stored) we need to add the following:\n\n.. code-block:: python\n\n    entry_points=\"\"\"\n        [paste.paster_create_template]\n        art_project=art.entry.template:ArtProjectTemplate\n    \"\"\",\n\nWe also need to add ``PasteScript>=1.3`` to the ``install_requires`` line. \n\n.. code-block:: python\n\n    install_requires=[\"PasteScript>=1.3\"],\n\nWe just need to install the entry points now by running:\n\n.. code-block:: bash\n\n    python setup.py develop\n\nWe should now be able to see a list of available templates with this command:\n\n.. code-block:: bash\n\n    $ paster create --list-templates\n\n\n.. note:: Windows users will need to add their Python scripts directory to their path or enter the full version of the command, similar to this:\n\n\t.. code-block:: bash\n\t  \n\t\tC:\\Python24\\Scripts\\paster.exe create --list-templates\n        \nYou should see the following:\n\n.. code-block:: text\n\n    Available templates:\n    art_project:              Art project template\n    basic_package:            A basic setuptools-enabled package\n\n\nThere may be other projects too. \n\n\nTroubleshooting\n===============\n\nIf the Art entries don't show up, check whether it is possible to import the ``template.py`` file because any errors are simply ignored by the paster create command rather than output as a warning.\n\nIf the code is correct, the issue might be that the entry points data hasn't been updated. Examine the Python ``site-packages`` directory and delete the ``Art.egg-link`` files, any ``Art*.egg`` files or directories and remove any entries for art from ``easy_install.pth`` (replacing ``Art`` with the name chosen for the project of course). Then re-run ``python setup.py develop`` to install the correct information.\n\nIf problems are still evident, then running the following code will print out a list of all entry points. It might help track the problem down:\n\n.. code-block:: python\n\n    import pkg_resources\n        for x in pkg_resources.iter_group_name(None, None):\n            print x\n\nUsing the Template\n===================\n\nNow that the entry point is working, a new project can be created:\n\n.. code-block:: bash\n\n    $ paster create --template=art TestProject\n\nPaster will ask lots of questions based on the variables set up in ``vars`` earlier. Pressing ``return`` will cause the default to be used. The final result is a nice project template ready for people to start coding with.\n\nImplementing Pylons Templates\n=============================\n\nIf the development context is subject to a frequent need to create lots of Pylons projects, each with a slightly different setup from the standard Pylons defaults then it is probably desirable to create a customised Pylons template to use when generating projects. This can be done in exactly the way described in this document.\n\nFirst, set up a new Python package, perhaps called something like ``CustomPylons`` (obviously, don't use the Pylons name because Pylons itself is already using it). Then check out the Pylons source code and copy the `pylons/templates/default_project <http://pylonshq.com/project/pylonshq/browser/Pylons/trunk/pylons/templates/default_project>`_ directory into the new project as a starting point. The next stage is to add the custom ``vars`` and ``Template`` class and set up the entry points in the ``CustomPylons`` ``setup.py`` file. \n\nAfter those tasks have been completed, it is then possible to create customised templates (ultimately based on the Pylons one) by using the ``CustomPylons`` package.\n"
  },
  {
    "path": "pylons/docs/en/advanced_pylons/entry_points_and_plugins.rst",
    "content": ".. _entry_points_and_plugins:\n\n===================================\nUsing Entry Points to Write Plugins\n===================================\n\nIntroduction\n============\n\nAn entry point is a Python object in a project's code that is identified by a string in the project's ``setup.py`` file. The entry point is referenced by a group and a name so that the object may be discoverable. This means that another application can search for all the installed software that has an entry point with a particular group name, and then access the Python object associated with that name. \n\nThis is extremely useful because it means it is possible to write plugins for an appropriately-designed application that can be loaded at run time. This document describes just such an application.\n\nIt is important to understand that entry points are a feature of the new Python eggs package format and are *not* a standard feature of Python. To learn about eggs, their benefits, how to install them and how to set them up, see:\n\n* `Python Eggs <http://peak.telecommunity.com/DevCenter/PythonEggs>`_\n* `Easy Install <http://peak.telecommunity.com/DevCenter/EasyInstall>`_\n* `Setuptools <http://peak.telecommunity.com/DevCenter/setuptools>`_\n\nIf reading the above documentation is inconvenient, suffice it to say that eggs are created via a similar ``setup.py`` file to the one used by Python's own `distutils <http://docs.python.org/lib/module-distutils.html>`_ module --- except that eggs have some powerful extra features such as entry points and the ability to specify module dependencies and have them automatically installed by ``easy_install`` when the application itself is installed.\n\nFor those developers unfamiliar with ``distutils``: it is the standard mechanism by which Python packages should be distributed. To use it, add a ``setup.py`` file to the desired project, insert the required metadata and specify the important files. The ``setup.py`` file can be used to issue various commands which create distributions of the pacakge in various formats for users to install.\n\nCreating Plugins\n================\n\nThis document describes how to use entry points to create a plugin mechansim which allows new types of content to be added to a content management system but we are going to start by looking at the plugin. \n\nSay the standard way the CMS creates a plugin is with the ``make_plugin()`` function. In order for a plugin to be a plugin it must therefore have the function which takes the same arguments as the :func:`make_plugin` function and returns a plugin. We are going to add some image plugins to the CMS so we setup a project with the following directory structure:\n\n.. code-block:: text\n\n    + image_plugins\n      + __init__.py\n    + setup.py\n\nThe ``image_plugins/__init__.py`` file looks like this:\n\n.. code-block:: python\n\n    def make_jpeg_image_plugin():\n        return \"This would return the JPEG image plugin\"\n\n    def make_png_image_plugin():\n        return \"This would return the PNG image plugin\"\n\nWe have now defined our plugins so we need to define our entry points. First lets write a basic ``setup.py`` for the project:\n\n.. code-block:: python\n\n    from setuptools import setup, find_packages\n\n    setup(\n        name='ImagePlugins',\n        version=\"1.0\",\n        description=\"Image plugins for the imaginary CMS 1.0 project\",\n        author=\"James Gardner\",\n        packages=find_packages(),\n        include_package_data=True,\n    )\n\nWhen using ``setuptools`` we can specify the ``find_packages()`` function and ``include_package_data=True`` rather than having to manually list all the modules and package data like we had to do in the old ``distutils`` ``setup.py``. \n\nBecause the plugin is designed to work with the (imaginary) CMS 1.0 package, we need to specify that the plugin requires the CMS to be installed too and so we add this line to the ``setup()`` function:\n\n.. code-block:: python\n\n        install_requires=[\"CMS>=1.0\"],\n  \nNow when the plugins are installed, CMS 1.0 or above will be installed automatically if it is not already present.\n\nThere are lots of other arguments such as ``author_email`` or ``url`` which you can add to the ``setup.py`` function too.\n\nWe are interested in adding the entry points. We need to decide on a group name for the entry points. It is traditional to use the name of the package using the entry point, separated by a ``.`` character and then use a name that describes what the entry point does. For our example ``cms.plugin`` might be an appropriate name for the entry point. Since the ``image_plugin`` module contains two plugins we will need two entries. Add the following to the ``setup.py`` function:\n\n\n.. code-block:: python\n\n        entry_points=\"\"\"\n            [cms.plugin]\n            jpg_image=image_plugin:make_jpeg_image_plugin\n            png_image=image_plugin:make_png_image_plugin\n        \"\"\",\n\nGroup names are specified in square brackets, plugin names are specified in the format ``name=module.import.path:object_within_the_module``. The object doesn't have to be a function and can have any valid Python name. The module import path doesn't have to be a top level component as it is in this example and the name of the entry point doesn't have to be the same as the name of the object it is pointing to.\n\nThe developer can add as many entries as desired in each group as long as the names are different and the same holds for adding groups. It is also possible to specify the entry points as a Python dictionary rather than a string if that approach is preferred.\n\nThere are two more things we need to do to complete the plugin. The first is to include an ``ez_setup`` module so that if the user installing the plugin doesn't have ``setuptools`` installed, it will be installed for them. We do this by adding the following to the very top of the ``setup.py`` file before the import:\n\n\n.. code-block:: python\n\n    from ez_setup import use_setuptools\n    use_setuptools()\n\n\nWe also need to download the ``ez_setup.py`` file into our project directory at the same level as ``setup.py``.\n\n.. note::\n\n\tIf you keep your project in SVN there is a `trick you can use with the `SVN:externals <http://peak.telecommunity.com/DevCenter/setuptools#managing-multiple-projects>`_ to keep the ``ez_setup.py`` file up to date.\n\nFinally in order for the CMS to find the plugins we need to install them. We can do this with:\n\n.. code-block:: bash\n\n    $ python setup.py install\n\nas usual or, since we might go on to develop the plugins further we can install them using a special development mode which sets up the paths to run the plugins from the source rather than installing them to Python's ``site-packages`` directory:\n\n.. code-block:: bash\n\n\t$ python setup.py develop\n\nBoth commands will download and install ``setuptools`` if you don't already have it installed.\n\n\nUsing Plugins\n=============\n\nNow that the plugin is written we need to write the code in the CMS package to load it. Luckily this is even easier. \n\nThere are actually lots of ways of discovering plugins. For example: by distribution name and version requirement (such as ``ImagePlugins>=1.0``) or by the entry point group and name (eg ``jpg_image``). For this example we are choosing the latter, here is a simple script for loading the plugins:\n\n.. code-block:: python\n\n    from pkg_resources import iter_entry_points\n    for entry_point in iter_entry_points(group='cms.plugin', name=None):\n        print(entry_point)\n\n    from pkg_resources import iter_entry_points\n    available_methods = []\n    for entry_point in iter_entry_points(group='authkit.method', name=None):\n        available_methods.append(entry_point.load())\n\nExecuting this short script, will result in the following output:\n\n.. code-block:: text\n\n    This would return the JPEG image plugin\n    This would return the PNG image plugin\n\nThe ``iter_entry_points()`` function has looped though all the objects in the ``cms.plugin`` group and returned the function they were associated with. The application then called the function that the entry point was pointing to.\n\nWe hope that we have demonstrated the power of entry points for building extensible code and developers are encouraged to read the `pkg_resources <http://peak.telecommunity.com/DevCenter/PkgResources>`_ module documentation to learn about some more features of the eggs format. \n\n"
  },
  {
    "path": "pylons/docs/en/advanced_pylons/index.rst",
    "content": ".. _advanced_pylons:\n\n===============\nAdvanced Pylons\n===============\n\n.. toctree::\n   :maxdepth: 1\n\n   paster\n   paster_commands\n   creating_paste_templates\n   entry_points_and_plugins\n   \n"
  },
  {
    "path": "pylons/docs/en/advanced_pylons/paster.rst",
    "content": ".. _paster:\n\nWSGI, CLI scripts\n=================\n\nWorking with :class:`wsgiwrappers.WSGIRequest`\n----------------------------------------------\n\nPylons uses a specialised *WSGIRequest* class that is accessible via the\n``paste.wsgiwrappers`` module.\n\nThe ``wsgiwrappers.WSGIRequest`` object represents a WSGI request that has \na more programmer-friendly interface. This interface does not expose every \ndetail of the WSGI environment *(why?)* and does not attempt to express \nanything beyond what is available in the environment dictionary.\n\nThe only state maintained in this object is the desired ``charset``, an \nassociated errors handler and a ``decode_param_names`` option.\n\n.. _note:\n\n    *Unicode notes*\n\n    When ``charset`` is set, the incoming parameter values will be \n    automatically coerced to unicode objects of the charset encoding.\n\n    When unicode is expected, ``charset`` will be overridden by the the value \n    of the charset parameter set in the Content-Type header, if one was \n    specified by the client.\n\n    The incoming parameter names are not decoded to unicode unless the \n    decode_param_names option is enabled.\n\nThe class variable ``defaults`` specifies default values for charset, errors,\nand language. These default values can be overridden for the current request \nvia the registry *(what's a registry?)*.\n\nThe language default value is considered the fallback during i18n \ntranslations to ensure in odd cases that mixed languages don't occur should \nthe language file contain the string but not another language in the accepted \nlanguages list. The language value only applies when getting a list of \naccepted languages from the HTTP Accept header.\n\nThis behavior is duplicated from Aquarium, and may seem strange but is very \nuseful. Normally, everything in the code is in \"en-us\". However, the \"en-us\" \ntranslation catalog is usually empty. If the user requests [\"en-us\", \"zh-cn\"] \nand a translation isn't found for a string in \"en-us\", you don't want gettext \nto fallback to \"zh-cn\". You want it to just use the string itself. Hence, if \na string isn't found in the language catalog, the string in the source code \nwill be used.\n\nAll other state is kept in the environment dictionary; this is essential for \ninteroperability.\n\nYou are free to subclass this object.\n\nAttributes\n----------\n\nGET\n^^^\n\nA dictionary-like object representing the QUERY_STRING parameters. Always present, possibly empty.\n\nIf the same key is present in the query string multiple times, a list of its \nvalues can be retrieved from the :class:`MultiDict` via the :meth:``getall`` \nmethod.\n\nReturns a :class:`MultiDict` container or, when charset is set, a :class:`UnicodeMultiDict`.\n\nPOST\n^^^^\n\nA dictionary-like object representing the ``POST`` body.\n\nMost values are encoded strings, or unicode strings when charset is set. \nThere may also be FieldStorage objects representing file uploads. If this is \nnot a POST request, or the body is not encoded fields (e.g., an XMLRPC \nrequest) then this will be empty.\n\nThis will consume wsgi.input when first accessed if applicable, but the raw \nversion will be put in environ['paste.parsed_formvars'].\n\nReturns a MultiDict container or a UnicodeMultiDict when charset is set.\n\ncookies\n^^^^^^^\n\nA dictionary of cookies, keyed by cookie name.\n\nJust a plain dictionary, may be empty but not None.\n\ndefaults\n^^^^^^^^\n\n.. code-block:: python\n\n    {'errors': 'replace', \n     'decode_param_names': False, \n     'charset': None, \n     'language': 'en-us'}\n\nhost\n^^^^\n\nThe host name, as provided in ``HTTP_HOST`` with a fall-back to :envvar:`SERVER_NAME`\n\nis_xhr\n^^^^^^\n\nReturns a boolean if ``X-Requested-With`` is present and is a ``XMLHttpRequest``\n\nlanguages\n^^^^^^^^^\n\nReturns a (possibly empty) list of preferred languages, most preferred first.\n\n\nparams\n^^^^^^\n\nA dictionary-like object of keys from ``POST``, ``GET``, ``URL`` dicts\n\nReturn a key value from the parameters, they are checked in the following order: POST, GET, URL\n\n\nAdditional methods supported:\n-----------------------------\n\ngetlist(key)\n^^^^^^^^^^^^\n\nReturns a list of all the values by that key, collected from POST, GET, URL dicts\n\nReturns a :class:`MultiDict` container or a :class:`UnicodeMultiDict` when :data:`charset` is set.\n\nurlvars\n^^^^^^^\n\nReturn any variables matched in the URL (e.g. wsgiorg.routing_args).\n\nMethods\n-------\n\n__init__(self, environ)\n^^^^^^^^^^^^^^^^^^^^^^^\n\ndetermine_browser_charset(self)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nDetermine the encoding as specified by the browser via the Content-Type's ``charset parameter``, if one is set\n\nmatch_accept(self, mimetypes)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nReturn a list of specified mime-types that the browser's HTTP Accept header allows in the order provided.\n\n"
  },
  {
    "path": "pylons/docs/en/advanced_pylons/paster_commands.rst",
    "content": ".. _paster_commands: - Adding commands to paster\n\n=========================\nAdding commands to Paster\n=========================\n\nPaster command\n==============\n\nThe command line will be ``paster my-command arg1 arg2`` if the current directory is the application egg, or ``paster --plugin=MyPylonsApp my-command arg1 arg2`` otherwise.  In the latter case, ``MyPylonsApp`` must have been installed via ``easy_install`` or ``python setup.py develop``.  \n\nMake a package directory for your commands:\n\n.. code-block:: bash\n\n\t$ mkdir myapp/commands\n\t$ touch myapp/commands/__init__.py\n\nCreate a module ``myapp/commands/my_command.py`` like this:\n\n.. code-block:: python\n\n\tfrom paste.script.command import Command\n\t\n\tclass MyCommand(Command):\n\t\t# Parser configuration\n\t\tsummary = \"--NO SUMMARY--\"\n\t\tusage = \"--NO USAGE--\"\n\t\tgroup_name = \"myapp\"\n\t\tparser = Command.standard_parser(verbose=False)\n\t\n\t\tdef command(self):\n\t\t\timport pprint\n\t\t\tprint \"Hello, app script world!\"\n\t\t\tprint\n\t\t\tprint \"My options are:\"\n\t\t\tprint \"    \", pprint.pformat(vars(self.options))\n\t\t\tprint \"My args are:\"\n\t\t\tprint \"    \", pprint.pformat(self.args)\n\t\t\tprint\n\t\t\tprint \"My parser help is:\"\n\t\t\tprint\n\t\t\tprint self.parser.format_help()\n\n.. note:: The class _must_ define ``.command``, ``.parser``, and ``.summary``\n\nModify the ``entry_points`` argument in :file:`setup.py` to contain:\n\n.. code-block:: python\n\n\t[paste.paster_command]\n\tmy-command = myapp.commands.my_command:MyCommand\n\n\nRun ``python setup.py develop`` or ``easy_install .`` to update the entry points in the egg in sys.path.\n\nNow you should be able to run:\n\n.. code-block:: bash\n\n\t$ paster --plugin=MyApp my-command arg1 arg2\n\tHello, MyApp script world!\n\n\tMy options are:\n\t\t {'interactive': False, 'overwrite': False, 'quiet': 0, 'verbose': 0}\n\tMy args are:\n\t\t ['arg1', 'arg2']\n\t\n\tMy parser help is:\n\t\n\tUsage: /usr/local/bin/paster my-command [options] --NO USAGE--\n\t--NO SUMMARY--\n\t\n\tOptions:\n\t  -h, --help  show this help message and exit\n\t\n\t$ paster --plugin=MyApp --help\n\tUsage: paster [paster_options] COMMAND [command_options]\n\t\n\t...\n\tmyapp:\n\t  my-command      --NO SUMMARY--\n\t\n\tpylons:\n\t  controller      Create a Controller and accompanying functional test\n\t  restcontroller  Create a REST Controller and accompanying functional test\n\t  shell           Open an interactive shell with the Pylons app loaded\n\nRequired class attributes\n==========================\n\nIn addition to the ``.command`` method, the class should define ``.parser`` and ``.summary``.\n\nCommand-line options\n====================\n\n:func:`Command.standard_parser` returns a Python :obj:`OptionParser`.  Calling ``parser.add_option`` enables the developer to add as many options as desired.  Inside the ``.command`` method, the user's options are available under ``self.options``, and any additional arguments are in ``self.args``.  \n\nThere are several other class attributes that affect the parser; see them defined in ``paste.script.command:Command``.  The most useful attributes are ``.usage``, ``.description``, ``.min_args``, and ``.max_args``.   ``.usage`` is the part of the usage string _after_ the command name.  The ``.standard_parser()`` method has several optional arguments to add standardized options; some of these got added to my parser although I don't see how.\n\nSee the ``paster shell`` command, ``pylons.commands:ShellCommand``, for an example of using command-line options and loading the ``.ini file`` and model.  \n\nAlso see \"paster setup-app\" where it is defined in ``paste.script.appinstall.SetupCommand``.  This is evident from the entry point in PasteScript  (:file:`PasteScript-VERSION.egg/EGG_INFO/entry_points.txt`).  It is a complex example of reading a config file and delegating to another entry point. \n\nThe code for calling ``myapp.websetup:setup_config`` is in ``paste.script.appinstall``.  \n\nThe ``Command`` class also has several convenience methods to handle console prompts, enable logging, verify directories exist and that files have expected content, insert text into a file, run a shell command, add files to Subversion, parse \"var=value\" arguments, add variables to an .ini file.\n\nUsing paster to access a Pylons app\n===================================\n\nPaster provides ``request`` and ``post`` commands for running requests on an application. These commands will be run in the full configuration context of a normal application.  Useful for cron jobs, the error handler will also be in place and you can get email reports of failed requests.\n\nBecause arguments all just go in ``QUERY_STRING``, ``request.GET`` and ``request.PARAMS`` won't look like you expect.  But you can parse them with\nsomething like:\n\n.. code-block:: python\n\n  parser = optparse.OptionParser()\n  parser.add_option(etc)\n\n  args = [item[0] for item in\n          cgi.parse_qsl(request.environ['QUERY_STRING'])]\n  \n  options, args = parser.parse_args(args)\n\npaster request / post\n---------------------\n\nUsage: paster request / post [options] CONFIG_FILE URL [OPTIONS/ARGUMENTS]\n\nRun a request for the described application\n\nThis command makes an artifical request to a web application that uses a\n``paste.deploy`` configuration file for the server and application.  Use 'paster\nrequest config.ini /url' to request ``/url``.\n\nUse 'paster post config.ini /url < data' to do a POST with the given request body.\n\nIf the URL is relative (i.e. doesn't begin with /) it is interpreted as relative to /.command/.  \n\nThe variable ``environ['paste.command_request']`` will be set to True in the request, so your application can distinguish these calls from normal requests.  \n\nNote that you can pass options besides the options listed here; any unknown options will be passed to the application in ``environ['QUERY_STRING']``.\n\n.. code-block:: none\n\n\tOptions:\n\t  -h, --help            show this help message and exit\n\t  -v, --verbose         \n\t  -q, --quiet           \n\t  -n NAME, --app-name=NAME\n                                Load the named application (default main)\n\t  --config-var=NAME:VALUE\n                                Variable to make available in the config for %()s\n                                substitution (you can use this option multiple times)\n\t  --header=NAME:VALUE   Header to add to request (you can use this option\n                                multiple times)\n\t  --display-headers     Display headers before the response body\n\nFuture development\n------------------\n\nA Pylons controller that handled some of this would probably be quite\nuseful.  Probably even nicer with additions to the current template, so\nthat ``/.command/`` all gets routed to a single controller that uses actions\nfor the various sub-commands, and can provide a useful response to\n``/.command/?-h``, etc.\n"
  },
  {
    "path": "pylons/docs/en/caching.rst",
    "content": ".. _caching:\n\n=======\nCaching\n=======\n\nInevitably, there will be occasions during applications development or deployment when some task is revealed to be taking a significant amount of time to complete. When this occurs, the best way to speed things up is with :term:`caching`. \n\nCaching is enabled in Pylons using `Beaker`_, the same package that\nprovides session handling. Beaker supports a variety of caching backends: in-memory, database, Google Datastore, filesystem, and memcached. Additional extensions are available that support Tokyo Cabinet,\nRedis, Dynomite, and Ringo. Back-ends can be added with Beaker's extension\nsystem.\n\n.. seealso:: `Beaker Extension Add-ons <http://github.com/didip/beaker_extensions/tree/master>`_\n\nTypes of Caching\n================\n\nPylons offers a variety of caching options depending on the granularity of\ncaching desired. Fine-grained caching down to specific sub-sections of a \ntemplate, arbitrary Python functions, all the way up to entire controller\nactions and browser-side full-page caching are available.\n\nAvailable caching options (ordered by granularity, least to most specific):\n\n* **Browser-side** - HTTP/1.1 supports the :term:`ETag` caching system that allows the browser to use its own cache instead of requiring regeneration of the entire page. ETag-based caching avoids repeated generation of content but if the browser has never seen the page before, the page will still be generated. Therefore using ETag caching in conjunction with one of the other types of caching listed here will achieve optimal throughput and avoid unnecessary calls on resource-intensive operations.\n\n* **Controller Actions** - A Pylons controller action can have its entire\n  result cached, including response headers if desired.\n\n* **Templates** - The results of an entire rendered template can be cached using the :meth:`3 cache keyword arguments to the render calls <pylons.templating.render_mako>`. These render commands can also be used inside templates. \n\n* **Arbitrary Functions** - Any function can be independently cached using\n  Beaker's cache decorators. This allows fine-grained caching of just the\n  parts of the code that can be cached.\n\n* **Template Fragments** - Built-in caching options are available for both `Mako`_ and `Myghty <http://www.myghty.org/docs/cache.myt>`_ template engines. They allow fine-grained caching of only certain sections of the template. This is also sometimes called fragment caching since individual fragments of a page can be cached.\n\nNamespaces and Keys\n===================\n\n`Beaker`_ is used for caching arbitrary Python functions, template results,\nand in `Mako`_ for caching individual `<def>` blocks. Browser-side caching\ndoes *not* utilize `Beaker`_.\n\nThe two primary concepts to bear in mind when caching with `Beaker`_ are:\n\n1. Caches have a *namespace*, this is to organize a cache such that variations\n   of the same thing being cached are associated under a single place.\n2. Variations of something being cached, are *keys* which are under that \n   namespace.\n\nFor example, if we want to cache a function, the function\nname along with a unique name for it would be considered the *namespace*. The\narguments it takes to differentiate the output to cache, are the *keys*.\n\nAn example of caching with the :func:`~beaker.cache.cache_region` decorator::\n    \n    @cache_region('short_term', 'search_func')\n    def get_results(search_param):\n        # do something to retrieve data\n        data = get_data(search_param)\n        return data\n\n    results = get_results('gophers')\n\nIn this example, the namespace will be the function name + module +\n'search_func'. Since a single module might have multiple methods of the\nsame name you wish to cache, the :func:`~beaker.cache.cache_region` decorator\ntakes another argument in addition to the region to use, which is added to the\nnamespace.\n\nThe key in this example is the `search_param` value. For each value of it, a\nseparate result will be cached.\n\n.. seealso::\n    \n    Stephen Pierzchala's `Caching for Performance <http://web.archive.org/web/20060424171425/http://www.webperformance.org/caching/caching_for_performance.pdf>`_ (stephen@pierzchala.com)\n    Beaker `Caching Docs <http://beaker.groovie.org/caching.html>`_\n\nConfiguring\n===========\n\n`Beaker`_'s cache options can be easily configured in the project's\nINI file. Beaker's `configuration documentation\n<http://beaker.groovie.org/configuration.html>`_ explains how to setup\nthe most common options.\n\nThe cache options specified will be used in the absence of more specific\nkeyword arguments to individual cache functions. Functions that support\n:ref:`cache_regions` will use the settings for that region.\n\n.. _cache_regions:\n\nCache Regions\n-------------\n\nCache regions are named groupings of related options. For example, in many web applications, there might be a few cache strategies used in a company, with short-term cached objects ending up in Memcached, and longer-term cached objects stored in the filesystem or a database.\n\nUsing cache regions makes it easy to declare the cache strategies in one\nplace, then use them throughout the application by referencing the cache\nstrategy name.\n\nCache regions should be setup in the :file:`development.ini` file, but can\nalso be configured and passed directly into the `CacheManager` instance that\nis created in the :file:`lib/app_globals.py` file.\n\nExample INI section for two cache regions (put these under your `[app:main]` \nsection):\n\n.. code-block:: ini\n    \n    beaker.cache.regions = short_term, long_term\n    beaker.cache.short_term.type = ext:memcached\n    beaker.cache.short_term.url = 127.0.0.1:11211\n    beaker.cache.short_term.expire = 3600\n\n    beaker.cache.long_term.type = ext:database\n    beaker.cache.long_term.url = mysql://dbuser:dbpass@127.0.0.1/cache_db\n    beaker.cache.long_term.expire = 86400\n\nThis sets up two cache regions, `short_term` and `long_term`.\n\n\nBrowser-Side\n============\n\nBrowser-side caching can utilize one of several methods. The entire page can\nhave cache headers associated with it to indicate to the browser that it \nshould be cached. Or, using the ETag Cache header, a page can have more \nfine-grained caching rules applied.\n\nCache Headers\n-------------\n\nCache headers may be set directly on the\n:class:`~pylons.controllers.util.Response` object by setting the headers \ndirectly using the :meth:`~webob.response.Response.headers` property, or\nby using the cache header helpers.\n\nTo ensure pages aren’t accidentally cached in dynamic web\napplications, Pylons default behavior sets the `Pragma` and `Cache-Control` headers to \n`no-cache`. Before setting cache headers, these default values should be\ncleared.\n\nClearing the default `no-cache` response headers::\n    \n    class SampleController(BaseController):\n        def index(self):\n            # Clear the default cache headers\n            del response.headers['Cache-Control']\n            del response.headers['Pragma']\n            \n            return render('/index.html)\n\nUsing the response cache helpers::\n    \n    # Set an action response to expires in 30 seconds\n    class SampleController(BaseController):\n        def index(self):\n            # Clear the default cache headers\n            del response.headers['Cache-Control']\n            del response.headers['Pragma']\n            \n            response.cache_expires(seconds=30)\n            return render('/index.html')\n    \n    # Set the cache-control to private with a max-age of 30 seconds\n    class SampleController(BaseController):\n        def index(self):\n            # Clear the default cache headers\n            del response.headers['Cache-Control']\n            del response.headers['Pragma']\n            \n            response.cache_control = {'max-age': 30, 'public': True}\n            return render('/index.html')\n    \nAll of the values that can be passed to the `cache_control` property dict,\nalso may be passed into the `cache_expires` function call. It's recommended\nthat you use the `cache_expires` helper as it also sets the Last-Modified and\nExpires headers to the second interval as well.\n\n.. seealso:: `Cache Control Header RFC <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9>`_\n\nE-Tag Caching\n-------------\n\nCaching via ETag involves sending the browser an ETag header so that it knows \nto save and possibly use a cached copy of the page from its own cache, instead \nof requesting the application to send a fresh copy. \n\nBecause the ETag cache relies on sending headers to the browser, it works in a \nslightly different manner to the other caching mechanisms. \n\nThe :func:`~pylons.controllers.util.etag_cache` function will set the proper HTTP headers if\nthe browser doesn't yet have a copy of the page. Otherwise, a 304 HTTP\nException will be thrown that is then caught by Paste middleware and\nturned into a proper 304 response to the browser. This will cause the\nbrowser to use its own locally-cached copy.\n\nETag-based caching requires a single key which is sent in the ETag HTTP header\nback to the browser. The `RFC specification for HTTP headers <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html>`_ indicates that an \nETag header merely needs to be a string. This value of this string does not need \nto be unique for every URL as the browser itself determines whether to use its own \ncopy, this decision is based on the URL and the ETag key. \n\n.. code-block:: python \n\n    def my_action(self): \n        etag_cache('somekey') \n        return render('/show.myt', cache_expire=3600) \n\nOr to change other aspects of the response: \n\n.. code-block:: python \n\n    def my_action(self): \n        etag_cache('somekey') \n        response.headers['content-type'] = 'text/plain' \n        return render('/show.myt')\n\nThe frequency with which an ETag cache key is changed will depend on the web \napplication and the developer's assessment of how often the browser should be \nprompted to fetch a fresh copy of the page.\n\n\nController Actions\n==================\n\nThe :func:`~pylons.decorators.cache.beaker_cache` decorator is for caching\nthe results of a complete controller action.\n\nExample:\n\n.. code-block:: python \n\n    from pylons.decorators.cache import beaker_cache \n\n    class SampleController(BaseController): \n\n        # Cache this controller action forever (until the cache dir is\n        # cleaned)\n        @beaker_cache() \n        def home(self): \n            c.data = expensive_call() \n            return render('/home.myt') \n\n        # Cache this controller action by its GET args for 10 mins to memory\n        @beaker_cache(expire=600, type='memory', query_args=True) \n        def show(self, id): \n            c.data = expensive_call(id) \n            return render('/show.myt') \n\nBy default the decorator uses a composite of all of the decorated function's arguments as the cache key. It can alternatively use a composite of the `request.GET` query args as the cache key when the `query_args` option is enabled.\n\nThe cache key can be further customized via the `key` argument.\n\n.. warning::\n    \n    By default, the :func:`~pylons.decorators.cache.beaker_cache` decorator\n    will cache the entire response object. This means the headers that were\n    generated during the action will be cached as well. This can be disabled\n    by providing `cache_response = False` to the decorator.\n\nTemplates\n=========\n\nAll :func:`render <pylons.templating.render_mako>` commands have caching\nfunctionality built in. To use it, merely add the appropriate cache keyword\nto the render call.\n\n.. code-block:: python \n\n    class SampleController(BaseController): \n        def index(self): \n            # Cache the template for 10 mins \n            return render('/index.html', cache_expire=600) \n\n        def show(self, id): \n            # Cache this version of the template for 3 mins \n            return render('/show.html', cache_key=id, cache_expire=180) \n\n        def feed(self): \n            # Cache for 20 mins to memory \n            return render('/feed.html', cache_type='memory', cache_expire=1200)\n\n        def home(self, user): \n            # Cache this version of a page forever (until the cache dir\n            # is cleaned)\n            return render('/home.html', cache_key=user, cache_expire='never') \n\n.. note::\n    \n    At the moment, these functions do not support the use of cache region\n    pre-defined argument sets.\n\n\nArbitrary Functions\n===================\n\nAny Python function that returns a pickle-able result can be cached using\n`Beaker`_. The recommended way to cache functions is to use the\n:meth:`~beaker.cache.cache_region` decorator. This decorator requires the\n:ref:`cache_regions` to be configured.\n\nUsing the :meth:`~beaker.cache.cache_region` decorator::\n    \n    @cache_region('short_term', 'search_func')\n    def get_results(search_param):\n        # do something to retrieve data\n        data = get_data(search_param)\n        return data\n\n    results = get_results('gophers')\n\n.. seealso:: `Beaker Caching Documentation <http://beaker.groovie.org/caching.html>`_\n\nInvalidating\n------------\n\nA cached function can be manually invalidated by using the\n:meth:`~beaker.cache.region_invalidate` function.\n\nExample::\n    \n    region_invalidate(get_results, None, 'search_func', search_param)\n\n\nFragments\n=========\n\nIndividual template files, and `<def>` blocks within them can be independently \ncached. Since the caching system utilizes `Beaker`_, any available `Beaker`_\nback-ends are present in `Mako`_ as well.\n\nExample::\n    \n    <%def name=\"mycomp\" cached=\"True\" cache_timeout=\"30\" cache_type=\"memory\">\n        other text\n    </%def>\n\n.. seealso:: `Mako Caching Documentation <http://www.makotemplates.org/docs/caching.html>`_\n\n.. _cache: http://en.wikipedia.org/wiki/Cache\n.. _Beaker: http://beaker.groovie.org\n.. _Mako: http://www.makotemplates.org/"
  },
  {
    "path": "pylons/docs/en/concepts.rst",
    "content": ".. _concepts:\n\n==================\nConcepts of Pylons\n==================\n\nUnderstanding the basic concepts of Pylons, the flow of a request and response\nthrough the stack and how Pylons operates makes it easier to customize when\nneeded, in addition to clearing up misunderstandings about why things behave\nthe way they do. \n\nThis section acts as a basic introduction to the concept of\na :term:`WSGI` application, and :term:`WSGI Middleware` in addition to showing\nhow Pylons utilizes them to assemble a complete working web framework.\n\nTo follow along with the explanations below, create a project following the \n:ref:`getting_started` Guide.\n\n\n*****************************\nThe 'Why' of a Pylons Project\n*****************************\n\nA new Pylons project works a little differently than in many other web\nframeworks. Rather than loading the framework, which then finds a new\nprojects code and runs it, Pylons creates a Python package that does the\nopposite. That is, when its run, it imports objects from Pylons, assembles\nthe WSGI Application and stack, and returns it.\n\nIf desired, a new project could be completely cleared of the Pylons imports\nand run any arbitrary WSGI application instead. This is done for a greater\ndegree of freedom and flexibility in building a web application that works\nthe way the developer needs it to.\n\nBy default, the project is configured to use standard components that most\ndevelopers will need, such as sessions, template engines, caching, high\nlevel request and response objects, and an :term:`ORM`. By having it all\nsetup in the project (rather than hidden away in 'framework' code), the\ndeveloper is free to tweak and customize as needed.\n\nIn this manner, Pylons has setup a project with its *opinion* of what may\nbe needed by the developer, but the developer is free to use the tools\nneeded to accomplish the projects goals. Pylons offers an unprecedented\nlevel of customization by exposing its functionality through the project\nwhile still maintaining a remarkable amount of simplicity by retaining a\nsingle standard interface between core components (:term:`WSGI`).\n\n\n*****************\nWSGI Applications\n*****************\n\nWSGI is a basic specification known as :pep:`333`, that describes a\nmethod for interacting with a HTTP server. This involves a way to get access\nto HTTP headers from the request, and how set HTTP headers and return content\non the way back out.\n\nA 'Hello World' WSGI Application:\n\n.. code-block :: python\n    \n    def simple_app(environ, start_response):\n        start_response('200 OK', [('Content-type', 'text/html')])\n        return ['<html><body>Hello World</body></html>']\n\nThis WSGI application does nothing but set a 200 status code for the response,\nset the HTTP 'Content-type' header, and return some HTML.\n\nThe WSGI specification lays out a `set of keys that will be set in the \nenviron dict <http://www.python.org/dev/peps/pep-0333/#environ-variables>`_.\n\nThe WSGI interface, that is, this method of calling a function (or method of\na class) with two arguments, and handling a response as shown above, is used\nthroughout Pylons as a standard interface for passing control to the next\ncomponent.\n\nInside a new project's :file:`config/middleware.py`, the `make_app` function is\nresponsible for creating a WSGI application, wrapping it in WSGI middleware\n(explained below) and returning it so that it may handle requests from a\nHTTP server.\n\n\n.. _wsgi-middleware:\n\n***************\nWSGI Middleware\n***************\n\nWithin :file:`config/middleware.py` a Pylons application is wrapped in successive layers which add functionality. The process of wrapping the Pylons application in middleware results in a structure conceptually similar to the layers in an onion.\n\n.. image:: _static/pylons_as_onion.png\n   :alt: Pylons middleware onion analogy\n   :align: center\n\nOnce the middleware has been used to wrap the Pylons application, the make_app\nfunction returns the completed app with the following structure (outermost\nlayer listed first):\n\n.. code-block:: text\n\n    Registry Manager\n        Status Code Redirect\n            Error Handler\n                Cache Middleware\n                    Session Middleware\n                        Routes Middleware\n                            Pylons App (WSGI Application)\n\nWSGI middleware is used extensively in Pylons to add functionality to the\nbase WSGI application. In Pylons, the 'base' WSGI Application is the \n:class:`~pylons.wsgiapp.PylonsApp`. It's responsible for looking in the\n`environ` dict that was passed in (from the Routes Middleware).\n\nTo see how this functionality is created, consider a small class that\nlooks at the `HTTP_REFERER` header to see if it's Google:\n\n.. code-block :: python\n    \n    class GoogleRefMiddleware(object):\n        def __init__(self, app):\n            self.app = app\n        \n        def __call__(self, environ, start_response):\n            environ['google'] = False\n            if 'HTTP_REFERER' in environ:\n                if environ['HTTP_REFERER'].startswith('http://google.com'):\n                    environ['google'] = True\n            return self.app(environ, start_response)\n\nThis is considered WSGI Middleware as it still can be called and returns\nlike a WSGI Application, however, it's adding something to environ, and then\ncalls a WSGI Application that it is initialized with. That's how the layers\nare built up in the `WSGI Stack` that is configured for a new Pylons project.\n\nSome of the layers, like the Session, Routes, and Cache middleware, only add\nobjects to the `environ` dict, or add HTTP headers to the response (the Session middleware for example adds the session cookie header). Others, such\nas the Status Code Redirect, and the Error Handler may fully intercept the\nrequest entirely, and change how it's responded to.\n\n\n*******************\nController Dispatch\n*******************\n\nWhen the request passes down the middleware, the incoming URL gets parsed in\nthe RoutesMiddleware, and if it matches a URL (See :ref:`url-config`), the\ninformation about the controller that should be called is put into the `environ` dict for use by :class:`~pylons.wsgiapp.PylonsApp`.\n\nThe :class:`~pylons.wsgiapp.PylonsApp` then attempts to find a controller in the :file:`controllers`\ndirectory that matches the name of the controller, and searches for a class\ninside it by a similar scheme (controller name + 'Controller', ie,\nHelloController). Upon finding a controller, its then called like any other\nWSGI application using the same WSGI interface that\n:class:`~pylons.wsgiapp.PylonsApp` was called with.\n\n.. versionadded:: 1.0\n    Controller name can also be a dotted path to the module / callable that\n    should be imported and called. For example, to use a controller named\n    'Foo' that is in the 'bar.controllers' package, the controller name\n    would be `bar.controllers:Foo`.\n \nThis is why the BaseController that resides in a project's\n:file:`lib/base.py` module inherits from\n:class:`~pylons.controllers.core.WSGIController` and has a `__call__`\nmethod that takes the `environ` and `start_response`. The\n:class:`~pylons.controllers.core.WSGIController` locates a method in the\nclass that corresponds to the `action` that Routes found, calls it, and \nreturns the response completing the request.\n\n\n******\nPaster\n******\n\nRunning the :command:`paster` command all by itself will\nshow the sets of commands it accepts:\n\n.. code-block :: bash\n    \n    $ paster\n    Usage: paster [paster_options] COMMAND [command_options]\n\n    Options:\n      --version         show program's version number and exit\n      --plugin=PLUGINS  Add a plugin to the list of commands (plugins are Egg\n                        specs; will also require() the Egg)\n      -h, --help        Show this help message\n\n    Commands:\n      create          Create the file layout for a Python distribution\n      grep            Search project for symbol\n      help            Display help\n      make-config     Install a package and create a fresh config file/directory\n      points          Show information about entry points\n      post            Run a request for the described application\n      request         Run a request for the described application\n      serve           Serve the described application\n      setup-app       Setup an application, given a config file\n\n    pylons:\n      controller      Create a Controller and accompanying functional test\n      restcontroller  Create a REST Controller and accompanying functional test\n      shell           Open an interactive shell with the Pylons app loaded\n\nIf :command:`paster` is run inside of a Pylons project, this should be the\noutput that will be printed. The last section, `pylons` will be absent if\nit is not run inside a Pylons project. This is due to a dynamic plugin\nsystem the :command:`paster` script uses, to determine what sets of\ncommands should be made available.\n\nInside a Pylons project, there is a directory ending in `.egg-info`, that has\na :file:`paster_plugins.txt` file in it. This file is looked for and read by\nthe :command:`paster` script, to determine what other packages should be\nsearched dynamically for commands. Pylons makes several commands available\nfor use in a Pylons project, as shown above.\n\n\n***********************\nLoading the Application\n***********************\n\nRunning (and thus loading) an application is done using the :command:`paster`\ncommand:\n\n.. code-block :: bash\n    \n    $ paster serve development.ini\n\nThis instructs the paster script to go into a 'serve' mode. It will attempt\nto load both a server and a WSGI application that should be served, by\nparsing the configuration file specified. It looks for a `[server]` block to\ndetermine what server to use, and an `[app]` block for what WSGI application\nshould be used.\n\nThe basic egg block in the :file:`development.ini` for a `helloworld` project:\n\n\n.. code-block :: ini\n    \n    [app:main]\n    use = egg:helloworld\n\nThat will tell paster that it should load the helloworld :term:`egg` to locate\na WSGI application. A new Pylons application includes a line in the\n:file:`setup.py` that indicates what function should be called to make the\nWSGI application:\n\n.. code-block :: python\n    \n    entry_points=\"\"\"\n    [paste.app_factory]\n    main = helloworld.config.middleware:make_app\n\n    [paste.app_install]\n    main = pylons.util:PylonsInstaller\n    \"\"\",\n\nHere, the `make_app` function is specified as the `main` WSGI application that\nPaste (the package that :command:`paster` comes from) should use.\n\nThe `make_app` function from the project is then called, and the server (by\ndefault, a HTTP server) runs the WSGI application.\n"
  },
  {
    "path": "pylons/docs/en/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Pylons documentation build configuration file, created by\n# sphinx-quickstart on Mon Apr 21 20:41:33 2008.\n#\n# This file is execfile()d with the current directory set to its containing dir.\n#\n# The contents of this file are pickled, so don't put values in the namespace\n# that aren't pickleable (module imports are okay, they're removed automatically).\n#\n# All configuration values have a default value; values that are commented out\n# serve to show the default value.\n\nimport sys, os\n\n# If your extensions are in another directory, add it here.\n#sys.path.append('some/directory')\nsys.path.append(os.path.dirname(os.path.abspath(__file__)))\n\n\n# General configuration\n# ---------------------\n\n# Add any Sphinx extension module names here, as strings. They can be extensions\n# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']\n\nintersphinx_mapping = {\n    'http://www.sqlalchemy.org/docs/': None,\n    'http://sluggo.scrapping.cc/python/WebHelpers/': None,\n    'http://routes.groovie.org/': None,\n    'http://beaker.groovie.org/': None,\n}\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General substitutions.\nproject = 'Pylons Framework'\ncopyright = '2008-2015, Ben Bangert, James Gardner, Philip Jenvey'\n\n# The default replacements for |version| and |release|, also used in various\n# other places throughout the built documents.\n#\n# The short X.Y version.\nversion = '1.0.2'\n# The full version, including alpha/beta/rc tags.\nrelease = '1.0.2'\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\ntoday_fmt = '%B %d, %Y'\n\n# List of documents that shouldn't be included in the build.\n#unused_docs = []\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\n#pygments_style = 'sphinx'\n\n# Options for HTML output\n# -----------------------\n\n# Add and use Pylons theme\nfrom subprocess import call, Popen, PIPE\n\np = Popen('which git', shell=True, stdout=PIPE)\ngit = p.stdout.read().strip()\ncwd = os.getcwd()\n_themes = os.path.join(cwd, '_themes')\n\nif not os.path.isdir(_themes):\n    call([git, 'clone', 'git://github.com/Pylons/pylons_sphinx_theme.git',\n            '_themes'])\nelse:\n    os.chdir(_themes)\n    call([git, 'checkout', 'master'])\n    call([git, 'pull'])\n    os.chdir(cwd)\n\nsys.path.append(os.path.abspath('_themes'))\nhtml_theme_path = ['_themes']\nhtml_theme = 'pylonsfw'\nhtml_theme_options = dict(\n    github_url='https://github.com/Pylons/pylons'\n    )\n\n# The style sheet to use for HTML and HTML Help pages. A file of that name\n# must exist either in Sphinx' static/ path, or in one of the custom paths\n# given in html_static_path.\n#html_style = 'default.css'\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\nhtml_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Content template for the index page.\n#html_index = ''\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_use_modindex = True\n\n# If true, the reST sources are included in the HTML build as _sources/<name>.\n#html_copy_source = True\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'Pylonsfwdoc'\n\n\n# Options for LaTeX output\n# ------------------------\n\n# The paper size ('letter' or 'a4').\nlatex_paper_size = 'letter'\n\n# The font size ('10pt', '11pt' or '12pt').\n#latex_font_size = '10pt'\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, document class [howto/manual]).\nlatex_documents = [\n  ('index', 'Pylons.tex', 'Pylons Reference Documentation',\n   'Ben Bangert, Graham Higgins, James Gardner, Philip Jenvey', 'manual',\n   'toctree_only'),\n]\n\n# Additional stuff for the LaTeX preamble.\nlatex_preamble = '''\n\\usepackage{palatino}\n\\definecolor{TitleColor}{rgb}{0.7,0,0}\n\\definecolor{InnerLinkColor}{rgb}{0.7,0,0}\n\\definecolor{OuterLinkColor}{rgb}{0.8,0,0}\n\\definecolor{VerbatimColor}{rgb}{0.985,0.985,0.985}\n\\definecolor{VerbatimBorderColor}{rgb}{0.8,0.8,0.8}\n'''\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\nlatex_use_modindex = False\n"
  },
  {
    "path": "pylons/docs/en/configuration.rst",
    "content": ".. _configuration:\n\n=============\nConfiguration\n=============\n\nPylons comes with two main ways to configure an application:\n\n* The configuration file (:ref:`run-config`)\n* The application's ``config`` directory\n\nThe files in the ``config`` directory change certain aspects of how the application behaves. Any options that the webmaster should be able to change during deployment should be specified in a configuration file.\n\n.. tip::\n    A good indicator of whether an option should be set in the ``config`` directory code vs. the configuration file is whether or not the option is necessary for the functioning of the application. If the application won't function without the setting, it belongs in the appropriate :file:`config/` directory file. If the option should be changed depending on deployment, it belongs in the :ref:`run-config`.\n\nThe applications :file:`config/` directory includes:\n\n* :file:`config/environment.py` described in :ref:`environment-config`\n* :file:`config/middleware.py` described in :ref:`middleware-config`\n* :file:`config/deployment.ini_tmpl` described in :ref:`production-config`\n* :file:`config/routing.py` described in :ref:`url-config`\n\nEach of these files allows developers to change key aspects of how the application behaves.\n \n.. _run-config:\n\n*********************\nRuntime Configuration\n*********************\n\nWhen a new project is created a sample configuration file called :file:`development.ini` is automatically produced as one of the project files. This default configuration file contains sensible options for development use, for example when developing a Pylons application it is very useful to be able to see a debug report every time an error occurs. The :file:`development.ini` file includes options to enable debug mode so these errors are shown.\n\nSince the configuration file is used to determine which application is run, multiple configuration files can be used to easily toggle sets of options. Typically a developer might have a ``development.ini`` configuration file for testing and a ``production.ini`` file produced by the :command:`paster make-config` command for testing the command produces sensible production output. A :file:`test.ini` configuration is also included in the project for test-specific options.\n\nTo specify a configuration file to use when running the application, change the last part of the :command:`paster serve` to include the desired config file:\n\n.. code-block :: bash \n\n    $ paster serve production.ini\n\n.. seealso::\n    Configuration file format **and options** are described in great detail in the `Paste Deploy documentation <http://pythonpaste.org/deploy/>`_.\n\n\nGetting Information From Configuration Files\n============================================\n\nAll information from the configuration file is available in the ``pylons.config`` object. ``pylons.config`` also contains application configuration as defined in the project's :file:`config.environment` module. \n\n.. code-block :: python\n\n    from pylons import config \n\n``pylons.config`` behaves like a dictionary. For example, if the configuration file has an entry under the ``[app:main]`` block:\n\n.. code-block :: ini\n\n    cache_dir = %(here)s/data\n\nThat can then be read in the projects code:\n\n.. code-block :: python\n\n    from pylons import config \n    cache_dir = config['cache.dir']\n\nOr the current debug status like this: \n\n.. code-block :: python \n\n    debug = config['debug']\n\nEvaluating Non-string Data in Configuration Files\n-------------------------------------------------\n\nBy default, all the values in the configuration file are considered strings.\nTo make it easier to handle boolean values, the Paste library comes with a\nfunction that will convert ``true`` and ``false`` to proper Python boolean\nvalues:\n\n.. code-block :: python\n    \n    from paste.deploy.converters import asbool\n    \n    debug = asbool(config['debug'])\n\nThis is used already in the default projects' :ref:`middleware-config` to\ntoggle middleware that should only be used in development mode (with\n``debug``) set to true.\n\n\n.. _production-config:\n\nProduction Configuration Files\n==============================\n\nTo change the defaults of the configuration INI file that should be used when deploying the application, edit the :file:`config/deployment.ini_tmpl` file. This is the file that will be used as a template during deployment, so that the person handling deployment has a starting point of the minimum options the application needs set.\n\nOne of the most important options set in the deployment ini is the ``debug = true`` setting. The email options should be setup so that errors can be e-mailed to the appropriate developers or webmaster in the event of an application error.\n\nGenerating the Production Configuration\n---------------------------------------\n\nTo generate the production.ini file from the projects' :file:`config/deployment.ini_tmpl` it must first be installed either as an :term:`egg` or under development mode. Assuming the name of the Pylons application is ``helloworld``, run:\n\n.. code-block :: bash\n\n    $ paster make-config helloworld production.ini\n\n.. note::\n    This command will also work from inside the project when its being developed.\n\nIt is the responsibility of the developer to ensure that a sensible set of default configuration values exist when the webmaster uses the ``paster make-config`` command. \n\n.. warning::\n    **Always** make sure that the ``debug`` is set to ``false`` when deploying a Pylons application.\n\n\n.. _environment-config:\n\n***********\nEnvironment\n***********\n\nThe :file:`config/environment.py` module sets up the basic Pylons environment\nvariables needed to run the application. Objects that should be setup once\nfor the entire application should either be setup here, or in the\n:file:`lib/app_globals` :meth:`__init__` method.\n\nIt also calls the :ref:`url-config` function to setup how the URL's will\nbe matched up to :ref:`controllers`, creates the :term:`app_globals`\nobject, configures which module will be referred to as :term:`h`, and is\nwhere the template engine is setup.\n\nWhen using SQLAlchemy it's recommended that the SQLAlchemy engine be setup\nin this module. The default SQLAlchemy configuration that Pylons comes\nwith creates the engine here which is then used in :file:`model/__init__.py`.\n\n\n.. _url-config:\n\n*****************\nURL Configuration\n*****************\n\nA Python library called Routes handles mapping URLs to controllers and their methods, or their :term:`action` as Routes refers to them. By default, Pylons sets up the following :term:`route`\\s (found in :file:`config/routing.py`):\n\n.. code-block:: python\n\n    map.connect('/{controller}/{action}')\n    map.connect('/{controller}/{action}/{id}')\n\n.. versionchanged:: 0.9.7\n    Prior to Routes 1.9, all map.connect statements required variable parts\n    to begin with a ``:`` like ``map.connect(':controller/:action')``. This\n    syntax is now optional, and the new ``{}`` syntax is recommended.\n\nAny part of the path inside the curly braces is a variable (a `variable part`\n) that will match\nany text in the URL for that 'part'. A 'part' of the URL is the text between\ntwo forward slashes. Every part of the URL must be present for the\n:term:`route` to match, otherwise a 404 will be returned.\n\nThe routes above are translated by the Routes library into regular expressions\nfor high performance URL matching. By default, all the variable parts (except\nfor the special case of ``{controller}``) become a matching regular expression\nof ``[^/]+`` to match anything except for a forward slash. This can be\nchanged easily, for example to have the ``{id}`` only match digits:\n\n.. code-block :: python\n    \n    map.connect('/{controller}/{action}/{id:\\d+}')\n\nIf the desired regular expression includes the ``{}``, then it should be\nspecified separately for the variable part. To limit the ``{id}`` to only\nmatch at least 2-4 digits:\n\n.. code-block :: python\n    \n    map.connect('/{controller}/{action}/{id}',  requirements=dict(id='\\d{2,4}'))\n\nThe controller and action can also be specified as keyword arguments so that\nthey don't need to be included in the URL:\n\n.. code-block :: python\n    \n    # Archives by 2 digit year -> /archives/08\n    map.connect('/archives/{year:\\d\\d}', controller='articles',  action='archives')\n\nAny variable part, or keyword argument in the ``map.connect`` statement will\nbe available for use in the\naction used. For the route above, which resolves to the `articles`\ncontroller:\n\n.. code-block :: python\n    \n    class ArticlesController(BaseController):\n\n        def archives(self, year):\n            ...\n\nThe part of the URL that matched as the year is available by name in the\nfunction argument.\n\n.. note::\n    Routes also includes the ability to attempt to 'minimize' the URL. This\n    behavior is generally not intuitive, and starting in Pylons 0.9.7 is\n    turned off by default with the ``map.minimization=False`` setting.\n\nThe default mapping can match to any controller and any of their\nactions which means the following URLs will match:\n\n.. code-block:: text\n\n    /hello/index       >>    controller: hello, action: index\n    /entry/view/4      >>    controller: entry, action: view, id:4\n    /comment/edit/2    >>    controller: comment, action: edit, id:2\n\nThis simple scheme can be suitable for even large applications when complex URL's aren't needed.\n\nControllers can be organized into directories as well. For example, if the admins should have a separate ``comments`` controller:\n\n.. code-block:: bash\n    \n    $ paster controller admin/comments\n\nWill create the ``admin`` directory along with the appropriate ``comments``\ncontroller under it. To get to the comments controller:\n\n.. code-block:: text\n    \n    /admin/comments/index    >>    controller: admin/comments, action: index\n\n.. note::\n    The ``{controller}`` match is special, in that it doesn't always stop\n    at the next forward slash (``/``). As the example above demonstrates,\n    it is able to match controllers nested under a directory should they\n    exist.\n\nAdding a route to match ``/``\n=============================\n\nThe controller and action can be specified directly in the :meth:`map.connect`\nstatement, as well as the raw URL to be matched:\n\n.. code-block:: python\n\n    map.connect('/', controller='main', action='index')\n\nresults in ``/`` being handled by the ``index`` method of the ``main``\ncontroller.\n\n.. note::\n    By default, projects' static files (in the :file:`public/` directory) are\n    served in preference to controllers. New Pylons projects include a welcome\n    page (:file:`public/index.html`) that shows up at the ``/`` url. You'll\n    want to remove this file before mapping a route there.\n\nGenerating URLs\n===============\n\nURLs are generated via the callable :class:`routes.util.URLGenerator`\nobject. Pylons provides an instance of this special object at\n:data:`pylons.url`. It accepts keyword arguments indicating the desired\ncontroller, action and additional variables defined in a route.\n\n.. code-block:: python\n    \n    # generates /content/view/2\n    url(controller='content', action='view', id=2)   \n\nTo generate the URL of the matched route of the current request, call\n:meth:`routes.util.URLGenerator.current`:\n\n.. code-block:: python\n\n    # Generates /content/view/3 during a request for /content/view/3\n    url.current()\n\n:meth:`routes.util.URLGenerator.current` also accepts the same arguments as\n`url()`. This uses `Routes memory\n<http://routes.groovie.org/manual.html#route-memory>`_ to generate a small\nchange to the current URL without the need to specify all the relevant\narguments:\n\n.. code-block:: python\n\n    # Generates /content/view/2 during a request for /content/view/3\n    url.current(id=2)\n\n.. seealso::\n\n    `Routes manual <http://routes.groovie.org/manual.html>`_\n    Full details and source code.\n\n\n.. _middleware-config:\n\n**********\nMiddleware\n**********\n\nA projects WSGI stack should be setup in the :file:`config/middleware.py`\nmodule. Ideally this file should import middleware it needs, and set it up\nin the `make_app` function.\n\nThe default stack that is setup for a Pylons application is described in\ndetail in :ref:`wsgi-middleware`.\n\nDefault middleware stack:\n\n.. code-block :: python\n\n    # The Pylons WSGI app\n    app = PylonsApp()\n    \n    # Routing/Session/Cache Middleware\n    app = RoutesMiddleware(app, config['routes.map'])\n    app = SessionMiddleware(app, config)\n    app = CacheMiddleware(app, config)\n    \n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n    \n    if asbool(full_stack):\n        # Handle Python exceptions\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n        # Display error documents for 401, 403, 404 status codes (and\n        # 500 when debug is disabled)\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])\n\n    # Establish the Registry for this application\n    app = RegistryManager(app)\n\n    if asbool(static_files):\n        # Serve static files\n        static_app = StaticURLParser(config['pylons.paths']['static_files'])\n        app = Cascade([static_app, app])\n\n    return app\n    \nSince each piece of middleware wraps the one before it, the stack needs to be\nassembled in reverse order from the order in which its called. That is, the\nvery last middleware that wraps the WSGI Application, is the very first that\nwill be called by the server.\n\nThe last piece of middleware in the stack, called Cascade, is used to\nserve static content files during development. For top performance,\nconsider disabling the Cascade middleware via setting the\n``static_files = false`` in the configuration file. Then have the\nwebserver or a :term:`CDN` serve static files.\n\n.. warning::\n\n    When unsure about whether or not to change the middleware, **don't**. The\n    order of the middleware is important to the proper functioning of a\n    Pylons application, and shouldn't be altered unless needed.\n\nAdding custom middleware\n========================\n\nCustom middleware should be included in the :file:`config/middleware.py` at\ncomment marker::\n\n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n\nFor example, to add a middleware component named `MyMiddleware`,\ninclude it in :file:`config/middleware.py`::\n\n    # The Pylons WSGI app\n    app = PylonsApp()\n    \n    # Routing/Session/Cache Middleware\n    app = RoutesMiddleware(app, config['routes.map'])\n    app = SessionMiddleware(app, config)\n    app = CacheMiddleware(app, config)\n    \n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n    app = MyMiddleware(app)\n    \nThe app object is simply passed as a parameter to the `MyMiddleware` middleware which in turn should return a wrapped WSGI application.\n\nCare should be taken when deciding in which layer to place custom\nmiddleware. In most cases middleware should be placed before the Pylons WSGI\napplication and its supporting Routes/Session/Cache middlewares, however if the\nmiddleware should run *after* the CacheMiddleware::\n\n    # Routing/Session/Cache Middleware\n    app = RoutesMiddleware(app, config['routes.map'])\n    app = SessionMiddleware(app, config)\n    \n    # MyMiddleware can only see the cache object, nothing *above* here\n    app = MyMiddleware(app)\n    \n    app = CacheMiddleware(app, config)\n\nWhat is full_stack?\n===================\n\nIn the Pylons ini file {:file:`development.ini` or :file:`production.ini`} this block determines if the flag full_stack is set to true or false::\n\n    [app:main]\n    use = egg:app_name\n    full_stack = true\n\nThe full_stack flag determines if the ErrorHandler and StatusCodeRedirect is included as a layer in the middleware wrapping process. The only condition in which this option would be set to `false` is if multiple Pylons applications are running and will be wrapped in the appropriate middleware elsewhere.\n\n\n.. _setup-config:\n\n*****************\nApplication Setup\n*****************\n\nThere are two kinds of 'Application Setup' that are occasionally referenced\nwith regards to a project using Pylons.\n\n* Setting up a new application\n* Configuring project information and package dependencies\n\nSetting Up a New Application\n============================\n\nTo make it easier to setup a new instance of a project, such as setting up\nthe basic database schema, populating necessary defaults, etc. a setup\nscript can be created.\n\nIn a Pylons project, the setup script to be run is located in the projects'\n:file:`websetup.py` file. The default script loads the projects configuration\nto make it easier to write application setup steps:\n\n.. code-block :: python\n    \n    import logging\n\n    from helloworld.config.environment import load_environment\n\n    log = logging.getLogger(__name__)\n\n    def setup_app(command, conf, vars):\n        \"\"\"Place any commands to setup helloworld here\"\"\"\n        load_environment(conf.global_conf, conf.local_conf)\n\n.. note::\n    If the project was configured during creation to use SQLAlchemy this file\n    will include some commands to setup the database connection to make it\n    easier to setup database tables.\n\nTo run the setup script using the development configuration:\n\n.. code-block :: bash\n    \n    $ paster setup-app development.ini\n\nConfiguring the Package\n=======================\n\nA newly created project with Pylons is a standard Python package. As a Python\npackage, it has a :file:`setup.py` file that records meta-information about\nthe package. Most of the options in it are fairly self-explanatory, the most\nimportant being the 'install_requires' option:\n\n.. code-block :: python\n    \n    install_requires=[\n        \"Pylons>=0.9.7\",\n    ],\n    \nThese lines indicate what packages are required for the proper functioning\nof the application, and should be updated as needed. To re-parse the\n:file:`setup.py` line for new dependencies:\n\n.. code-block :: bash\n\n    $ python setup.py develop\n\nIn addition to updating the packages as needed so that the dependency\nrequirements are made, this command will ensure that this package is active\nin the system (without requiring the traditional\n:command:`python setup.py install`).\n\n.. seealso::\n    `Declaring Dependencies <http://peak.telecommunity.com/DevCenter/setuptools#declaring-dependencies>`_\n"
  },
  {
    "path": "pylons/docs/en/controllers.rst",
    "content": ".. _controllers:\n\n===========\nControllers\n===========\n\n.. image:: _static/pylon2.jpg\n   :alt: \n   :align: left\n   :height: 450px\n   :width: 368px\n\nIn the :term:`MVC` paradigm the *controller* interprets the inputs, commanding\nthe model and/or the view to change as appropriate. Under Pylons, this concept\nis extended slightly in that a Pylons controller is not directly interpreting\nthe client's request, but is acting to determine the appropriate way to\nassemble data from the model, and render it with the correct template.\n\nThe controller interprets requests from the user and calls portions of the model and view as necessary to fulfill the request. So when the user clicks a Web link or submits an HTML form, the controller itself doesn’t output anything or perform any real processing. It takes the request and determines which model components to invoke and which formatting to apply to the resulting data.\n\nPylons uses a class, where the superclass provides the :term:`WSGI` interface\nand the subclass implements the application-specific controller logic.\n\nThe Pylons WSGI Controller handles incoming web requests that are dispatched from the Pylons WSGI application :class:`~pylons.wsgiapp.PylonsApp`.\n\nThese requests result in a new instance of the :class:`~pylons.controllers.core.WSGIController` being created, which is then called with the dict options from the Routes match. The standard WSGI response is then returned with start_response called as per the WSGI spec.\n\nSince Pylons controllers are actually called with the WSGI interface, normal WSGI applications can also be Pylons ‘controllers’.\n\nStandard Controllers\n====================\n\nStandard Controllers intended for subclassing by web developers\n\nKeeping methods private\n-----------------------\n\nThe default route maps any controller and action, so you will likely want to\nprevent some controller methods from being callable from a URL.\n\nPylons uses the default Python convention of private methods beginning with\n``_``. To hide a method ``edit_generic`` in this class, just changing its name\nto begin with ``_`` will be sufficient:\n\n.. code-block:: python\n\n    class UserController(BaseController):\n        def index(self):\n            return \"This is the index.\"\n\n        def _edit_generic(self):\n            \"\"\"I can't be called from the web!\"\"\"\n            return True\n\nSpecial methods\n---------------\n\nSpecial controller methods you may define:\n\n``__before__``\n    This method is called before your action is, and should be used for\n    setting up variables/objects, restricting access to other actions,\n    or other tasks which should be executed before the action is called.\n\n``__after__``\n    This method is called after the action is, unless an unexpected\n    exception was raised. Subclasses of\n    :class:`~webob.exc.HTTPException` (such as those raised by\n    ``redirect_to`` and ``abort``) are expected; e.g. ``__after__``\n    will be called on redirects.\n    \nAdding Controllers dynamically\n------------------------------\n\nIt is possible for an application to add controllers without restarting the application. This requires telling Routes to re-scan the controllers directory.\n\nNew controllers may be added from the command line with the paster command (recommended as that also creates the test harness file), or any other means of creating the controller file.\n\nFor Routes to become aware of new controllers present in the controller directory, an internal flag is toggled to indicate that Routes should rescan the directory:\n\n.. code-block:: python\n\n    from routes import request_config\n\n    mapper = request_config().mapper\n    mapper._created_regs = False\n\n\nOn the next request, Routes will rescan the controllers directory and those routes that use the ``:controller`` dynamic part of the path will be able to match the new controller.\n\nCustomizing the Controller Name\n-------------------------------\n\nBy default, Pylons looks for a controller named 'Something'Controller. This\nnaming scheme can be overridden by supplying an optional module-level variable\ncalled ``__controller__`` to indicate the desired controller class::\n    \n    import logging\n\n    from pylons import request, response, session, tmpl_context as c\n    from pylons.controllers.util import abort, redirect_to\n\n    from helloworld.lib.base import BaseController, render\n\n    log = logging.getLogger(__name__)\n    \n    __controller__ = 'Hello'\n\n    class Hello(BaseController):\n\n        def index(self):\n            # Return a rendered template\n            #return render('/hello.mako')\n            # or, return a string\n            return 'Hello World'\n    \n\n\nAttaching WSGI apps\n-------------------\n\n.. note::\n\n    This recipe assumes a basic level of familiarity with the WSGI Specification (PEP 333)\n\nWSGI runs deep through Pylons, and is present in many parts of the architecture. Since Pylons controllers are actually called with the WSGI interface, normal WSGI applications can also be Pylons 'controllers'. \n\nOptionally, if a full WSGI app should be mounted and handle the remainder of the URL, Routes can automatically move the right part of the URL into the :envvar:`SCRIPT_NAME`, so that the WSGI application can properly handle its :envvar:`PATH_INFO` part.\n\nThis recipe will demonstrate adding a basic WSGI app as a Pylons controller. \n\nCreate a new controller file in your Pylons project directory:\n\n.. code-block:: python\n\n    $ paster controller wsgiapp\n\nThis sets up the basic imports that you may want available when using other WSGI applications.\n\nEdit your controller so it looks like this:\n\n.. code-block:: python\n\n    import logging\n\n    from YOURPROJ.lib.base import *\n\n    log = logging.getLogger(__name__)\n\n    def WsgiappController(environ, start_response):\n        start_response('200 OK', [('Content-type', 'text/plain')])\n        return [\"Hello World\"]\n\nWhen hooking up other WSGI applications, they will expect the part of the URL that was used to get to this controller to have been moved into :envvar:`SCRIPT_NAME`. :mod:`Routes <routes>` can properly adjust the environ if a map route for this controller is added to the :file:`config/routing.py` file:\n\n.. code-block:: python\n\n    # CUSTOM ROUTES HERE\n\n    # Map the WSGI application\n    map.connect('wsgiapp/{path_info:.*}', controller='wsgiapp')\n\n\nBy specifying the ``path_info`` dynamic path, Routes will put everything leading up to the ``path_info`` in the :envvar:`SCRIPT_NAME` and the rest will go in the :envvar:`PATH_INFO`.\n\n\nUsing the WSGI Controller to provide a WSGI service\n===================================================\n\nThe Pylons WSGI Controller\n--------------------------\n\nPylons' own WSGI Controller follows the WSGI spec for calling and return\nvalues\n\nThe Pylons WSGI Controller handles incoming web requests that are \ndispatched from ``PylonsApp``. These requests result in a new\ninstance of the ``WSGIController`` being created, which is then called\nwith the dict options from the Routes match. The standard WSGI\nresponse is then returned with :meth:`start_response` called as per\nthe WSGI spec.\n\nWSGIController methods\n----------------------\n\n\nSpecial ``WSGIController`` methods you may define:\n\n``__before__``\n    This method will be run before your action is, and should be\n    used for setting up variables/objects, restricting access to\n    other actions, or other tasks which should be executed before\n    the action is called.\n``__after__``\n    Method to run after the action is run. This method will\n    *always* be run after your method, even if it raises an\n    Exception or redirects.\n    \nEach action to be called is inspected with :meth:`_inspect_call` so\nthat it is only passed the arguments in the Routes match dict that\nit asks for. The arguments passed into the action can be customized\nby overriding the :meth:`_get_method_args` function which is\nexpected to return a dict.\n\nIn the event that an action is not found to handle the request, the\nController will raise an \"Action Not Found\" error if in debug mode,\notherwise a ``404 Not Found`` error will be returned.\n\n.. _rest_controller:\n\nUsing the REST Controller with a RESTful API\n============================================\n\nUsing the paster restcontroller template\n----------------------------------------\n\n.. code-block:: bash\n\n    $ paster restcontroller --help\n\nCreate a REST Controller and accompanying functional test\n\nThe RestController command will create a REST-based Controller file\nfor use with the :meth:`~routes.base.Mapper.resource`\nREST-based dispatching. This template includes the methods that\n:meth:`~routes.base.Mapper.resource` dispatches to in\naddition to doc strings for clarification on when the methods will\nbe called.\n\nThe first argument should be the singular form of the REST\nresource. The second argument is the plural form of the word. If\nits a nested controller, put the directory information in front as\nshown in the second example below.\n\nExample usage:\n\n.. code-block:: bash\n\n    $ paster restcontroller comment comments\n    Creating yourproj/yourproj/controllers/comments.py\n    Creating yourproj/yourproj/tests/functional/test_comments.py\n\nIf you'd like to have controllers underneath a directory, just\ninclude the path as the controller name and the necessary\ndirectories will be created for you:\n\n.. code-block:: bash\n\n    $ paster restcontroller admin/trackback admin/trackbacks\n    Creating yourproj/controllers/admin\n    Creating yourproj/yourproj/controllers/admin/trackbacks.py\n    Creating yourproj/yourproj/tests/functional/test_admin_trackbacks.py\n\nAn Atom-Style REST Controller for Users\n---------------------------------------\n\n.. code-block:: python\n\n    # From http://pylonshq.com/pasties/503\n    import logging\n\n    from formencode.api import Invalid\n    from pylons import url\n    from simplejson import dumps\n\n    from restmarks.lib.base import *\n\n    log = logging.getLogger(__name__)\n\n    class UsersController(BaseController):\n        \"\"\"REST Controller styled on the Atom Publishing Protocol\"\"\"\n        # To properly map this controller, ensure your \n        # config/routing.py file has a resource setup:\n        #     map.resource('user', 'users')\n\n        def index(self, format='html'):\n            \"\"\"GET /users: All items in the collection.<br>\n                @param format the format passed from the URI.\n            \"\"\"\n            #url('users')\n            users = model.User.select()\n            if format == 'json':\n                data = []\n                for user in users:\n                    d = user._state['original'].data\n                    del d['password']\n                    d['link'] = url('user', id=user.name)\n                    data.append(d)\n                response.headers['content-type'] = 'text/javascript'\n                return dumps(data)\n            else:\n                c.users = users\n                return render('/users/index_user.mako')\n\n        def create(self):\n            \"\"\"POST /users: Create a new item.\"\"\"\n            # url('users')\n            user = model.User.get_by(name=request.params['name'])\n            if user:\n                # The client tried to create a user that already exists\n                abort(409, '409 Conflict', \n                      headers=[('location', url('user', id=user.name))])\n            else:\n                try:\n                    # Validate the data that was sent to us\n                    params = model.forms.UserForm.to_python(request.params)\n                except Invalid, e:\n                    # Something didn't validate correctly\n                    abort(400, '400 Bad Request -- %s' % e)\n                user = model.User(**params)\n                model.objectstore.flush()\n                response.headers['location'] = url('user', id=user.name)\n                response.status_code = 201\n                c.user_name = user.name\n                return render('/users/created_user.mako')\n\n        def new(self, format='html'):\n            \"\"\"GET /users/new: Form to create a new item.\n                @param format the format passed from the URI.\n            \"\"\"\n            # url('new_user')\n            return render('/users/new_user.mako')\n\n        def update(self, id):\n            \"\"\"PUT /users/id: Update an existing item.\n                @param id the id (name) of the user to be updated\n            \"\"\"\n            # Forms posted to this method should contain a hidden field:\n            #    <input type=\"hidden\" name=\"_method\" value=\"PUT\" />\n            # Or using helpers:\n            #    h.form(url('user', id=ID),\n            #           method='put')\n            # url('user', id=ID)\n            old_name = id\n            new_name = request.params['name']\n            user = model.User.get_by(name=id)\n\n            if user:\n                if (old_name != new_name) and model.User.get_by(name=new_name):\n                    abort(409, '409 Conflict')\n                else:\n                    params = model.forms.UserForm.to_python(request.params)\n                    user.name = params['name']\n                    user.full_name = params['full_name']\n                    user.email = params['email']\n                    user.password = params['password']\n                    model.objectstore.flush()\n                    if user.name != old_name:\n                        abort(301, '301 Moved Permanently',\n                              [('Location', url('users', id=user.name))])\n                    else:\n                        return\n\n        def delete(self, id):\n            \"\"\"DELETE /users/id: Delete an existing item.\n                @param id the id (name) of the user to be updated\n            \"\"\"\n            # Forms posted to this method should contain a hidden field:\n            #    <input type=\"hidden\" name=\"_method\" value=\"DELETE\" />\n            # Or using helpers:\n            #    h.form(url('user', id=ID),\n            #           method='delete')\n            # url('user', id=ID)\n            user = model.User.get_by(name=id)\n            user.delete()\n            model.objectstore.flush()\n            return\n\n        def show(self, id, format='html'):\n            \"\"\"GET /users/id: Show a specific item.\n                @param id the id (name) of the user to be updated.\n                @param format the format of the URI requested.\n            \"\"\"\n            # url('user', id=ID)\n            user = model.User.get_by(name=id)\n            if user:\n                if format=='json':\n                    data = user._state['original'].data\n                    del data['password']\n                    data['link'] = url('user', id=user.name)\n                    response.headers['content-type'] = 'text/javascript'\n                    return dumps(data)\n                else:\n                    c.data = user\n                    return render('/users/show_user.mako')\n            else:\n                abort(404, '404 Not Found')\n\n        def edit(self, id, format='html'):\n            \"\"\"GET /users/id;edit: Form to edit an existing item.\n                @param id the id (name) of the user to be updated.\n                @param format the format of the URI requested.\n            \"\"\"\n            # url('edit_user', id=ID)\n            user = model.User.get_by(name=id)\n            if not user:\n                abort(404, '404 Not Found')\n            # Get the form values from the table\n            c.values = model.forms.UserForm.from_python(user.__dict__)\n            return render('/users/edit_user.mako')\n\n.. _xmlrpc_controller:\n\nUsing the XML-RPC Controller for XML-RPC requests\n================================================= \n\nIn order to deploy this controller you will need at least a passing familiarity with XML-RPC itself. We will first review the basics of XML-RPC and then describe the workings of the ``Pylons XMLRPCController``. Finally, we will show an example of how to use the controller to implement a simple web service. \n\nAfter you've read this document, you may be interested in reading the companion document: \"A blog publishing web service in XML-RPC\" which takes the subject further, covering details of the MetaWeblog API (a popular XML-RPC service) and demonstrating how to construct some basic service methods to act as the core of a MetaWeblog blog publishing service. \n\nA brief introduction to XML-RPC\n------------------------------- \n\nXML-RPC is a specification that describes a Remote Procedure Call (RPC) interface by which an application can use the Internet to execute a specified procedure call on a remote XML-RPC server. The name of the procedure to be called and any required parameter values are \"marshalled\" into XML. The XML forms the body of a POST request which is despatched via HTTP to the XML-RPC server. At the server, the procedure is executed, the returned value(s) is/are marshalled into XML and despatched back to the application. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned. \n\nXML-RPC Controller that speaks WSGI \n-----------------------------------\n\nPylons uses Python's xmlrpclib library to provide a specialised :class:`XMLRPCController` class that gives you the full range of these XML-RPC Introspection facilities for use in your service methods and provides the foundation for constructing a set of specialised service methods that provide a useful web service --- such as a blog publishing interface. \n\nThis controller handles XML-RPC responses and complies with the `XML-RPC Specification <http://www.xmlrpc.com/spec>`_ as well as the `XML-RPC Introspection <http://scripts.incutio.com/xmlrpc/introspection.html>`_ specification. \n\nAs part of its basic functionality an XML-RPC server provides three standard introspection procedures or \"service methods\" as they are called. The Pylons :class:`XMLRPCController` class provides these standard service methods ready-made for you: \n\n* :meth:`system.listMethods` Returns a list of XML-RPC methods for this XML-RPC resource \n* :meth:`system.methodSignature` Returns an array of arrays for the valid signatures for a method. The first value of each array is the return value of the method. The result is an array to indicate multiple signatures a method may be capable of. \n* :meth:`system.methodHelp` Returns the documentation for a method \n\nBy default, methods with names containing a dot are translated to use an underscore. For example, the ``system.methodHelp`` is handled by the method :meth:`system_methodHelp`. \n\nMethods in the XML-RPC controller will be called with the method given in the XML-RPC body. Methods may be annotated with a signature attribute to declare the valid arguments and return types. \n\nFor example:\n\n.. code-block:: python\n\n    class MyXML(XMLRPCController): \n        def userstatus(self): \n            return 'basic string' \n        userstatus.signature = [['string']] \n\n        def userinfo(self, username, age=None): \n            user = LookUpUser(username) \n            result = {'username': user.name} \n            if age and age > 10: \n                result['age'] = age \n            return result \n        userinfo.signature = [['struct', 'string'], \n                              ['struct', 'string', 'int']]\n\n\nSince XML-RPC methods can take different sets of data, each set of valid arguments is its own list. The first value in the list is the type of the return argument. The rest of the arguments are the types of the data that must be passed in. \n\nIn the last method in the example above, since the method can optionally take an integer value, both sets of valid parameter lists should be provided. \n\nValid types that can be checked in the signature and their corresponding Python types: \n\n+--------------------+--------------------+\n| XMLRPC             | Python             |\n+====================+====================+\n| string             | str                |\n+--------------------+--------------------+\n| array              | list               |\n+--------------------+--------------------+\n| boolean            | bool               |\n+--------------------+--------------------+\n| int                | int                |\n+--------------------+--------------------+\n| double             | float              |\n+--------------------+--------------------+\n| struct             | dict               |\n+--------------------+--------------------+\n| dateTime.iso8601   | xmlrpclib.DateTime |\n+--------------------+--------------------+\n| base64             | xmlrpclib.Binary   |\n+--------------------+--------------------+\n\nNote, requiring a signature is optional. \n\nAlso note that a convenient fault handler function is provided. \n\n.. code-block:: python \n\n    def xmlrpc_fault(code, message): \n        \"\"\"Convenience method to return a Pylons response XMLRPC Fault\"\"\" \n\n(The `XML-RPC Home page <http://www.xmlrpc.com/>`_ and the `XML-RPC HOW-TO <http://www.faqs.org/docs/Linux-HOWTO/XML-RPC-HOWTO.html>`_ both provide further detail on the XML-RPC specification.) \n\nA simple XML-RPC service  \n------------------------\n\nThis simple service ``test.battingOrder`` accepts a positive integer < 51 as the parameter ``posn`` and returns a string containing the name of the US state occupying that ranking in the order of ratifying the constitution / joining the union. \n\n.. code-block:: python\n \n    import xmlrpclib\n\n    from pylons import request\n    from pylons.controllers import XMLRPCController\n\n    states = ['Delaware', 'Pennsylvania', 'New Jersey', 'Georgia',\n              'Connecticut', 'Massachusetts', 'Maryland', 'South Carolina',\n              'New Hampshire', 'Virginia', 'New York', 'North Carolina',\n              'Rhode Island', 'Vermont', 'Kentucky', 'Tennessee', 'Ohio',\n              'Louisiana', 'Indiana', 'Mississippi', 'Illinois', 'Alabama',\n              'Maine', 'Missouri', 'Arkansas', 'Michigan', 'Florida', 'Texas',\n              'Iowa', 'Wisconsin', 'California', 'Minnesota', 'Oregon',\n              'Kansas', 'West Virginia', 'Nevada', 'Nebraska', 'Colorado',\n              'North Dakota', 'South Dakota', 'Montana', 'Washington', 'Idaho',\n              'Wyoming', 'Utah', 'Oklahoma', 'New Mexico', 'Arizona', 'Alaska',\n              'Hawaii'] \n\n    class RpctestController(XMLRPCController): \n\n        def test_battingOrder(self, posn): \n            \"\"\"This docstring becomes the content of the \n            returned value for system.methodHelp called with \n            the parameter \"test.battingOrder\"). The method \n            signature will be appended below ... \n            \"\"\" \n            # XML-RPC checks agreement for arity and parameter datatype, so \n            # by the time we get called, we know we have an int. \n            if posn > 0 and posn < 51: \n                return states[posn-1] \n            else: \n                # Technically, the param value is correct: it is an int. \n                # Raising an error is inappropriate, so instead we \n                # return a facetious message as a string. \n                return 'Out of cheese error.' \n        test_battingOrder.signature = [['string', 'int']] \n\n\nTesting the service\n-------------------\n\nFor developers using OS X, there's an `XML/RPC client <http://www.ditchnet.org/xmlrpc/>`_ that is an extremely useful diagnostic tool when developing XML-RPC (it's free ... but not entirely bug-free). Or, you can just use the Python interpreter: \n\n.. code-block:: pycon\n\n    >>> from pprint import pprint \n    >>> import xmlrpclib \n    >>> srvr = xmlrpclib.Server(\"http://example.com/rpctest/\") \n    >>> pprint(srvr.system.listMethods()) \n    ['system.listMethods', \n     'system.methodHelp', \n     'system.methodSignature', \n     'test.battingOrder'] \n    >>> print srvr.system.methodHelp('test.battingOrder') \n    This docstring becomes the content of the \n    returned value for system.methodHelp called with \n    the parameter \"test.battingOrder\"). The method \n    signature will be appended below ... \n\n    Method signature: [['string', 'int']] \n    >>> pprint(srvr.system.methodSignature('test.battingOrder')) \n    [['string', 'int']] \n    >>> pprint(srvr.test.battingOrder(12)) \n    'North Carolina' \n\nTo debug XML-RPC servers from Python, create the client object using the optional verbose=1 parameter. You can then use the client as normal and watch as the XML-RPC request and response is displayed in the console. \n"
  },
  {
    "path": "pylons/docs/en/debugging.rst",
    "content": ".. _debugging:\n\n======================================\nErrors, Troubleshooting, and Debugging\n======================================\n\nWhen a web application has an error in production, a few different options for handling it are available. Pylons comes with error handlers to allow the following options:\n\n* E-mail the traceback as HTML to the administrators\n* Show the :ref:`interactive_debugging` interface to the developer\n* Programmatically handle the error in another controller\n* Display a plain error on the web page\n\nSome of these options can be combined by enabling or disabling the appropriate middleware.\n\nError Middleware\n================\n\nIn a new Pylons project, the error handling middleware is configured in the projects :file:`config/middleware.py`::\n    \n    # Excerpt of applicable section\n    \n    if asbool(full_stack):\n        # Handle Python exceptions\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n        # Display error documents for 401, 403, 404 status codes (and\n        # 500 when debug is disabled)\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])\n    \nThe first middleware configured, :func:`~pylons.middleware.ErrorHandler`, actually configures one of two :mod:`WebError <weberror>` middlewares depending on whether the project is in ``debug`` mode or not. If it is in ``debug`` mode, then the :ref:`interactive_debugging` is enabled, otherwise, the :ref:`e-mail error handling <error_emails>` will be used.\n\nThe second middleware configured is the :class:`~pylons.middleware.StatusCodeRedirect` middleware. This middleware watches the request, and if the application returns a response containing one of the status code's listed, it will call back into the application to the error controller, and use that output instead.\n\nNone of these are required for a Pylons project to run, and commenting them all out results in the plain text of the error to display on the web page.\n\n.. warning::\n    \n    If no middleware at all is used, the error will appear on the screen in\n    its entirety, *including full traceback output*.\n\nRecommended Configurations\n--------------------------\n\n* For plain-text output or errors and non-200 status codes, comment out the :class:`~pylons.middleware.StatusCodeRedirect`. Tracebacks will be e-mailed to you in production, and the :ref:`interactive_debugging` will be used during development.\n\n* For programmatic error and non-200 status code handling, keep the stack as-is.\n\n* To *not* have tracebacks e-mailed, remove only the :func:`~pylons.middleware.ErrorHandler` middleware. This will also disable :ref:`interactive_debugging` however. To retain :ref:`interactive_debugging` but disable traceback e-mails::\n    \n    if asbool(config['debug']):\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n.. note::\n    \n    To only capture specific non-200 status codes, the :class:`~pylons.middleware.StatusCodeRedirect` middleware can be passed a list of the codes that it should intercept and redirect to the error controller. When in non-debug mode, it captures the 400-404, and 500 status codes. Altering the list will capture more or less types of requests as desired.\n\nAvoiding Displaying Tracebacks\n------------------------------\n\nWhen disabling the :func:`~pylons.middleware.ErrorHandler` middleware, a replacement middleware should be created and used that captures exceptions and changes them into a normal WSGI response, otherwise the raw traceback error will be displayed on the browser.\n\nAn example middleware that just captures exceptions and changes them to a 500 error::\n    \n    from webob import Request, Response\n    \n    class EatExceptions(object):\n        def __init__(self, app):\n            self.app = app\n        \n        def __call__(self, environ, start_response):\n            req = Request(environ)\n            try:\n                response = req.get_response(self.app)    \n            except:\n                response = Response()\n                response.status_int = 500\n                response.body = 'An error has occured'\n            return response(environ, start_response)\n\nReplacing the ``ErrorHandler`` with this middleware will cause tracebacks to not be displayed to the user.\n\n\n.. _interactive_debugging:\n\nInteractive Debugging\n=====================\n\nThings break, and when they do, quickly pinpointing what went wrong and why makes a huge difference. By default, Pylons uses a customized version of `Ian Bicking's <http://blog.ianbicking.org/>`_ EvalException middleware that also includes full Mako/Myghty Traceback information. \n\n\nThe Debugging Screen \n-------------------- \n\nThe debugging screen has three tabs at the top: \n\n``Traceback`` \nProvides the raw exception trace with the interactive debugger \n\n``Extra Data`` \nDisplays CGI, WSGI variables at the time of the exception, in addition to configuration information \n\n``Template`` \nHuman friendly traceback for Mako or Myghty templates \n\nSince Mako and Myghty compile their templates to Python modules, it can be difficult to accurately figure out what line of the template resulted in the error. The `Template` tab provides the full Mako or Myghty traceback which contains accurate line numbers for your templates, and where the error originated from. If your exception was triggered before a template was rendered, no Template information will be available in this section. \n\nExample: Exploring the Traceback \n-------------------------------- \n\nUsing the interactive debugger can also be useful to gain a deeper insight into objects present only during the web request like the ``session`` and ``request`` objects. \n\nTo trigger an error so that we can explore what's happening just raise an exception inside an action you're curious about. In this example, we'll raise an error in the action that's used to display the page you're reading this on. Here's what the docs controller looks like: \n\n.. code-block:: python \n\n    class DocsController(BaseController): \n        def view(self, url): \n            if request.path_info.endswith('docs'): \n                redirect(url('/docs/'))\n            return render('/docs/' + url) \n\nSince we want to explore the ``session`` and ``request``, we'll need to bind them first. Here's what our action now looks like with the binding and raising an exception: \n\n.. code-block:: python \n\n    def view(self, url): \n        raise \"hi\" \n        if request.path_info.endswith('docs'): \n            redirect(url('/docs/'))\n        return render('/docs/' + url) \n\nHere's what exploring the Traceback from the above example looks like (Excerpt of the relevant portion): \n\n.. image:: _static/doctraceback.png\n    :width: 750px\n    :height: 260px\n\n.. _error_emails:\n\nE-mailing Errors\n================\n\nYou can make various of changes to how the debugging works. For example if you disable the ``debug`` variable in the config file Pylons will email you an error report instead of displaying it as long as you provide your email address at the top of the config file: \n\n.. code-block:: ini \n\n    error_email_from = you@example.com \n\nThis is very useful for a production site. Emails are sent via SMTP so you need to specify a valid SMTP server too.\n\nProgrammatically Handling Errors\n================================\n\nBy default, the :class:`~pylons.middleware.StatusCodeRedirect` will redirect any response with the designated status codes back into the application again. This will result in the ``error`` controller in the Pylons project being called. This is why there is a default route in :file:`config/routing.py` of::\n    \n    map.connect('/error/{action}', controller='error')\n    map.connect('/error/{action}/{id}', controller='error')\n    \nThe error controller allows a project to theme the error message appropriately by changing it to render a template, or redirect as desired.\n\nOriginal Request Information\n----------------------------\n\nThe original request and response that resulted in the error controller being called is available inside the error controller as::\n    \n    # Original request\n    request.environ['pylons.original_request']\n    \n    # Original response\n    request.environ['pylons.original_response']\n\nIf an :exc:`~webob.exc.HTTPException` was thrown in the controller (the :func:`~pylons.controllers.util.abort` function throws these), the original object is available as::\n    \n    request.environ['pylons.controller.exception']\n\nThis allows access to the error message on the exception object.\n"
  },
  {
    "path": "pylons/docs/en/deployment.rst",
    "content": ".. _deployment:\n\nPackaging and Deployment Overview\n=================================\n\nTODO: some of this is redundant to the (more current) :ref:`configuration` doc -- should be consolidated and cross-referenced\n\nThis document describes how a developer can take advantage of Pylons' application setup functionality to allow webmasters to easily set up their application. \n\nInstallation refers to the process of downloading and installing the application with :term:`easy_install` whereas setup refers to the process of setting up an instance of an installed application so it is ready to be deployed. \n\nFor example, a wiki application might need to create database tables to use. The webmaster would only install the wiki ``.egg`` file once using :term:`easy_install` but might want to run 5 wikis on the site so would setup the wiki 5 times, each time specifying a different database to use so that 5 wikis can run from the same code, but store their data in different databases. \n\nEgg Files\n*********\n\nBefore you can understand how a user configures an application you have to understand how Pylons applications are distributed. All Pylons applications are distributed in ``.egg`` format. An egg is simply a Python executable package that has been put together into a single file. \n\nYou create an egg from your project by going into the project root directory and running the command: \n\n.. code-block:: bash \n\n    $ python setup.py bdist_egg \n\nIf everything goes smoothly a ``.egg`` file with the correct name and version number appears in a newly created ``dist`` directory. \n\nWhen a webmaster wants to install a Pylons application he will do so by downloading the egg and then installing it. \n\nInstalling as a Non-root User\n*****************************\n\nIt's quite possible when using shared hosting accounts that you do not have root access to install packages. In this case you can install :term:`setuptools` based packages like Pylons and Pylons web applications in your home directory using a :term:`virtualenv` setup. This way you can install all the packages you want to use without super-user access. \n\nUnderstanding the Setup Process \n*******************************\n\nSay you have written a Pylons wiki application called ``wiki``. When a webmaster wants to install your wiki application he will run the following command to generate a config file: \n\n.. code-block:: bash \n\n    $ paster make-config wiki wiki_production.ini \n\nHe will then edit the config file for his production environment with the settings he wants and then run this command to setup the application: \n\n.. code-block:: bash \n\n    $ paster setup-app wiki_production.ini \n\nFinally he might choose to deploy the wiki application through the paste server like this (although he could have chosen CGI/FastCGI/SCGI etc): \n\n.. code-block:: bash \n\n    $ paster serve wiki_production.ini \n\nThe idea is that an application only needs to be installed once but if necessary can be set up multiple times, each with a different configuration. \n\nAll Pylons applications are installed in the same way, so you as the developer need to know how the above commands work. \n\nMake Config \n----------- \n\nThe ``paster make-config`` command looks for the file ``deployment.ini_tmpl`` and uses it as a basis for generating a new ``.ini`` file. \n\nUsing our new wiki example again, the ``wiki/config/deployment.ini_tmpl`` file contains the text: \n\n.. code-block:: ini \n\n    [DEFAULT]\n    debug = true\n    email_to = you@yourdomain.com\n    smtp_server = localhost\n    error_email_from = paste@localhost\n\n    [server:main]\n    use = egg:Paste#http\n    host = 0.0.0.0\n    port = 5000\n\n    [app:main]\n    use = egg:wiki\n    full_stack = true\n    static_files = true\n    cache_dir = %(here)s/data\n    beaker.session.key = wiki\n    beaker.session.secret = ${app_instance_secret}\n    app_instance_uuid = ${app_instance_uuid}\n\n    # If you'd like to fine-tune the individual locations of the cache data dirs\n    # for the Cache data, or the Session saves, un-comment the desired settings\n    # here:\n    #beaker.cache.data_dir = %(here)s/data/cache\n    #beaker.session.data_dir = %(here)s/data/sessions\n\n    # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*\n    # Debug mode will enable the interactive debugging tool, allowing ANYONE to\n    # execute malicious code after an exception is raised.\n    set debug = false\n\n\n    # Logging configuration\n    [loggers]\n    keys = root\n\n    [handlers]\n    keys = console\n\n    [formatters]\n    keys = generic\n\n    [logger_root]\n    level = INFO\n    handlers = console\n\n    [handler_console]\n    class = StreamHandler\n    args = (sys.stderr,)\n    level = NOTSET\n    formatter = generic\n\n    [formatter_generic]\n    format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s\n\n\nWhen the command ``paster make-config wiki wiki_production.ini`` is run, the contents of this file are produced so you should tweak this file to provide sensible default configuration for production deployment of your app. \n\nSetup App \n--------- \n\nThe ``paster setup-app`` command references the newly created ``.ini`` file and calls the function ``wiki.websetup.setup_app()`` to set up the application. If your application needs to be set up before it can be used, you should edit the ``websetup.py`` file. \n\nHere's an example which just prints the location of the cache directory via Python's logging facilities: \n\n.. code-block:: python \n\n    \"\"\"Setup the helloworld application\"\"\" \n    import logging \n\n    from pylons import config\n    from helloworld.config.environment import load_environment \n\n    log = logging.getLogger(__name__) \n\n    def setup_app(command, conf, vars): \n        \"\"\"Place any commands to setup helloworld here\"\"\" \n        load_environment(conf.global_conf, conf.local_conf) \n        log.info(\"Using cache dirctory %s\" % config['cache.dir']) \n\nFor a more useful example, say your application needs a database set up and loaded with initial data. The user will specify the location of the database to use by editing the config file before running the ``paster setup-app`` command. The ``setup_app()`` function will then be able to load the configuration and act on it in the function body. This way, the ``setup_app()`` function can be used to initialize the database when ``paster setup-app`` is run. Using the optional :term:`SQLAlchemy` project template support when creating a Pylons project will set all of this up for you in a basic way. The :ref:`quickwiki_tutorial` illustrates an example of this configuration.\n\nDeploying the Application\n*************************\n\nOnce the application is setup it is ready to be deployed. There are lots of ways of deploying an application, one of which is to use the ``paster serve`` command which takes the configuration file that has already been used to setup the application and serves it on a local HTTP server for production use: \n\n.. code-block:: bash \n\n    $ paster serve wiki_production.ini \n\nMore information on Paste deployment options is available on the Paste website at http://pythonpaste.org. See :ref:`deployment_webservers` for alternative Pylons deployment scenarios.\n\nAdvanced Usage\n**************\n\nSo far everything we have done has happened through the ``paste.script.appinstall.Installer`` class which looks for the ``deployment.ini_tmpl`` and ``websetup.py`` file and behaves accordingly. \n\nIf you need more control over how your application is installed you can use your own installer class. Create a file, for example ``wiki/installer.py`` and code your new installer class in the file by deriving it from the existing one:\n\n.. code-block:: python \n\n    from paste.script.appinstall import Installer \n    class MyInstaller(Installer): \n        pass \n\nYou then override the functionality as necessary (have a look at the source code for ``Installer`` as a basis. You then change your application's ``setup.py`` file so that the ``paste.app_install`` entry point ``main`` points to your new installer: \n\n.. code-block:: python \n\n    entry_points=\"\"\" \n    ... \n    [paste.app_install] \n    main=wiki.installer:MyInstaller \n    ... \n    \"\"\", \n\nDepending on how you code your ``MyInstaller`` class you may not even need your ``websetup.py`` or ``deployment.ini_tmpl`` as you might have decided to create the ``.ini`` file and setup the application in an entirely different way. \n\n\n.. _deployment_webservers:\n\nRunning Pylons Apps with Other Web Servers\n==========================================\n\nThis document assumes that you have already installed a Pylons web application, and :ref:`run-config` for it.  Pylons applications use `PasteDeploy <http://pythonpaste.org/deploy/>`_ to  start up your Pylons WSGI application, and can use the flup package to provide a Fast-CGI, SCGI, or AJP connection to it. \n\nUsing Fast-CGI\n**************\n\n`Fast-CGI <http://fastcgi.com/>`_ is a gateway to connect web severs like `Apache <http://httpd.apache.org/>`_ and `lighttpd <http://lighttpd.net/>`_ to a CGI-style application. Out of the box, Pylons applications can run with Fast-CGI in either a threaded or forking mode. (Threaded is the recommended choice) \n\nSetting a Pylons application to use Fast-CGI is very easy, and merely requires you to change the config line like so: \n\n.. code-block:: ini \n\n    # default \n    [server:main] \n    use = egg:Paste#http \n\n    # Use Fastcgi threaded \n    [server:main] \n    use = egg:PasteScript#flup_fcgi_thread \n    host = 0.0.0.0 \n    port = 6500 \n\nNote that you will need to install the `flup <http://www.saddi.com/software/flup/dist/>`_ package, which can be \ninstalled via easy_install: \n\n.. code-block:: bash \n\n    $ easy_install -U flup \n\nThe options in the config file are passed onto flup. The two common ways to run Fast CGI is either using a socket to listen for requests, or listening on a port/host which allows a webserver to send your requests to web applications on a different machine. \n\nTo configure for a socket, your ``server:main`` section should look like this: \n\n.. code-block:: ini \n\n    [server:main] \n    use = egg:PasteScript#flup_fcgi_thread \n    socket = /location/to/app.socket \n\nIf you want to listen on a host/port, the configuration cited in the first example will do the trick. \n\nApache Configuration\n********************\n\nFor this example, we will assume you're using Apache 2, though Apache 1 configuration will be very similar. First, make sure that you have the Apache `mod_fastcgi <http://fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html>`_ module installed in \nyour Apache. \n\nThere will most likely be a section where you declare your FastCGI servers, and whether they're external: \n\n.. code-block:: apacheconf \n\n    <IfModule mod_fastcgi.c> \n    FastCgiIpcDir /tmp \n    FastCgiExternalServer /some/path/to/app/myapp.fcgi -host some.host.com:6200 \n    </IfModule> \n\nIn our example we'll assume you're going to run a Pylons web application listening on a host/port. Changing ``-host`` to ``-socket`` will let you use a Pylons web application listening on a socket. \n\nThe filename you give in the second option does not need to physically exist on the webserver, URIs that Apache resolve to this filename will be handled by the FastCGI application. \n\nThe other important line to ensure that your Apache webserver has is to indicate that fcgi scripts should be handled with Fast-CGI: \n\n.. code-block:: apacheconf \n\n    AddHandler fastcgi-script .fcgi \n\nFinally, to configure your website to use the Fast CGI application you will need to indicate the script to be used: \n\n.. code-block:: apacheconf \n\n    <VirtualHost *:80> \n        ServerAdmin george@monkey.com \n        ServerName monkey.com \n        ServerAlias www.monkey.com \n        DocumentRoot /some/path/to/app \n\n        ScriptAliasMatch ^(/.*)$ /some/path/to/app/myapp.fcgi$1 \n    </VirtualHost> \n\nOther useful directives should be added as needed, for example, the ErrorLog directive, etc. This configuration will result in all requests being sent to your FastCGI application. \n\nPrefixMiddleware\n****************\n\n``PrefixMiddleware`` provides a way to manually override the root prefix (``SCRIPT_NAME``) of your application for certain situations. \n\nWhen running an application under a prefix (such as '``/james``') in FastCGI/apache, the ``SCRIPT_NAME`` environment variable is automatically set to to the appropriate value: '``/james``'. Pylons' URL generators such as ``url`` always take the ``SCRIPT_NAME`` value into account. \n\nOne situation where ``PrefixMiddleware`` is required is when an application is accessed via a reverse proxy with a prefix. The application is accessed through the reverse proxy via the the URL prefix '``/james``', whereas the reverse proxy forwards those requests to the application at the prefix '``/``'. \n\nThe reverse proxy, being an entirely separate web server, has no way of specifying the ``SCRIPT_NAME`` variable; it must be manually set by a ``PrefixMiddleware`` instance. Without setting ``SCRIPT_NAME``, ``url`` will generate URLs such as: '``/purchase_orders/1``', when it should be generating: '``/james/purchase_orders/1``'. \n\nTo filter your application through a ``PrefixMiddleware`` instance, add the following to the '``[app:main]``' section of your .ini file: \n\n.. code-block :: ini \n\n    filter-with = proxy-prefix \n\n    [filter:proxy-prefix] \n    use = egg:PasteDeploy#prefix \n    prefix = /james \n\nThe name ``proxy-prefix`` simply acts as an identifier of the filter section; feel free to rename it. \n\nThese .ini settings are equivalent to adding the following to the end of your application's ``config/middleware.py``, right before the ``return app`` line: \n\n.. code-block :: python \n\n    # This app is served behind a proxy via the following prefix (SCRIPT_NAME) \n    app = PrefixMiddleware(app, global_conf, prefix='/james') \n\nThis requires the additional import line: \n\n.. code-block :: python \n\n    from paste.deploy.config import PrefixMiddleware \n\nWhereas the modification to ``config/middleware.py`` will setup an instance of ``PrefixMiddleware`` under every environment (.ini).\n\nUsing Java Web Servers with Jython\n**********************************\n\nSee :ref:`java_deployment`.\n\n.. _adding_documentation:\n\nDocumenting Your Application\n============================\n\nTODO: this needs to be rewritten -- Pudge is effectively dead\n\nWhile the information in this document should be correct, it may not be entirely complete... Pudge is somewhat unruly to work with at this time, and you may need to experiment to find a working combination of package versions. In particular, it has been noted that an older version of Kid, like 0.9.1, may be required. You might also need to install {{RuleDispatch}} if you get errors related to {{FormEncode}} when attempting to build documentation. \n\nApologies for this suboptimal situation. Considerations are being taken to fix Pudge or supplant it for future versions of Pylons. \n\nIntroduction\n************\n\nPylons comes with support for automatic documentation generation tools like `Pudge <http://pudge.lesscode.org>`_. \n\nAutomatic documentation generation allows you to write your main documentation in the docs directory of your project as well as throughout the code itself using docstrings. \n\nWhen you run a simple command all the documentation is built into sophisticated HTML. \n\nTutorial\n********\n\nFirst create a project as described in :ref:`getting_started`.\n\nYou will notice a docs directory within your main project directory. This is where you should write your main documentation. \n\nThere is already an ``index.txt`` file in ``docs`` so you can already generate documentation. First we'll install Pudge and buildutils. By default, Pylons sets an option to use `Pygments <http://pygments.org>`_ for syntax-highlighting of code in your documentation, so you'll need to install it too (unless you wish to remove the option from ``setup.cfg``): \n\n.. code-block:: bash \n\n    $ easy_install pudge buildutils \n    $ easy_install Pygments \n\nthen run the following command from your project's main directory where the ``setup.py`` file is: \n\n.. code-block:: bash \n\n    $ python setup.py pudge \n\n.. Note:: \n\n    The ``pudge`` command is currently disabled by default. Run the following command first to enable it: \n\n    ..code-block:: bash \n\n        $ python setup.py addcommand -p buildutils.pudge_command \n\n    Thanks to Yannick Gingras for the tip. \n\nPudge will produce output similar to the following to tell you what it is doing and show you any problems: \n\n.. code-block:: text\n\n    running pudge \n    generating documentation \n    copying: pudge\\template\\pythonpaste.org\\rst.css -> do/docs/html\\rst.css \n    copying: pudge\\template\\base\\pudge.css -> do/docs/html\\pudge.css \n    copying: pudge\\template\\pythonpaste.org\\layout.css -> do/docs/html\\layout.css \n    rendering: pudge\\template\\pythonpaste.org\\site.css.kid -> site.css \n    colorizing: do/docs/html\\do/__init__.py.html \n    colorizing: do/docs/html\\do/tests/__init__.py.html \n    colorizing: do/docs/html\\do/i18n/__init__.py.html \n    colorizing: do/docs/html\\do/lib/__init__.py.html \n    colorizing: do/docs/html\\do/controllers/__init__.py.html \n    colorizing: do/docs/html\\do/model.py.html \n\nOnce finished you will notice a ``docs/html`` directory. The ``index.html`` is the main file which was generated from ``docs/index.txt``. \n\nLearning ReStructuredText\n*************************\n\nPython programs typically use a rather odd format for documentation called `reStructuredText`_. It is designed so that the text file used to generate the HTML is as readable as possible but as a result can be a bit confusing for beginners. \n\nRead the reStructuredText tutorial which is part of the `docutils <http://docutils.sf.net>`_ project. \n\nOnce you have mastered reStructuredText you can write documentation until your heart's content. \n\n.. _reStructuredText: http://docutils.sourceforge.net/rst.html\n\nUsing Docstrings\n****************\n\nDocstrings are one of Python's most useful features if used properly. They are described in detail in the Python documentation but basically allow you to document any module, class, method or function, in fact just about anything. Users can then access this documentation interactively. \n\nTry this: \n\n.. code-block:: pycon\n\n    >>> import pylons \n    >>> help(pylons) \n    ... \n\nAs you can see if you tried it you get detailed information about the pylons module including the information in the docstring. \n\nDocstrings are also extracted by Pudge so you can describe how to use all the controllers, actions and modules that make up your application. Pudge will extract that information and turn it into useful API documentation automatically. \n\nTry clicking the ``Modules`` link in the HTML documentation you generated earlier or look at the Pylons source code for some examples of how to use docstrings. \n\nUsing doctest\n*************\n\nThe final useful thing about docstrings is that you can use the ``doctest`` module with them. ``doctest`` again is described in the Python documentation but it looks through your docstrings for things that look like Python code written at a Python prompt. Consider this example: \n\n.. code-block:: pycon \n\n    >>> a = 2 \n    >>> b = 3 \n    >>> a + b \n    5 \n\nIf ``doctest`` was run on this file it would have found the example above and executed it. If when the expression ``a + b`` is executed the result was not ``5``, ``doctest`` would raise an Exception. \n\nThis is a very handy way of checking that the examples in your documentation are actually correct. \n\nTo run ``doctest`` on a module use: \n\n.. code-block:: python \n\n    if __name__ == \"__main__\": \n        import doctest \n        doctest.testmod() \n\nThe ``if __name__ == \"__main__\":`` part ensures that your module won't be tested if it is just imported, only if it is run from the command line \n\nTo run ``doctest`` on a file use: \n\n.. code-block:: python \n\n    import doctest \n    doctest.testfile(\"docs/index.txt\") \n\nYou might consider incorporating this functionality in your ``tests/test.py`` file to improve the testing of your application. \n\nSummary\n*******\n\nSo if you write your documentation in reStructuredText, in the ``docs`` directory and in your code's docstrings, liberally scattered with example code, Pylons provides a very useful and powerful system for you. \n\nIf you want to find out more information have a look at the Pudge documentation or try tinkering with your project's ``setup.cfg`` file which contains the Pudge settings. \n\n\n.. _app_distribution:\n\nDistributing Your Application\n=============================\n\nTODO: this assumes helloworld tutorial context that is no longer present, and could be consolidated with packaging info in :ref:`deployment`\n\nAs mentioned earlier eggs are a convenient format for packaging applications. You can create an egg for your project like this:\n\n.. code-block:: bash\n\n    $ cd helloworld\n    $ python setup.py bdist_egg\n\nYour egg will be in the ``dist`` directory and will be called ``helloworld-0.0.0dev-py2.4.egg``.\n\nYou can change options in ``setup.py`` to change information about your project. For example change version to ``version=\"0.1.0\",`` and run ``python setup.py bdist_egg`` again to produce a new egg with an updated version number.\n\nYou can then register your application with the `Python Package Index`_ (PyPI) with the following command:\n\n.. code-block:: bash\n\n    $ python setup.py register\n\n.. note::\n\n    You should not do this unless you actually want to register a package!\n\nIf users want to install your software and have installed :term:`easy_install` they can install your new egg as follows:\n\n.. code-block:: bash\n\n    $ easy_install helloworld==0.1.0\n\nThis will retrieve the package from PyPI and install it. Alternatively you can install the egg locally:\n\n.. code-block:: bash\n\n    $ easy_install -f C:\\path\\with\\the\\egg\\files\\in helloworld==0.1.0\n\nIn order to use the egg in a website you need to use Paste. You have already used Paste to create your Pylons template and to run a test server to test the tutorial application.\n\nPaste is a set of tools available at http://pythonpaste.org for providing a uniform way in which all compatible Python web frameworks can work together. To run a paste application such as any Pylons application you need to create a Paste configuration file. The idea is that the your paste configuration file will contain all the configuration for all the different Paste applications you run. A configuration file suitable for development is in the ``helloworld/development.ini`` file of the tutorial but the idea is that the person using your egg will add relevant configuration options to their own Paste configuration file so that your egg behaves they way they want. See the section below for more on this configuration.\n\nPaste configuration files can be run in many different ways, from CGI scripts, as standalone servers, with FastCGI, SCGI, mod_python and more. This flexibility means that your Pylons application can be run in virtually any environment and also take advantage of the speed benefits that the deployment option offers.\n\n.. seealso::\n\n    :ref:`deployment_webservers`\n\n.. _Python Package Index: http://pypi.python.org/pypi\n\nRunning Your Application\n************************\n\nIn order to run your application your users will need to install it as described above but then generate a config file and setup your application before deploying it. This is described in :ref:`run-config` and :ref:`deployment`.\n"
  },
  {
    "path": "pylons/docs/en/events.rst",
    "content": ".. _events:\n\n======\nEvents\n======\n\n"
  },
  {
    "path": "pylons/docs/en/execution.rst",
    "content": "Pylons Execution Analysis\n%%%%%%%%%%%%%%%%%%%%%%%%%\n\n*By Mike Orr and Alfredo Deza*\n\nThis chapter shows how Pylons calls your application, and how Pylons interacts\nwith Paste, Routes, Mako, and its other dependencies.  We'll create\na simple application and then analyze the Python code executed starting from\nthe moment we run the \"paster serve\" command.\n\n**Abbreviations:** **$APP** is your top-level application directory. \n**$SP** is the site-packages directory where Pylons is installed.\n**$BIN** is the location of ``paster`` and other executables. $SP paths are\nshown in pip style ($SP/pylons) rather than easy_install style\n($SP/Pylons-VERSION.egg/pylons).\n\nThe sample application\n========================\n\n1. Create an application called \"Analysis\" with a controller called \"main\"::\n\n    $ paster create -t pylons Analysis\n    $ cd Analysis\n    $ paster controller main\n\n   Press Enter at all question prompts.\n\n2. Edit **analysis/controllers/main.py** to look like this::\n\n        from analysis.lib.base import BaseController\n\n        class MainController(BaseController):\n\n            def index(self):\n                return '<h1>Welcome to the Analysis Demo</h1>Here is a <a href=\"/page2\">link</a>.'\n\n            def page2(self):\n                return 'Thank you for using the Analysis Demo. <a href=\"/\">Home</a>'\n                \n   There are two shortcuts here which you would not use in a normal\n   application. One, we're returning incomplete HTML documents. Two, we've\n   hardcoded the URLs to make the analysis easier to follow, rather than using\n   the ``url`` object.\n\n3. Now edit **analysis/config/routing.py**.  Add these lines after \"CUSTOM\n   ROUTES HERE\" (line 21)::\n\n    map.connect(\"home\", \"/\", controller=\"main\", action=\"index\")\n    map.connect(\"page2\", \"/page2\", controller=\"main\", action=\"page2\")\n\n4. Delete the file **analysis/public/index.html**.\n\n5. Now run the server.  (Press ctrl-C to quit it.) ::\n\n    $ paster serve development.ini\n    Starting server in PID 7341.\n    serving on http://127.0.0.1:5000\n\n\nPylons' dependencies\n====================\n\nPylons 1.0 has the following direct and indirect dependencies, which will be\nfound in your site-packages directory ($SP):\n\n* Beaker 1.5.4\n* decorator 3.2.0\n* FormEncode 1.2.2\n* Mako 0.3.4\n* MarkupSafe 0.9.3\n* Nose 0.11.4\n* Paste 1.7.3.1\n* PasteDeploy 1.3.3\n* PasteScript 1.7.3\n* Routes 1.12.3\n* simplejson 2.0.9 (if Python < 2.6)\n* Tempita 0.4\n* WebError 0.10.2\n* WebHelpers 1.2\n* WebOb 0.9.8\n* Webtest 1.2.1\n\nThese are the current versions as of August 29, 2010. Your installation may have\nslightly newer or older versions.\n\nThe analysis\n============\n\nStartup (PasteScript)\n---------------------\n\nWhen you run ``paster serve development.ini``, it runs the \"$BIN/paster\" program.\nThis is a platform-specific stub created by ``pip`` or ``easy_install``.  It\ndoes this::\n\n    __requires__ = 'PasteScript==1.7.3'\n    import sys\n    from pkg_resources import load_entry_point\n\n    sys.exit(\n       load_entry_point('PasteScript==1.7.3', 'console_scripts', 'paster')()\n    )\n\nThis says to load a Python object \"paster\" located in an egg \"PasteScript\",\nversion 1.7.3, under the entry point group ``[console_scripts]``.  \n\nTo explain what this means we have to get into Setuptools. Setuptools is\nPython's de facto package manager, and was installed as part of your virtualenv\nor Pylons installation. (If you're using Distribute 0.6, an alternative\npackage manager, it works the same way.) ``load_entry_point`` is a function\nthat looks up a Python object via entry point and returns it.\n\nSo what's an entry point? It's an alias for a Python object. Here's the entry\npoint itself::\n\n        [console_scripts]\n        paster=paste.script.command:run\n\nThis is from $SP/PasteScript-VERSION.egg-info/entry_points.txt.\n(If you used easy_install rather than pip, the path would be slightly\ndifferent: $APP/PasteScript-VERSION.egg/EGG-INFO/entry_points.txt.)\n\n\"console_scripts\" is the entry point group. \"paster\" is the\nentry point. The right side of the value tells which module to import\n(``paste.script.command``) and which object in it to return (the ``run``\nfunction). (To create an entry point, define it in your package's setup.py. Pip\nor easy_install will create the egg_info metadata from that. If you modify a\npackage's entry points, you must reinstall the package to update the egg_info.)\n\nThe most common use case for entry points is for plugins. So Nose for instance\ndefines an entry point group by which it will look for plugins. Any other\npackage can provide plugins for Nose by defining entry points in that group.\nPaster uses plugins extensively, as we'll soon see.\n\nSo to make a long story short, \"paster serve\" calls this ``run`` function. I\ninserted print statements into ``paste.script.command`` to figure out what it\ndoes. Here's a simplified description:\n\n1. The ``run()`` function parses the command-line options into a subcommand \n   ``\"serve\"`` with arguments ``[\"development.ini\"]``.\n\n2. It calls ``get_commands()``, which loads Paster commands from plugins\n   located at various entry points.  (You can add custom commands with the\n   \"--plugin\" command-line argument.)  Paste's standard commands are listed in\n   the same entry_points.txt file we saw above::\n\n        [paste.global_paster_command]\n        serve=paste.script.serve:ServeCommand [Config]\n        #... other commands like \"make-config\", \"setup-app\", etc ...\n\n3. It calls ``invoke()``, which essentially does\n   ``paste.script.serve.ServeCommand([\"development.ini\"]).run()``. This in turn\n   calls ``ServeCommand.command()``, which handles daemonizing and other\n   top-level stuff.  Since our command line is short, there's no top-level\n   stuff to do. It creates 'server' and 'app' objects based on the\n   configuration file, and calls ``server(app)``.\n\nLoading the server and the application (PasteDeploy)\n----------------------------------------------------\n\nThis all happens during step 3 of the application startup. We need to find and\ninstantiate the WSGI application and server based on the configuration file.\nThe application is our Analysis application.  The server is Paste's built-in\nmultithreaded HTTP server.  A simplified version of the code is::\n\n    # Inside paste.script.serve module, ServeCommand.command() method.\n    from paste.deploy.loadwsgi import loadapp, loadserver\n    server = self.loadserver(server_spec, name=server_name,\n                                     relative_to=base, global_conf=vars)\n    app = self.loadapp(app_spec, name=app_name,\n                      relative_to=base, global_conf=vars)\n\n``loadserver()`` and ``loadapp()`` are defined in module\n``paste.deploy.loadwsgi``. The code here is complex, so we'll just look at its\ngeneral behavior. Both functions see the \"config:\" URI and read our config\nfile. Since there is no server name or app name they both default to \"main\".\nTherefore loadserver() looks for a \"\\[server:main]\" section in the config file,\nand loadapp()` looks for \"\\[app:main]\". Here's what they find in\n\"development.ini\"::\n\n    [server:main]\n    use = egg:Paste#http\n    host = 127.0.0.1\n    port = 5000\n\n    [app:main]\n    use = egg:Analysis\n    full_stack = true\n    static_files = true\n    ...\n\nThe \"use =\" line in each section tells which object to load. The other lines\nare configuration parameters for that object, or for plugins that object is\nexpected to load.  We can also put custom parameters in \\[app:main] for our\napplication to read directly.\n\n\nServer loading\n++++++++++++++\n\n1. ``loadserver()``'s args are ``uri=\"config:development.ini\", name=None,\n   relative_to=\"$APP\"``.\n\n2. A \"config:\" URI means to read a config file.\n\n3. A server name was not specified so it defaults to \"main\". So loadserver()\n   looks for a section \"\\[server:main]\". The \"server\" part comes from the\n   loadwsgi._Server.config_prefixes class attribute in\n   $SP/paste/deploy/loadwsgi.py).\n\n4. \"use = egg:Paste#http\" says to load an egg called \"Paste\".\n\n5. loadwsgi._Server.egg_protocols lists two protocols it supports:\n   \"server_factory\" and \"server_runner\".\n\n6. \"paste.server_runner\" is an entry point group in the \"Paste\" egg, and it has\n   an entry point \"http\". The relevant lines in\n   $SP/Paste\\*.egg_info/entry_points.txt are::\n\n        [paste.server_runner]\n        http = paste.httpserver:server_runner\n\n7. There's a server_runner() function in the paste.httpserver module\n   ($SP/paste/httpserver.py).\n\nWe'll stop here for a moment and look at how the application is loaded.\n\nApplication loading\n+++++++++++++++++++\n\n1. loadapp() looks for a section \"\\[app:main]\" in the config file. The \"app\"\n   part comes from the loadwsgi._App.config_prefixes class attribute (in\n   $SP/paste/deploy/loadwsgi.py).\n\n2. \"use = egg:Analysis\" says to find an egg called \"Analysis\".\n\n3. loadwsgi._App.egg_protocols lists \"paste.app_factory\" as one of the\n   protocols it supports.\n\n4. \"paste.app_factory\" is also an entry point group in the egg, as seen in\n   $APP/Analysis.egg-info/entry_points.txt::\n\n        [paste.app_factory]\n        main = analysis.config.middleware:make_app\n\n5. The line \"main = analysis.config.middleware:make_app\" means to \n   look for a ``make_app()`` object in the ``analysis`` package. \n   This is a function imported from ``analysis.config.middleware`` \n   ($APP/analysis/config/middleware.py).\n\n\nInstantiating the application (Analysis)\n----------------------------------------\n\nHere's a closer look at our application's ``make_app`` function::\n\n    # In $APP/analysis/config/middleware.py\n    def make_app(global_conf, full_stack=True, static_files=True, **app_conf):\n        config = load_environment(global_conf, app_conf)\n        app = PylonsApp(config=config)\n        app = SomeMiddleware(app, ...)   # Repeated for several middlewares.\n        app.config = config\n        return app\n\nThis sets up the Pylons environment (next subsection), creates the application\nobject (following subsection), wraps it in several layers of middleware (listed\nin \"Anatomy of a Request\" below), and returns the complete application object.\n\nThe \\[DEFAULT] section of the config file is passed as dict ``global_conf``.\nThe \\[app:main] section is passed as keyword arguments into dict ``app_conf``.\n\n``full_stack`` defaults to True because we're running the application\nstandalone.  If we were embedding this application as a WSGI component of some\nlarger application, we'd set ``full_stack`` to False to disable some of the\nmiddleware.  \n\n``static_files=True`` means to serve static files from our public\ndirectory ($APP/analysis/public). Advanced users can arrange for Apache to\nserve the static files itself, and put \"static_files = false\"\nin their configuration file to gain a bit of efficiency.\n\nload_environment & pylons.config\n++++++++++++++++++++++++++++++++\n\nBefore we begin, remember that ``pylons.config``, ``pylons.app_globals``,\n``pylons.request``, ``pylons.response``, ``pylons.session``, ``pylons.url``,\nand ``pylons.cache`` are special globals that change value depending on the\ncurrent request. The objects are proxies which maintain a thread-local stack of\nreal values.  Pylons pushes the actual values onto them at the beginning of a\nrequest, and pops them off at the end. (Some of them it also pushes at other\ntimes so they can be used outside of requests.) The proxies delegate attribute\naccess and key access to the topmost actual object on the stack. (You can also\ncall ``myproxy._current_obj()`` to get the actual object itself.)  The proxy\ncode is in ``paste.registry.StackedObjectProxy``, so these are called\n\"StackedObjectProxies\", or \"SOPs\" for short.\n\nThe first thing ``analysis.config.middleware.make_app()`` does is call\n``analysis.config.environment.load_environment()``::\n\n    def load_environment(global_conf, app_conf):\n        config = PylonsConfig()\n        root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n        paths = dict(root=root,\n                     controllers=os.path.join(root, 'controllers'),\n                     static_files=os.path.join(root, 'public'),\n                     templates=[os.path.join(root, 'templates')])\n\n        # Initialize config with the basic options\n        config.init_app(global_conf, app_conf, package='analysis',\n                        paths=paths)\n        config['routes.map'] = make_map(config)\n        config['pylons.app_globals'] = app_globals.Globals(config)\n        config['pylons.h'] = analysis.lib.helpers\n\n        # Setup cache object as early as possible\n        import pylons\n        pylons.cache._push_object(config['pylons.app_globals'].cache)\n\n        # Create the Mako TemplateLookup, with the default auto-escaping\n        config['pylons.app_globals'].mako_lookup = TemplateLookup(\n            directories=paths['templates'],\n            error_handler=handle_mako_error,\n            module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n            input_encoding='utf-8', default_filters=['escape'],\n            imports=['from webhelpers.html import escape'])\n\n        # CONFIGURATION OPTIONS HERE (note: all config options will override\n        # any Pylons config options)\n\n        return config\n\n``config`` is the Pylons configuration object, which will later be pushed onto\n``pylons.config``. It's an instance of ``pylons.configuration.PylonsConfig``, a\ndict subclass. ``config.init_app()`` initializes the dict's keys.  It sets the\nkeys to a merger of app_conf and global_conf (with app_conf overriding). It\nalso adds \"app_conf\" and \"global_conf\" keys so you can access the original\napp_conf and global_conf if desired. It also adds several Pylons-specific keys.\n\n``config[\"routes.map\"]`` is the Routes map defined in\n``analysis.config.routing.make_map()``. \n\n``config[\"pylons.app_globals\"]`` is the application's globals object, which\nwill later be pushed onto ``pylons.app_globals``.  It's an instance of\n``analysis.lib.app_globals.Globals``.\n\n``config[\"pylons.h\"]`` is the helpers module, ``analysis.lib.helpers``. Pylons\nwill assign it to ``h`` in the templates' namespace.\n\nThe \"cache\" lines push ``pylons.app_globals.cache`` onto ``pylons.cache`` for\nbackward compatibility.  This gives a preview of how StackedObjectProxies work.\n\nThe Mako stanza creates a TemplateLookup, which ``render()`` will use to find\ntemplates. The object is put on ``app_globals``.\n\nIf you've used older versions of Pylons, you'll notice a couple differences in\n1.0.  The ``config`` object is created as a local variable and returned, and\nit's passed explicitly to the route map factory and globals factory. Previous\nversions pushed it onto ``pylons.config`` immediately and used it from there.\nThis was changed to make it easier to nest Pylons applications inside other\nPylons applications. \n\nThe other difference is that Buffet is gone, and along with it the\n``template_engine`` argument and template config options. Pylons 1.0 gets out\nof the business of initializing template engines.  You use one of the standard\nrender functions such as ``render_mako`` or write your own, and define any\nattributes in ``app_globals`` that your render function depends on.\n\n\nPylonsApp\n+++++++++\n\nThe second line of ``make_app()`` creates a Pylons application object\nbased on your configuration.  Again the ``config`` object is passed around\nexplicitly, unlike older versions of Pylons. A Pylons application is an\ninstance of ``pylons.wsgiapp.PylonsApp`` instance. (Older versions of Pylons\nhad a ``PylonsBaseWSGIApp`` superclass, but that has been merged into\n``PylonsApp``.)\n\nMiddleware\n++++++++++\n\n``make_app()`` then wraps the application (the ``app`` variable) in several\nlayers of middleware. Each middleware provides an optional add-on service. \n\n================== ============================ ===============================\nMiddleware         Service                      Effect if disabled\n================== ============================ ===============================\nRoutesMiddleware   Use Routes to manage URLs.   Routes and ``pylons.url`` won't\n                                                work.\nSessionMiddleware  HTTP sessions using Beaker,  ``pylons.session`` won't work.\n                   with flexible persistence\n                   backends (disk, memached,\n                   database).\nErrorHandler       Display interactive          Paste will catch exceptions and \n                   traceback if an exception    convert them to Internal Server\n                   occurs. In production mode,  Error.\n                   email the traceback to the\n                   site admin.\nStatusCodeRedirect If an HTTP error occurs,     If an HTTP error occurs, \n                   make a subrequest to display display a plain white HTML page\n                   a fancy styled HTML error    with the error message.\n                   page.\nRegistryManager    Handles the special globals  The special globals won't work. \n                   (``pylons.request``, etc).   There are other ways to access\n                                                the objects without going\n                                                through the special globals.\nStaticURLParser    Serve the static files       The static files won't be \n                   in the application's         found. Presumably you've\n                   public directory.            configured Apache to serve them\n                                                directly.\nCascade            Call several sub-middlewares No cascading through\n                   in order, and use the first  alternative apps.\n                   one that doesn't return\n                   \"404 Not Found\". Used in\n                   conjunction with \n                   StaticURLParser.\n================== ============================ ===============================\n\nAt the end of the function, ``app.config`` is set to the ``config`` object, so\nthat any part of the application can access the config without going through\nthe special global.\n\nAnatomy of a request\n--------------------\n\nLet's say you're running the demo and click the \"link\" link on the home page.\nThe browser sends a request for \"http://localhost:5000/page2\".  In my Firefox\nthe HTTP request headers are::\n\n    GET /page2 \n    Host: 127.0.0.1:5000\n    User-Agent: Mozilla/5.0 ...\n    Accept: text/html,...\n    Accept-Language: en-us,en;q=0.5\n    Accept-Encoding: gzip,deflate\n    Accept-Charset: ISO-8859-1,utf-8;q=0.7*;q=0.7\n    Keep-Alive: 300\n    Connection: keep-alive\n    Referer: http://127.0.0.1/5000/\n    Cache-Control   max-age=0\n\nThe response is::\n\n    HTTP/1.x 200 OK\n    Server: PasteWSGIServer/0.5 Python/2.6.4\n    Date: Sun, 06 Dec 2009 14:06:05 GMT\n    Content-Type: text/html; charset=utf-8\n    Pragma:  no-cache\n    Cache-Control:   no-cache\n    Content-Length:  59\n\n    Thank you for using the Analysis Demo.  <a href=\"/\">Home</a>\n\nHere's the processing sequence:\n\n1. ``server(app)`` is still running, called by ``ServeCommand.command()`` in\n   $SP/paste/script/serve.py.\n\n2. ``server`` is actually ``paste.httpserver.server_runner()`` in\n   $SP/paste/httpserver. The only keyword args are 'host' and\n   'port' extracted from the config file.  ``server_runner`` de-stringifies\n   the arguments and calls ``serve(wsgi_app, **kwargs)`` (same module).  \n\n3. ``serve()``'s 'use_threadpool' arg defaults to True, so it creates a\n   ``WSGIThreadPoolServer`` instance called (``server``) with the following\n   inheritance::\n\n        SocketServer.BaseServer     # In SocketServer.py in Python stdlib.\n        BaseHTTPServer.HTTPServer  # In BaseHTTPServer.py in Python stdlib.\n        paste.httpserver.SecureHTTPServer  # Adds SSL (HTTPS).\n        paste.httpserver.WSGIServerBase    # Adds WSGI.\n        paste.httpserver.WSGIThreadPoolServer\n            multiple inheritance: ThreadPoolMixIn <= ThreadPool\n\n    Note that SecureHTTPServer overrides the implementation of Python's\n    SocketServer.TCPServer\n\n4. It calls ``server.serve_forever()``, implemented by the ``ThreadPoolMixIn``\n   superclass.  This calls ``self.handle_request()`` in a loop until\n   ``self.running`` becomes false.  That initiates this call stack::\n\n        # In paste.httpserver.serve(), calling 'server.serve_forever()'\n        ThreadPoolMixIn.serve_forever()  # Defined in paste.httpserver.\n        -> TCPServer.handle_request()    # Called for every request.\n        -> WSGIServerBase.get_request()\n        -> SecureHTTPServer.get_request()\n        -> self.socket.accept()          # Defined in stdlib socket module.\n\n   ``self.socket.accept()`` blocks, waiting for the next request.\n\n5. The request arrives and ``self.socket.accept()`` returns a new socket for\n   the connection. ``TCPServer.handle_request()`` continues. It calls\n   ``ThreadPoolMixIn.process_request()``, which puts the request in a thread\n   queue::\n\n        self.thread_pooladd.add_task(\n            lambda: self.process_request_in_thread(request, client_address))\n            # 'request' is the connection socket.\n\n   The thread pool is defined in the ``ThreadPool`` class. It spawns a number\n   of threads which each wait on the queue for a callable to run. In this case\n   the callable will be a complete Web transaction including sending the HTML\n   page to the client. Each thread will repeatedly process transactions from\n   the queue until they receive a sentinel value ordering them to die.\n\n   The main thread goes back to listening for other requests, so we're no\n   longer interested in it.\n\n6. **Thread #2** pulls the lambda out of the queue and calls it::\n\n        lambda\n        -> ThreadPoolMixIn.process_request_in_thread()\n        -> BaseServer.finish_request()\n        -> self.RequestHandlerClass(request, client_address, self)  # Instantiates this.\n           The class instantiated is paste.httpserver.WSGIHandler; i.e., the 'handler' variable in serve().\n\n7. The newly-created request handler takes over::\n\n        SocketServer.BaseRequestHandler.__init__(request, client_address, server)\n        -> WSGIHandler.handle()\n        -> BaseHTTPRequestHandler.handle()  # In stdlib BaseHTTPServer.py\n           Handles requests in a loop until self.close_connection is true.  (For HTTP keepalive?)\n        -> WSGIHandler.handle_one_request()\n           Reads the command from the socket.  The command is\n           \"GET /page2 HTTP/1.1\" plus the HTTP headers above.\n           BaseHTTPRequestHandler.parse_request() parses this into attributes\n           .command, .path, .request_version, and .headers.\n        -> WSGIHandlerMixin.wsgi_execute().\n        -> WSGIHandlerMixin.wsgi_setup()\n           Creates the .wsgi_environ dict.\n\n   The WSGI environment dict is described in PEP 333, the WSGI specification.\n   It contains various keys specifying the URL to fetch, query parameters,\n   server info, etc. All keys required by the CGI specification are present,\n   as are other keys specific to WSGI or to paricular middleware. The\n   application will calculate a response based on the dict. The application is\n   wrapped in layers of middleware -- nested function calls -- which modify\n   the dict on the way in and modify the response on the way out.\n\n8. The request handler, still in ``WSGIHandlerMixin.wsgi_execute()``, calls the\n   application thus::\n\n        result = self.server.wsgi_application(self.wsgi_environ,\n                                            self.wsgi_start_response)\n\n   ``wsgi_start_response`` is a callable mandated by the WSGI spec. The\n   application will call it to specify the HTTP headers. The return value is\n   an iteration of strings, which when concatenated form the HTML document to\n   send to the browser. Other MIME types are handled analagously.\n\n9. The application, as we remember, was returned by\n   ``analysis.config.middleware.make_app()``. It's wrapped in several layers\n   of middleware, so calling it will execute the middleware in reverse order\n   of how they're listed in $APP/analysis/config/middleware.py and\n   $SP/pylons/wsgiapp.py:\n\n        * ``Cascade`` (defined in $SP/paste/cascade.py) lists a \n          series of applications which will be tried in order (Skipped if static_files is set to False):\n\n                1. ``StaticURLParser`` (defined in \n                   $SP/paste/urlparser) looks for a file URL\n                   under $APP/analysis/public that matches the URL.  The demo\n                   has no static files.\n\n                2. If that fails the cascader tries your application.  \n                   But first there are other middleware to go through...\n\n        * ``RegistryManager`` (defined in $SP/paste/registry.py) \n          makes Pylons special globals both thread-local and middleware-local.\n          This includes **app_globals**, **cache**, **request**, **response**,\n          **session**, **tmpl_context**, **url**, and any other\n          ``StackedObjectProxy`` listed in $SP/pylons/__init__.py.  (**h** is\n          a module so it doesn't need a proxy.)\n\n        * ``StatusCodeRedirect`` (defined in $SP/pylons/middleware.py)\n          intercepts any HTTP error status returned by the application (e.g.,\n          \"Page Not Found\", \"Internal Server Error\") and sends another request\n          to the application to get the appropriate error page to display\n          instead. (Skipped if ``full_stack`` argument was false.)\n\n        * ``ErrorHandler`` (defined in $SP/pylons/middleware.py)\n          sends an interactive traceback to the browser if the app raises an\n          exception, if \"debug\" is true in the config file.  Otherwise it\n          attempts to email the traceback to the site administrator, and\n          substitutes a generic Internal Server Error for the response.\n          (Skipped if ``full_stack`` argument was false.\n\n        * User-defined middleware goes here.\n\n        * ``SessionMiddleware`` (wsgiapp.py) adds `Beaker`_\n          session support (the ``pylons.session`` object).  (Skipped if the\n          WSGI environment has a key 'session' -- it doesn't in this demo.)\n\n        * ``RoutesMiddleware`` (wsgiapp.py) compares the request URI against the\n          routing rules in $APP/analysis/config/routing.py and sets\n          'wsgi.routing_args' to the routing match dict (useful) and\n          'routes.route' to the Route (probably not useful).  Pylons 1.0 apps\n          have a ``singleton=False`` argument that suppresses initializing the\n          deprecated ``url_for()`` function. Routes now puts a URL\n          generator in the WSGI environment, which Pylons aliases to\n          ``pylons.url``.\n\n        * The innermost middleware calls the PylonsApp instance it was \n          initialized with.\n\n    Note: CacheMiddleware is no longer used in Pylons 1.0. Instead,\n    ``app_globals`` creates the cache as an attribute, and a line in\n    environment.py aliases ``pylons.cache`` to it.\n\n10. Surprise! PylonsApp is itself middleware. Its .\\_\\_call\\_\\_() method does::\n\n        self.setup_app_env(environ, start_response)\n        controller = self.resolve(environ, start_response)\n        response = self.dispatch(controller, environ, start_response)\n        return response\n\n    ``.setup_app_env()`` registers all those special globals.\n\n    ``.resolve()`` calculates the controller class based on the route chosen by\n    the RoutesMiddleware, and returns the controller class.\n\n    ``.dispatch`` instantiates the controller class and calls in the WSGI\n    manner.  If the controller does not exist (``.resolve()`` returned None),\n    raise an Exception that tells you what controller did not have any \n    content.\n\n    This method also handles the special URL \"/_test_vars\", which is enabled\n    if the application is running under a Nose test. This URL initializes\n    Pylons' special globals, for tests that have to access them before making\n    a regular request.\n\n11. ``analysis.controllers.main.MainController`` does not have a\n    ``.\\_\\_call\\_\\_()`` method, so control falls to its parent,\n    ``analysis.lib.base.BaseController``.  This trivially calls the\n    grandparent, ``pylons.controllers.WSGIController``. It calls the action\n    method ``MainController.page2()``. The action method may have any number of\n    positional arguments as long as they correspond to variables in the routing\n    match dict.  (GET/POST variables are in the **request.params** dict.)  If\n    the method has a ``\\*\\*kwargs`` argument, all other match variables are put\n    there.  Any variables passed to the action method are also put on the\n    **tmpl_context** object as attributes. If an action method name\n    starts with \"\\_\", it's private and HTTPNotFound is raised.\n\n12. If the controller has .\\_\\_before\\_\\_() and/or .\\_\\_after\\_\\_() methods,\n    they are called before and after the action, respectively. These can\n    perform authorization, lock OS resources, etc. These methods can have\n    arguments in the same manner as the action method.  However, if the code is\n    used by all controllers, most Pylons programmers prefer to it in the base\n    controller's ``.\\_\\_call\\_\\_`` method instead.\n\n13. The action method returns a string, unicode, Response object, or is a\n    generator of strings. In this trivial case it returns a string. A typical\n    Pylons action would set some *tmpl_context* attributes and 'return\n    render('/some/template.html\")' . In either case the global *response*\n    object's body would be set to the string.\n\n14. ``WSGIController.\\_\\_call\\_\\_()`` continues, converting the Response object\n    to an appropriate WSGI return value. (First it calls the start_response\n    callback to specify the HTTP headers, then it returns an iteration of\n    strings.  The Response object converts unicode to utf-8 encoded strings, or\n    whatever encoding you've specified in the config file.)\n\n15. The stack of middleware calls unwinds, each modifying the return value and\n    headers if it desires.  \n\n16. The server receives the final return value. (We're way back in\n    ``paste.httpserver.WSGIHandlerMixin.wsgi_execute()`` now.) The outermost\n    middleware has called back to ``server.start_response()``, which has saved\n    the status and HTTP headers in ``.wsgi_curr_headers``. ``.wsgi_execute()``\n    then iterates the application's return value, calling\n    ``.wsgi_write_chunk(chunk)`` for each encoded string yielded.\n    ``.wsgi_write_chunk('')`` formats the status and HTTP headers and sends them\n    on the socket if they haven't been sent yet, then sends the chunk. The\n    convoluted header behavior here is mandated by the WSGI spec.\n\n17. Control returns to ``BaseHTTPRequestHandler.handle()``.\n    ``.close_connection`` is true so this method returns. The call stack\n    continues unwinding all the way to\n    ``paste.httpserver.ThreadPoolMixIn.process_request_in_thread()``. This\n    tries to finish the request first and then close it unless it finds errors in it to end raising an Exception.\n\n18. The request lambda finishes and control returns to\n    ``ThreadPool.worker_thread_callback()``. It waits for another request in\n    the thread queue. If the next item in the queue is the shutdown sentinel\n    value, thread #2 dies.\n\nThus endeth our request's long journey, and this analysis is finished too.\n\n.. _beaker:  http://beaker.groovie.org/\n"
  },
  {
    "path": "pylons/docs/en/forms.rst",
    "content": ".. _forms:\n\n===========\nForms\n===========\n\nThe basics\n==========\n\nWhen a user submits a form on a website the data is submitted to the URL specified in the `action` attribute of the `<form>` tag. The data can be submitted either via HTTP `GET` or `POST` as specified by the `method` attribute of the `<form>` tag. If your form doesn't specify an `action`, then it's submitted to the current URL, generally you'll want to specify an `action`. When a file upload field such as `<input type=\"file\" name=\"file\" />` is present, then the HTML `<form>` tag must also specify `enctype=\"multipart/form-data\"` and `method` must be `POST`. \n\n\nGetting Started \n=============== \n\nAdd two actions that looks like this: \n\n.. code-block:: python \n\n    # in the controller \n\n    def form(self): \n        return render('/form.mako') \n\n    def email(self): \n        return 'Your email is: %s' % request.params['email'] \n\nAdd a new template called `form.mako` in the `templates` directory that contains the following: \n\n.. code-block:: html \n\n    <form name=\"test\" method=\"GET\" action=\"/hello/email\"> \n    Email Address: <input type=\"text\" name=\"email\" /> \n    <input type=\"submit\" name=\"submit\" value=\"Submit\" /> \n    </form> \n\nIf the server is still running (see the :ref:`Getting Started Guide <getting_started>`) you can visit http://localhost:5000/hello/form and you will see the form. Try entering the email address `test@example.com` and clicking Submit. The URL should change to ``http://localhost:5000/hello/email?email=test%40example.com`` and you should see the text `Your email is test@example.com`. \n\nIn Pylons all form variables can be accessed from the :data:`request.params` object which behaves like a dictionary. The keys are the names of the fields in the form and the value is a string with all the characters entity decoded. For example note how the `@` character was converted by the browser to `%40` in the URL and was converted back ready for use in :data:`request.params`. \n\n.. Note:: `request` and `response` are objects from the `WebOb` library.  Full documentation on their attributes and methods is `here <http://pythonpaste.org/webob/>`_.\n\nIf you have two fields with the same name in the form then using the dictionary interface will return the first string. You can get all the strings returned as a list by using the `.getall()` method. If you only expect one value and want to enforce this you should use `.getone()` which raises an error if more than one value with the same name is submitted. \n\nBy default if a field is submitted without a value, the dictionary interface returns an empty string. This means that using `.get(key, default)` on `request.params` will only return a default if the value was not present in the form. \n\n\nPOST vs GET and the Re-Submitted Data Problem \n--------------------------------------------- \n\nIf you change the `form.mako` template so that the method is `POST` and you re-run the example you will see the same message is displayed as before. However, the URL displayed in the browser is simply http://localhost:5000/hello/email without the query string. The data is sent in the body of the request instead of the URL, but Pylons makes it available in the same way as for GET requests through the use of `request.params`. \n\n.. note:: \n\n    If you are writing forms that contain password fields you should usually use POST to prevent the password being visible to anyone who might be looking at the user's screen. \n\nWhen writing form-based applications you will occasionally find users will press refresh immediately after submitting a form. This has the effect of repeating whatever actions were performed the first time the form was submitted but often the user will expect that the current page be shown again. If your form was submitted with a POST, most browsers will display a message to the user asking them if they wish to re-submit the data, this will not happen with a GET so POST is preferable to GET in those circumstances. \n\nOf course, the best way to solve this issue is to structure your code differently so: \n\n.. code-block:: python \n\n    # in the controller \n\n    def form(self): \n        return render('/form.mako') \n\n    def email(self): \n        # Code to perform some action based on the form data \n        # ... \n        redirect(url(controller='home', action='result'))\n\n    def result(self): \n        return 'Your data was successfully submitted' \n\nIn this case once the form is submitted the data is saved and an HTTP redirect occurs so that the browser redirects to http://localhost:5000/hello/result. If the user then refreshes the page, it simply redisplays the message rather than re-performing the action. \n\n\nUsing the Helpers \n================= \n\nCreating forms can also be done using WebHelpers, which comes with Pylons. Here is the same form created in the previous section but this time using the helpers: \n\n.. code-block:: html+mako \n\n    ${h.form(h.url(action='email'), method='get')} \n    Email Address: ${h.text('email')} \n    ${h.submit('Submit')} \n    ${h.end_form()} \n\nBefore doing this you'll have to import the helpers you want to use into your\nproject's `lib/helpers.py` file; then they'll be available under Pylons' ``h``\nglobal.  Most projects will want to import at least these:\n\n.. code-block:: python\n\n   from webhelpers.html import escape, HTML, literal, url_escape\n   from webhelpers.html.tags import *\n\nThere are many other helpers for text formatting, container objects,\nstatistics, and for dividing large query results into pages.  See the\n:mod:`WebHelpers documentation <webhelpers>` to choose the helpers you'll need.\n\n\n.. _file_uploads:\n\nFile Uploads \n============ \nFile upload fields are created by using the `file` input field type. The `file_field` helper provides a shortcut for creating these form fields: \n\n.. code-block:: mako \n\n    ${h.file_field('myfile')} \n\nThe HTML form must have its `enctype` attribute set to `multipart/form-data` to enable the browser to upload the file. The `form` helper's `multipart` keyword argument provides a shortcut for setting the appropriate `enctype` value: \n\n.. code-block:: html+mako \n\n    ${h.form(h.url(action='upload'), multipart=True)} \n    Upload file: ${h.file_field('myfile')} <br /> \n    File description: ${h.text_field('description')} <br /> \n    ${h.submit('Submit')} \n    ${h.end_form()} \n\nWhen a file upload has succeeded, the `request.POST` (or `request.params`) `MultiDict` will contain a `cgi.FieldStorage` object as the value of the field. \n\n`FieldStorage` objects have three important attributes for file uploads: \n\n`filename` \n    The name of file uploaded as it appeared on the uploader's filesystem. \n\n`file` \n    A file(-like) object from which the file's data can be read: A python `tempfile` or a `StringIO` object. \n\n`value` \n    The content of the uploaded file, eagerly read directly from the file object. \n\nThe easiest way to gain access to the file's data is via the `value` attribute: it returns the entire contents of the file as a string: \n\n.. code-block:: python \n\n    def upload(self): \n        myfile = request.POST['myfile'] \n        return 'Successfully uploaded: %s, size: %i, description: %s' % \\ \n            (myfile.filename, len(myfile.value), request.POST['description']) \n\nHowever reading the entire contents of the file into memory is undesirable, especially for large file uploads. A common means of handling file uploads is to store the file somewhere on the filesystem. The `FieldStorage` typically reads the file onto filesystem, however to a non permanent location, via a python `tempfile` object (though for very small uploads it stores the file in a `StringIO` object instead). \n\nPython `tempfiles` are secure file objects that are automatically destroyed when they are closed (including an implicit close when the object is garbage collected). One of their security features is that their path cannot be determined: a simple `os.rename` from the `tempfile's` path isn't possible. Alternatively, `shutil.copyfileobj` can perform an efficient copy of the file's data to a permanent location: \n\n.. code-block:: python \n\n    permanent_store = '/uploads/' \n\n    class Uploader(BaseController): \n        def upload(self): \n            myfile = request.POST['myfile'] \n            permanent_file = open(os.path.join(permanent_store, \n                                    myfile.filename.lstrip(os.sep)), \n                                    'w') \n\n        shutil.copyfileobj(myfile.file, permanent_file) \n        myfile.file.close() \n        permanent_file.close() \n\n        return 'Successfully uploaded: %s, description: %s' % \\ \n            (myfile.filename, request.POST['description']) \n\n.. warning:: \n    The previous basic example allows any file uploader to overwrite any file in\n    the `permanent_store` directory that your web application has permissions\n    to.\n\nAlso note the use of `myfile.filename.lstrip(os.sep)` here: without it, `os.path.join` is unsafe. `os.path.join` won't join absolute paths (beginning with `os.sep`), i.e. `os.path.join('/uploads/', '/uploaded_file.txt')` == `'/uploaded_file.txt'`. Always check user submitted data to be used with `os.path.join`. \n\nValidating user input with FormEncode\n=====================================\n\nValidation the Quick Way \n------------------------\n\nAt the moment you could enter any value into the form and it would be displayed in the message, even if it wasn't a valid email address. In most cases this isn't acceptable since the user's input needs validating. The recommended tool for validating forms in Pylons is `FormEncode <http://www.formencode.org>`_. \n\nFor each form you create you also create a validation schema. In our case this is fairly easy: \n\n.. code-block:: python \n\n    import formencode \n\n    class EmailForm(formencode.Schema): \n        allow_extra_fields = True \n        filter_extra_fields = True \n        email = formencode.validators.Email(not_empty=True) \n\n.. note:: \n\n    We usually recommend keeping form schemas together so that you have a single\n    place you can go to update them. It's also convenient for inheritance since\n    you can make new form schemas that build on existing ones. If you put your\n    forms in a `models/form.py` file, you can easily use them throughout your\n    controllers as `model.form.EmailForm` in the case shown.\n\nOur form actually has two fields, an email text field and a submit button. If extra fields are submitted FormEncode's default behavior is to consider the form invalid so we specify `allow_extra_fields = True`. Since we don't want to use the values of the extra fields we also specify `filter_extra_fields = True`. The final line specifies that the email field should be validated with an `Email()` validator. In creating the validator we also specify `not_empty=True` so that the email field will require input. \n\nPylons comes with an easy to use `validate` decorator, if you wish to use it import it in your `lib/base.py` like this:\n\n.. code-block:: python\n\n    # other imports\n\n    from pylons.decorators import validate\n \nUsing it in your controller is pretty straight-forward: \n\n.. code-block:: python \n\n    # in the controller \n\n    def form(self): \n        return render('/form.mako') \n\n    @validate(schema=EmailForm(), form='form') \n    def email(self): \n        return 'Your email is: %s' % self.form_result.get('email') \n\nValidation only occurs on POST requests so we need to alter our form definition so that the method is a POST: \n\n.. code-block:: mako \n\n    ${h.form(h.url(action='email'), method='post')} \n\nIf validation is successful, the valid result dict will be saved as\n`self.form_result` so it can be used in the action. Otherwise, the action will\nbe re-run as if it was a GET request to the controller action specified in\n`form`, and the output will be filled by FormEncode's htmlfill to fill in the\nform field errors. For simple cases this is really handy because it also avoids\nhaving to write code in your templates to display error messages if they are\npresent.\n\nThis does exactly the same thing as the example above but works with the\noriginal form definition and in fact will work with any HTML form regardless of\nhow it is generated because the validate decorator uses `formencode.htmlfill`\nto find HTML fields and replace them with the values were originally submitted.\n\n.. note:: \n\n    Python 2.3 doesn't support decorators so rather than using the\n    `@validate()` syntax you need to put `email =\n    validate(schema=EmailForm(), form='form')(email)` after the email\n    function's declaration.\n\n\nValidation the Long Way \n-----------------------\n\nThe `validate` decorator covers up a bit of work, and depending on your needs it's possible you could need direct access to FormEncode abilities it smoothes over. \n\nHere's the longer way to use the `EmailForm` schema: \n\n.. code-block:: python \n\n    # in the controller \n\n    def email(self): \n        schema = EmailForm() \n        try: \n            form_result = schema.to_python(request.params) \n        except formencode.validators.Invalid, error: \n            return 'Invalid: %s' % error \n        else: \n            return 'Your email is: %s' % form_result.get('email') \n\nIf the values entered are valid, the schema's `to_python()` method returns a\ndictionary of the validated and coerced `form_result`. This means that you can\nguarantee that the `form_result` dictionary contains values that are valid and\ncorrect Python objects for the data types desired.\n\nIn this case the email address is a string so `request.params['email']`\nhappens to be the same as `form_result['email']`. If our form contained a\nfield for age in years and we had used a `formencode.validators.Int()`\nvalidator, the value in `form_result` for the age would also be the correct\ntype; in this case a Python integer.\n\nFormEncode comes with a useful set of validators but you can also easily\ncreate your own. If you do create your own validators you will find it very\nuseful that all FormEncode schemas' `.to_python()` methods take a second\nargument named `state`. This means you can pass the Pylons `c` object\ninto your validators so that you can set any variables that your validators\nneed in order to validate a particular field as an attribute of the `c`\nobject. It can then be passed as the `c` object to the schema as follows:\n\n.. code-block:: python \n\n    c.domain = 'example.com' \n    form_result = schema.to_python(request.params, c) \n\nThe schema passes `c` to each validator in turn so that you can do things like this: \n\n.. code-block:: python \n\n    class SimpleEmail(formencode.validators.Email): \n        def _to_python(self, value, c): \n            if not value.endswith(c.domain): \n                raise formencode.validators.Invalid(\n                    'Email addresses must end in: %s' % \\ \n                        c.domain, value, c) \n            return formencode.validators.Email._to_python(self, value, c) \n\nFor this to work, make sure to change the `EmailForm` schema you've defined to use the new `SimpleEmail` validator. In other words, \n\n.. code-block:: python \n\n    email = formencode.validators.Email(not_empty=True) \n    # becomes: \n    email = SimpleEmail(not_empty=True) \n\n\nIn reality the invalid error message we get if we don't enter a valid email address isn't very useful. We really want to be able to redisplay the form with the value entered and the error message produced. Replace the line: \n\n.. code-block:: python \n\n    return 'Invalid: %s' % error \n\nwith the lines: \n\n.. code-block:: python \n\n    c.form_result = error.value \n    c.form_errors = error.error_dict or {} \n    return render('/form.mako') \n\nNow we will need to make some tweaks to `form.mako`. Make it look like this: \n\n.. code-block:: html+mako \n\n    ${h.form(h.url(action='email'), method='get')} \n\n    % if c.form_errors: \n    <h2>Please correct the errors</h2> \n    % else: \n    <h2>Enter Email Address</h2> \n    % endif \n\n    % if c.form_errors: \n    Email Address: ${h.text_field('email', value=c.form_result['email'] or '')} \n    <p>${c.form_errors['email']}</p> \n    % else: \n    Email Address: ${h.text_field('email')} \n    % endif \n\n    ${h.submit('Submit')} \n    ${h.end_form()} \n\nNow when the form is invalid the `form.mako` template is re-rendered with the error messages. \n\n\nOther Form Tools \n================ \n\nIf you are going to be creating a lot of forms you may wish to consider using `FormBuild <http://formbuild.org>`_ to help create your forms. To use it you create a custom Form object and use that object to build all your forms. You can then use the API to modify all aspects of the generation and use of all forms built with your custom Form by modifying its definition without any need to change the form templates. \n\nHere is an one example of how you might use it in a controller to handle a form submission: \n\n.. code-block:: python \n\n    # in the controller \n\n    def form(self): \n        results, errors, response = formbuild.handle( \n            schema=Schema(), # Your FormEncode schema for the form \n                             # to be validated \n            template='form.mako', # The template containg the code \n                                  # that builds your form \n            form=Form # The FormBuild Form definition you wish to use \n        )\n        if response: \n            # The form validation failed so re-display \n            # the form with the auto-generted response \n            # containing submitted values and errors or \n            # do something with the errors \n            return response \n        else: \n            # The form validated, do something useful with results. \n            ... \n\nFull documentation of all features is available in the `FormBuild manual <http://formbuild.org/manual.html>`_ which you should read before looking at `Using FormBuild in Pylons <http://formbuild.org/pylons.html>`_ \n\nLooking forward it is likely Pylons will soon be able to use the TurboGears widgets system which will probably become the recommended way to build forms in Pylons. \n"
  },
  {
    "path": "pylons/docs/en/gettingstarted.rst",
    "content": ".. _getting_started:\n\n===============\nGetting Started\n===============\n\nThis section is intended to get Pylons up and running as fast as\npossible and provide a quick overview of the project. Links are provided\nthroughout to encourage exploration of the various aspects of Pylons.\n\n\n************\nRequirements\n************\n\n* Python 2 series above and including 2.4 (Python 3 or later not supported at\n    this time)\n\n\n.. _installing_pylons:\n\n**********\nInstalling\n**********\n\nTo avoid conflicts with system-installed Python libraries, Pylons comes with a\nboot-strap Python script that sets up a \"virtual\" Python environment. Pylons will then be installed under the virtual environment.\n\n.. admonition:: By the Way\n\n    :term:`virtualenv` is a useful tool to create isolated Python environments.\n    In addition to isolating packages from possible system conflicts, it makes\n    it easy to install Python libraries using :term:`easy_install` without\n    dumping lots of packages into the system-wide Python.\n\n    The other great benefit is that no root access is required since all\n    modules are kept under the desired directory. This makes it easy\n    to setup a working Pylons install on shared hosting providers and other\n    systems where system-wide access is unavailable.\n\n1. Download the `go-pylons.py <http://www.pylonshq.com/download/1.0/go-pylons.py>`_ script.\n2. Run the script and specify a directory for the virtual environment to be created under:\n\n    .. code-block:: bash\n\n        $ python go-pylons.py mydevenv\n\n.. admonition:: Tip\n\n    The two steps can be combined on unix systems with curl using the\n    following short-cut:\n\n    .. code-block:: bash\n\n        $ curl https://raw.githubusercontent.com/Pylons/pylons/master/scripts/go-pylons.py | python - mydevenv\n\n    To isolate further from additional system-wide Python libraries, run\n    with the --no-site-packages option:\n\n    .. code-block:: bash\n\n        $ python go-pylons.py --no-site-packages mydevenv\n\n    | **How it Works**\n\n    The ``go-pylons.py`` script is little more than a basic :term:`virtualenv`\n    bootstrap script, that then does ``easy_install Pylons==1.0``. You could\n    do the equivilant steps by manually fetching the ``virtualenv.py`` script\n    and then installing Pylons like so:\n\n    .. code-block:: bash\n\n        curl -O http://bitbucket.org/ianb/virtualenv/raw/8dd7663d9811/virtualenv.py\n        python virtualenv.py mydevenv\n        mydevenv/bin/easy_install Pylons==1.0\n\n\nThis will leave a functional virtualenv and Pylons installation.\n\n\nActivate the virtual environment (scripts may also be run by specifying the\nfull path to the mydevenv/bin dir):\n\n.. code-block:: bash\n\n    $ source mydevenv/bin/activate\n\nOr on Window to activate:\n\n.. code-block:: text\n\n    > mydevenv\\Scripts\\activate.bat\n\n.. note::\n\n    If you get an error such as::\n\n        ImportError: No module named _md5\n\n    during the install. It is likely that your Python installation is missing\n    standard libraries needed to run Pylons. Debian and other systems using\n    debian packages most frequently encounter this, make sure to install\n    the ``python-dev`` packages and ``python-hashlib`` packages.\n\n\nWorking Directly From the Source Code\n=====================================\n\n`Mercurial <http://www.selenic.com/mercurial/wiki/>`_ must be installed to retrieve the latest development source for Pylons. `Mercurial packages <http://www.selenic.com/mercurial/wiki/index.cgi/BinaryPackages>`_ are also available for Windows, MacOSX, and other OS's.\n\nCheck out the latest code:\n\n.. code-block:: bash\n\n    $ hg clone http://bitbucket.org/bbangert/pylons/\n\nTo tell setuptools to use the version in the ``Pylons`` directory:\n\n.. code-block:: bash\n\n    $ cd pylons\n    $ python setup.py develop\n\nThe active version of Pylons is now the copy in this directory, and changes made there will be reflected for Pylons apps running.\n\n\n*************************\nCreating a Pylons Project\n*************************\n\nCreate a new project named ``helloworld`` with the following command:\n\n.. code-block:: bash\n\n    $ paster create -t pylons helloworld\n\n.. note::\n\n    Windows users must configure their ``PATH`` as described in :ref:`windows_notes`, otherwise they must specify the full path to the ``paster`` command (including the virtual environment bin directory).\n\nRunning this will prompt for two choices:\n\n1. which templating engine to use\n2. whether to include :term:`SQLAlchemy` support\n\nHit enter at each prompt to accept the defaults (Mako templating, no :term:`SQLAlchemy`).\n\nHere is the created directory structure with links to more information:\n\n- helloworld\n    - MANIFEST.in\n    - README.txt\n    - development.ini - :ref:`run-config`\n    - docs\n    - ez_setup.py\n    - helloworld (See the nested :ref:`helloworld directory <helloworld_dir>`)\n    - helloworld.egg-info\n    - setup.cfg\n    - setup.py - :ref:`setup-config`\n    - test.ini\n\n.. _helloworld_dir:\n\nThe nested ``helloworld directory`` looks like this:\n\n- helloworld\n    - __init__.py\n    - config\n        - environment.py - :ref:`environment-config`\n        - middleware.py - :ref:`middleware-config`\n        - routing.py - :ref:`url-config`\n    - controllers - :ref:`controllers`\n    - lib\n        - app_globals.py - :term:`app_globals`\n        - base.py\n        - helpers.py - :ref:`helpers`\n    - model - :ref:`models`\n    - public\n    - templates - :ref:`templates`\n    - tests - :ref:`testing`\n    - websetup.py - :ref:`run-config`\n\n\n\n***********************\nRunning the application\n***********************\n\nRun the web application:\n\n.. code-block:: bash\n\n    $ cd helloworld\n    $ paster serve --reload development.ini\n\nThe command loads the project's server configuration file in :file:`development.ini` and serves the Pylons application.\n\n.. note::\n\n    The ``--reload`` option ensures that the server is automatically reloaded\n    if changes are made to Python files or the :file:`development.ini`\n    config file. This is very useful during development. To stop the server\n    press :command:`Ctrl+c` or the platform's equivalent.\n\n    The paster serve command can be run anywhere, as long as the\n    development.ini path is properly specified. Generally during development\n    it's run in the root directory of the project.\n\nVisiting http://127.0.0.1:5000/ when the server is running will show the welcome page.\n\n\n***********\nHello World\n***********\n\nTo create the basic hello world application, first create a\n:term:`controller` in the project to handle requests:\n\n.. code-block:: bash\n\n    $ paster controller hello\n\nOpen the :file:`helloworld/controllers/hello.py` module that was created.\nThe default controller will return just the string 'Hello World':\n\n.. code-block:: python\n\n    import logging\n\n    from pylons import request, response, session, tmpl_context as c, url\n    from pylons.controllers.util import abort, redirect\n\n    from helloworld.lib.base import BaseController, render\n\n    log = logging.getLogger(__name__)\n\n    class HelloController(BaseController):\n\n        def index(self):\n            # Return a rendered template\n            #return render('/hello.mako')\n            # or, Return a response\n            return 'Hello World'\n\nAt the top of the module, some commonly used objects are imported automatically.\n\nNavigate to http://127.0.0.1:5000/hello/index where there should be a short text string saying \"Hello World\" (start up the app if needed):\n\n.. image:: _static/helloworld.png\n\n.. admonition:: Tip\n\n    :ref:`url-config` explains how URL's get mapped to controllers and\n    their methods.\n\nAdd a template to render some of the information that's in the :term:`environ`.\n\nFirst, create a :file:`hello.mako` file in the :file:`templates`\ndirectory with the following contents:\n\n.. code-block:: mako\n\n    Hello World, the environ variable looks like: <br />\n\n    ${request.environ}\n\nThe :term:`request` variable in templates is used to get information about the current request. :ref:`Template globals <template-globals>` lists all the variables Pylons makes available for use in templates.\n\nNext, update the :file:`controllers/hello.py` module so that the\nindex method is as follows:\n\n.. code-block:: python\n\n    class HelloController(BaseController):\n\n        def index(self):\n            return render('/hello.mako')\n\nRefreshing the page in the browser will now look similar to this:\n\n.. image:: _static/hellotemplate.png\n"
  },
  {
    "path": "pylons/docs/en/glossary.rst",
    "content": ".. _glossary:\n\nGlossary\n========\n\n.. glossary::\n\n    action\n        The class method in a Pylons applications' controller that handles\n        a request.\n\n    API\n        Application Programming Interface. The means of communication between\n        a programmer and a software program or operating system.\n\n    app_globals\n        The ``app_globals`` object is created on application instantiation by\n        the :class:`Globals` class in a projects :file:`lib/app_globals.py`\n        module.\n\n        This object is created once when the application is loaded by the\n        projects :file:`config/environment.py` module (See\n        :ref:`environment-config`). It remains persistent\n        during the lifecycle of the web application, and is *not* thread-safe\n        which means that it is best used for global options that should be\n        *read-only*, or as an object to attach db connections or other objects\n        which ensure their own access is thread-safe.\n\n    c\n        Commonly used alias for :term:`tmpl_context` to save on the typing\n        when using lots of controller populated variables in templates.\n\n    caching\n        The storage of the results of expensive or length computations for\n        later re-use at a point more quickly accessed by the end user.\n\n    CDN\n        Content Delivery Networks (CDN's) are generally globally distributed\n        content delivery networks optimized for low latency for static file\n        distribution. They can significantly increase page-load times by\n        ensuring that the static resources on a page are delivered by servers\n        geographically close to the client in addition to lightening the load\n        placed on the application server.\n\n    ColdFusion Components\n        CFCs represent an attempt by Macromedia to bring ColdFusion closer\n        to an Object Oriented Programming (OOP) language. ColdFusion is in\n        no way an OOP language, but thanks in part to CFCs, it does boast\n        some of the attributes that make OOP languages so popular.\n\n    \n    config\n        The :class:`~pylons.configuration.PylonsConfig` instance for a given\n        application. This can be accessed as ``pylons.config`` after an \n        Pylons application has been loaded.\n    \n    controller\n        The 'C' in MVC. The controller is given a request, does the necessary\n        logic to prepare data for display, then renders a template with\n        the data and returns it to the user. See :ref:`controllers`.\n\n    easy_install\n        A tool that lets you download, build, install and manage Python packages\n        and their dependencies. `easy_install`_ is the end-user facing component\n        of :term:`setuptools`.\n\n        Pylons can be installed with ``easy_install``, and applications built\n        with Pylons can easily be deployed this way as well.\n\n        .. seealso::\n            Pylons :ref:`deployment`\n\n        .. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall\n    \n    dotted name string\n        A reference to a Python module by name using a string to identify it,\n        e.g. ``pylons.controllers.util``. These strings are evaluated to\n        import the module being referenced without having to import it in\n        the code used. This is generally used to avoid import-time \n        side-effects.\n    \n    egg\n        Python egg's are bundled Python packages, generally installed by\n        a package called :term:`setuptools`. Unlike normal Python package\n        installs, egg's allow a few additional features, such as package\n        dependencies, and dynamic discovery.\n\n        .. seealso::\n            `The Quick Guide to Python Eggs <http://peak.telecommunity.com/DevCenter/PythonEggs>`_\n\n    EJBs\n        Enterprise JavaBeans (EJB) technology is the server-side component\n        architecture for Java Platform, Enterprise Edition (Java EE). EJB\n        technology enables rapid and simplified development of distributed,\n        transactional, secure and portable applications based on Java\n        technology.\n\n    environ\n        environ is a dictionary passed into all :term:`WSGI` application. It\n        generally contains unparsed header information, CGI style variables\n        and other objects inserted by :term:`WSGI Middleware`.\n\n    ETag\n        An ETag (entity tag) is an HTTP response header returned by an\n        HTTP/1.1 compliant web server used to determine change in content\n        at a given URL. See http://wikipedia.org/wiki/HTTP_ETag\n\n    g\n        Alias used in prior versions of Pylons for :term:`app_globals`.\n\n    Google App Engine\n      A cloud computing platform for hosting web applications implemented in\n      Python. Building Pylons applications for App Engine is facilitated by\n      Ian Bicking's `appengine-monkey project <http://code.google.com/p/appengine-monkey/>`_.\n\n      .. seealso::\n        `What is Google App Engine? - Official Doc <http://code.google.com/appengine/docs/whatisgoogleappengine.html>`_\n\n    h\n        The helpers reference, ``h``, is made available for use inside\n        templates to assist with common rendering tasks. ``h`` is just a\n        reference to the :file:`lib/helpers.py` module and can be used in the\n        same manner as any other module import.\n\n    Model-View-Controller\n        An architectural pattern used in software engineering. In Pylons, the\n        MVC paradigm is extended slightly with a pipeline that may transform\n        and extend the data available to a controller, as well as the Pylons\n        :term:`WSGI` app itself that determines the appropriate Controller\n        to call.\n\n        .. seealso::\n            `MVC at Wikipedia\n            <http://wikipedia.org/wiki/Model-View-Controller>`_\n\n    MVC\n        See :term:`Model-View-Controller`\n\n    ORM\n        (Object-Relational Mapper) Maps relational databases such as\n        MySQL, Postgres, Oracle to objects providing a cleaner API.\n        Most ORM's also make it easier to prevent SQL Injection attacks\n        by binding variables, and can handle generating sometimes\n        extensive SQL.\n\n    Pylons\n        A Python-based WSGI oriented web framework.\n\n    Rails\n        Abbreviated as RoR, Ruby on Rails (also referred to as just\n        Rails) is an open source Web application framework, written in Ruby\n\n    request\n        Refers to the current request being processed. Available to import\n        from :mod:`pylons` and is available for use in templates by the\n        same name. See :class:`~pylons.controllers.util.Request`.\n    \n    response\n        Refers to the response to the current request. Available to import\n        from :mod:`pylons` and is available for use in template by the same\n        name. See :class:`~pylons.controllers.util.Response`.\n\n    route\n        Routes determine how the URL's are mapped to the controllers and which\n        URL is generated. See :ref:`url-config`\n\n    setuptools\n        An extension to the basic distutils, setuptools allows packages to\n        specify package dependencies and have dynamic discovery of other\n        installed Python packages.\n\n        .. seealso::\n            `Building and Distributing Packages with setuptools <http://peak.telecommunity.com/DevCenter/setuptools>`_\n\n    SQLAlchemy\n        One of the most popular Python database object-relational mappers\n        (:term:`ORM`). `SQLAlchemy <http://www.sqlalchemy.org/>`_ is the default\n        ORM recommended in Pylons. SQLAlchemy at the ORM level can look similar\n        to Rails ActiveRecord, but uses the `DataMapper <http://www.martinfowler.com/eaaCatalog/dataMapper.html>`_\n        pattern for additional flexibility with the ability to map simple to\n        extremely complex databases.\n\n    tmpl_context\n        The ``tmpl_context`` is available in the :mod:`pylons` module, and\n        refers to the template context. Objects attached to it are available\n        in the template namespace as either ``tmpl_context`` or ``c`` for\n        convenience.\n\n    UI\n        User interface. The means of communication between a person\n        and a software program or operating system.\n\n    virtualenv\n        A tool to create isolated Python environments, designed to supersede the\n        ``workingenv`` package and `virtual python`_ configurations. In addition\n        to isolating packages from possible system conflicts, `virtualenv`_\n        makes it easy to install Python libraries using :term:`easy_install`\n        without dumping lots of packages into the system-wide Python.\n\n        The other great benefit is that no root access is required since all\n        modules are kept under the desired directory. This makes it easy\n        to setup a working Pylons install on shared hosting providers and other\n        systems where system-wide access is unavailable.\n\n        ``virtualenv`` is employed automatically by the ``go-pylons.py`` script\n        described in :ref:`getting_started`. The Pylons wiki has more\n        information on `working with virtualenv`_.\n\n        .. _virtual python: http://peak.telecommunity.com/DevCenter/EasyInstall#creating-a-virtual-python\n        .. _virtualenv: http://pypi.python.org/pypi/virtualenv\n        .. _working with virtualenv: http://wiki.pylonshq.com/display/pylonscookbook/Using+a+Virtualenv+Sandbox\n\n    web server gateway interface\n        A specification for web servers and application servers to\n        communicate with web applications. Also referred to by its\n        initials, as :term:`WSGI`.\n\n    WSGI\n        The `WSGI Specification <http://www.python.org/dev/peps/pep-0333/>`_,\n        also commonly referred to as PEP 333 and described by :pep:`333`.\n\n    WSGI Middleware\n        :term:`WSGI` Middleware refers to the ability of WSGI applications\n        to modify the environ, and/or the content of other WSGI applications\n        by being placed in between the request and the other WSGI application.\n\n        .. seealso::\n            :ref:`WSGI Middleware in Concepts of Pylons <wsgi-middleware>`\n            :ref:`WSGI Middleware Configuration <middleware-config>`\n"
  },
  {
    "path": "pylons/docs/en/helpers.rst",
    "content": ".. _helpers:\n\n=======\nHelpers\n=======\n\nHelpers are functions intended for usage in templates, to assist with common\nHTML and text manipulation, higher level constructs like a HTML\ntag builder (that safely escapes variables), and advanced functionality\nlike Pagination of data sets.\n\nThe majority of the helpers available in Pylons are provided by the\n:mod:`webhelpers` package. Some of these helpers are also used in controllers\nto prepare data for use in the template by other helpers, such as the\n:func:`~webhelpers.rails.secure_form_tag` function which has a corresponding \n:func:`~pylons.decorators.secure.authenticate_form`.\n\nTo make individual helpers available for use in templates under :term:`h`, the\nappropriate functions need to be imported in :file:`lib/helpers.py`. All the\nfunctions available in this file are then available under :term:`h` just like\nany other module reference.\n\nBy customizing the :file:`lib/helpers.py` module you can quickly add custom\nfunctions and classes for use in your templates.\n\nHelper functions are organized into modules by theme. All HTML generators are under the ``webhelpers_html`` package, except for a few third-party modules which are directly under ``webhelpers``. The webhelpers modules are separately documented, see :mod:`webhelpers`.\n\n.. _pagination:\n\nPagination\n==========\n\n.. note::\n\n    The `paginate` module is not compatible to the deprecated `pagination`\n    module that was provided with former versions of the Webhelpers package.\n\n\nPurpose of a paginator\n----------------------\n\nWhen you display large amounts of data like a result from an SQL query then\nusually you cannot display all the results on a single page. It would simply be\ntoo much. So you divide the data into smaller chunks. This is what a paginator\ndoes. It shows one page of chunk of data at a time. Imagine you are providing a\ncompany phonebook through the web and let the user search the entries. Assume\nthe search result contains 23 entries. You may decide to display no more than 10\nentries per page. The first page contains entries 1-10, the second 11-20 and the\nthird 21-23. And you also show a navigational element like\n``Page 1 of 3: [1] 2 3`` that allows the user to switch between the available\npages.\n\n\nThe ``Page`` class\n------------------\n\nThe :mod:`webhelpers` package provides a *paginate* module that can be used\nfor this purpose. It can create pages from simple Python lists as well as\nSQLAlchemy queries and SQLAlchemy select objects. The module provides a ``Page``\nobject that represents a single page of items from a larger result set. Such a\n``Page`` mainly behaves like a list of items on that page. Let's take the above\nexample of 23 items spread across 3 pages:\n\n.. code-block :: pycon\n       \n    # Create a list of items from 1 to 23\n    >>> items = range(1,24)\n    \n    # Import the paginate module\n    >>> import webhelpers.paginate\n    \n    # Create a Page object from the 'items' for the second page\n    >>> page2 = webhelpers.paginate.Page(items, page=2, items_per_page=10)\n\n    # The Page object can be printed (__repr__) to show details on the page\n    >>> page2\n\n        Page:\n        Collection type:  <type 'list'>\n        (Current) page:   2\n        First item:       11\n        Last item:        20\n        First page:       1\n        Last page:        3\n        Previous page:    1\n        Next page:        3\n        Items per page:   10\n        Number of items:  23\n        Number of pages:  3\n\n    # Show the items on this page\n    >>> list(page2)\n    \n        [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n\n    # Print the items in a for loop\n    >>> for i in page2: print \"This is entry\", i\n\n        This is entry 11\n        This is entry 12\n        This is entry 13\n        This is entry 14\n        This is entry 15\n        This is entry 16\n        This is entry 17\n        This is entry 18\n        This is entry 19\n        This is entry 20\n\nThere are further parameters to invoking a ``Page`` object. Please see\n:class:`webhelpers.paginate.Page`\n\n.. note::\n\n    Page numbers and item numbers start from 1. If you are accessing the\n    items on the page by their index please note that the first item is\n    ``item[1]`` instead of ``item[0]``.\n\n\nSwitching between pages using a `pager`\n---------------------------------------\n\nThe user needs a way to get to another page. This is usually done with a list\nof links like ``Page 3 of 41 - 1 2 [3] 4 5 .. 41``. Such a list can be\ncreated by the Page's :meth:`~webhelpers.paginate.Page.pager` method.\nTake the above example again:\n\n.. code-block:: pycon\n\n    >>> page2.pager()\n    \n        <a class=\"pager_link\" href=\"/content?page=1\">1</a>\n        <span class=\"pager_curpage\">2</span>\n        <a class=\"pager_link\" href=\"/content?page=3\">3</a>\n\nWithout the HTML tags it looks like ``1 [2] 3``. The links point to a URL\nwhere the respective page is found. And the current page (2) is highlighted.\n\nThe appearance of a pager can be customized. By default the format string\nis ``~2~`` which means it shows adjacent pages from the current page with\na maximal radius of 2. In a larger set this would look like\n``1 .. 34 35 [36] 37 38 .. 176``. The radius of 2 means that two pages before\nand after the current page 36 are shown.\n\nSeveral special variables can be used in the format string. See\n:meth:`~webhelpers.paginate.Page.pager` for a complete list. Some examples\nfor a pager of 20 pages while being on page 10 currently:\n\n.. code-block:: pycon\n\n    >>> page.pager()\n    \n        1 .. 8 9 [10] 11 12 .. 20\n        \n    >>> page.pager('~4~')\n    \n        1 .. 6 7 8 9 [10] 11 12 13 14 .. 20\n        \n    >>> page.pager('Page $page of $page_count - ~3~')\n    \n        Page 10 of 20 - 1 .. 7 8 9 [10] 11 12 13 .. 20\n        \n    >>> page.pager('$link_previous $link_next ~2~')\n    \n        < > 1 .. 8 9 [10] 11 12 .. 20\n        \n    >>> page.pager('Items $first_item - $last_item / ~2~')\n    \n        Items 91 - 100 / 1 .. 8 9 [10] 11 12 .. 20\n\n\nPaging over an SQLAlchemy query\n-------------------------------\n\nIf the data to page over comes from a database via SQLAlchemy then the\n``paginate`` module can access a ``query`` object directly. This is useful\nwhen using ORM-mapped models. Example:\n\n.. code-block:: pycon\n\n    >>> employee_query = Session.query(Employee)\n    >>> page2 = webhelpers.paginate.Page(\n            employee_query,\n            page=2,\n            items_per_page=10)\n    >>> for employee in page2: print employee.first_name\n\n        John\n        Jack\n        Joseph\n        Kay\n        Lars\n        Lynn\n        Pamela\n        Sandra\n        Thomas\n        Tim\n\nThe `paginate` module is smart enough to only query the database for the\nobjects that are needed on this page. E.g. if a page consists of the items\n11-20 then SQLAlchemy will be asked to fetch exactly that 10 rows\nthrough `LIMIT` and `OFFSET` in the actual SQL query. So you must not load\nthe complete result set into memory and pass that. Instead always pass\na `query` when creating a `Page`.\n\n\nPaging over an SQLAlchemy select\n--------------------------------\n\nSQLAlchemy also allows to run arbitrary SELECTs on database tables.\nThis is useful for non-ORM queries. `paginate` can use such select\nobjects, too. Example:\n\n.. code-block:: pycon\n\n    >>> selection = sqlalchemy.select([Employee.c.first_name])\n    >>> page2 = webhelpers.paginate.Page(\n            selection,\n            page=2,\n            items_per_page=10,\n            sqlalchemy_session=model.Session)\n    >>> for first_name in page2: print first_name\n    \n        John\n        Jack\n        Joseph\n        Kay\n        Lars\n        Lynn\n        Pamela\n        Sandra\n        Thomas\n        Tim\n\nThe only difference to using SQLAlchemy *query* objects is that you need to\npass an SQLAlchemy *session* via the ``sqlalchemy_session`` parameter.\nA bare ``select`` does not have a database connection assigned. But the session\nhas.\n\n\nUsage in a Pylons controller and template\n-----------------------------------------\n\nA simple example to begin with.\n\nController:\n\n.. code-block:: python\n\n    def list(self):\n        c.employees = webhelpers.paginate.Page(\n            model.Session.query(model.Employee),\n            page = int(request.params['page']),\n            items_per_page = 5)\n        return render('/employees/list.mako')\n\nTemplate:\n\n.. code-block:: mako\n\n    ${c.employees.pager('Page $page: $link_previous $link_next ~4~')}\n    <ul>\n    % for employee in c.employees:\n        <li>${employee.first_name} ${employee.last_name}</li>\n    % endfor\n    </ul>\n\nThe `pager()` creates links to the previous URL and just sets the\n*page* parameter appropriately. That's why you need to pass the requested page\nnumber (``request.params['page']``) when you create a `Page`.\n\n\nPartial updates with AJAX\n-------------------------\n\nUpdating a page partially is easy. All it takes is a little Javascript\nthat - instead of loading the complete page - updates just the part\nof the page containing the paginated items. The ``pager()`` method accepts an\n``onclick`` parameter for that purpose. This value is added as an ``onclick``\nparameter to the A-HREF tags. So the ``href`` parameter points to a URL\nthat loads the complete page while the ``onclick`` parameter provides Javascript\nthat loads a partial page. An example (using the jQuery Javascript library for\nsimplification) may help explain that.\n\nController:\n\n.. code-block:: python\n\n    def list(self):\n        c.employees = webhelpers.paginate.Page(\n            model.Session.query(model.Employee),\n            page = int(request.params['page']),\n            items_per_page = 5)\n        if 'partial' in request.params:\n            # Render the partial page\n            return render('/employees/list-partial.mako')\n        else:\n            # Render the full page\n            return render('/employees/list-full.mako')\n\nTemplate ``list-full.mako``:\n\n.. code-block:: mako\n\n    <html>\n        <head>\n            ${webhelpers.html.tags.javascript_link('/public/jQuery.js')}\n        </head>\n        <body>\n            <div id=\"page-area\">\n                <%include file=\"list-partial.mako\"/>\n            </div>\n        </body>\n    </html>\n\nTemplate ``list-partial.mako``:\n\n.. code-block:: mako\n\n    ${c.employees.pager(\n        'Page $page: $link_previous $link_next ~4~',\n        onclick=\"$('#my-page-area').load('%s'); return false;\")}\n    <ul>\n    % for employee in c.employees:\n        <li>${employee.first_name} ${employee.last_name}</li>\n    % endfor\n    </ul>\n\nTo avoid code duplication in the template the full template includes the partial\ntemplate. If a partial page load is requested then just the\n``list-partial.mako`` gets rendered. And if a full page load is requested then\nthe ``list-full.mako`` is rendered which in turn includes the\n``list-partial.mako``.\n\nThe ``%s`` variable in the ``onclick`` string gets replaced with a URL pointing\nto the respective page with a ``partial=1`` added (the name of the parameter can be customized through the ``partial_param`` parameter). Example:\n\n* ``href`` parameter points to ``/employees/list?page=3``\n* ``onclick`` parameter contains Javascript loading\n  ``/employees/list?page=3&partial=1``\n\njQuery's syntax to load a URL into a certain DOM object (e.g. a DIV) is simply:\n\n.. code-block:: javascript\n\n    $('#some-id').load('/the/url')\n\nThe advantage of this technique is that it degrades gracefully. If the user does\nnot have Javascript enabled then a full page is loaded. And if Javascript works\nthen a partial load is done through the ``onclick`` action.\n\n\n.. _secure-forms:\n\nSecure Form Tag Helpers\n=======================\n\nFor prevention of Cross-site request forgery (CSRF) attacks.\n\nGenerates form tags that include client-specific authorization tokens to be\nverified by the destined web app.\n\nAuthorization tokens are stored in the client's session. The web app can then\nverify the request's submitted authorization token with the value in the\nclient's session.\n\nThis ensures the request came from the originating page. See the wikipedia entry\nfor `Cross-site request forgery`__ for more information.\n\n.. __: http://en.wikipedia.org/wiki/Cross-site_request_forgery\n\nPylons provides an ``authenticate_form`` decorator that does this verification\non the behalf of controllers.\n\nThese helpers depend on Pylons' ``session`` object.  Most of them can be easily \nported to another framework by changing the API calls.\n\nThe helpers are implemented in such a way that it should be easy for developers\nto create their own helpers if using helpers for AJAX calls.\n\n:func:`authentication_token` returns the current authentication token, creating one\nand storing it in the session if it doesn't already exist.\n\n:func:`auth_token_hidden_field` creates a hidden field containing the authentication token.\n\n:func:`secure_form` is :func:`form` plus :func:`auth_token_hidden_field`.\n\n"
  },
  {
    "path": "pylons/docs/en/i18n.rst",
    "content": ".. _i18n:\n\n=====================================\nInternationalization and Localization\n=====================================\n\nIntroduction\n============\n\nInternationalization and localization are means of adapting software for \nnon-native environments, especially for other nations and cultures. \n\nParts of an application which might need to be localized might include: \n\n* Language \n* Date/time format \n* Formatting of numbers e.g. decimal points, positioning of separators, character used as separator \n* Time zones (UTC in internationalized environments) \n* Currency \n* Weights and measures \n\nThe distinction between internationalization and localization is subtle but \nimportant. Internationalization is the adaptation of products for potential use\nvirtually everywhere, while localization is the addition of special features \nfor use in a specific locale. \n\nFor example, in terms of language used in software, internationalization is the\nprocess of marking up all strings that might need to be translated whilst \nlocalization is the process of producing translations for a particular locale. \n\nPylons provides built-in support to enable you to internationalize language but\nleaves you to handle any other aspects of internationalization which might be \nappropriate to your application. \n\n.. note:: \n\n    Internationalization is often abbreviated as I18N (or i18n or I18n) where the \n    number 18 refers to the number of letters omitted. \n    Localization is often abbreviated L10n or l10n in the same manner. These \n    abbreviations also avoid picking one spelling (internationalisation vs. \n    internationalization, etc.) over the other. \n\nIn order to represent characters from multiple languages, you will \nneed to utilize Unicode. This document assumes you have read the \n:ref:`unicode`. \n\nBy now you should have a good idea of what Unicode is, how to use it in Python \nand which areas of you application need to pay specific attention to decoding and \nencoding Unicode data. \n\nThis final section will look at the issue of making your application work with \nmultiple languages. \n\nPylons uses the `Python gettext module  <http://docs.python.org/lib/module-gettext.html>`_ for internationalization. \nIt is based off the `GNU gettext API <http://www.gnu.org/software/gettext/>`_. \n\nGetting Started \n=============== \n\nEverywhere in your code where you want strings to be available in different \nlanguages you wrap them in the ``_()`` function. There are also a number of \nother translation functions which are documented in the API reference at \nhttp://pylonshq.com/docs/module-pylons.i18n.translation.html \n\n.. note:: \n\n    The ``_()`` function is a reference to the ``ugettext()`` function. ``_()`` is a convention for marking text to be translated and saves on keystrokes. ``ugettext()`` is the Unicode version of ``gettext()``; it returns unicode strings. \n\nIn our example we want the string ``'Hello'`` to appear in three different \nlanguages: English, French and Spanish. We also want to display the word \n``'Hello'`` in the default language. We'll then go on to use some plural words \ntoo. \n\nLets call our project ``translate_demo``: \n\n.. code-block:: bash \n\n    $ paster create -t pylons translate_demo \n\nNow lets add a friendly controller that says hello: \n\n.. code-block:: bash \n\n    $ cd translate_demo \n    $ paster controller hello \n\nEdit ``controllers/hello.py`` to make use of the ``_()`` function everywhere \nwhere the string ``Hello`` appears: \n\n.. code-block:: python \n\n    import logging \n\n    from pylons.i18n import get_lang, set_lang \n\n    from translate_demo.lib.base import * \n\n    log = logging.getLogger(__name__) \n\n    class HelloController(BaseController): \n\n        def index(self): \n            response.write('Default: %s<br />' % _('Hello')) \n            for lang in ['fr','en','es']: \n                set_lang(lang) \n            response.write(\"%s: %s<br />\" % (get_lang(), _('Hello'))) \n\nWhen writing wrapping strings in the gettext functions, it is important not to \npiece sentences together manually; certain languages might need to invert the \ngrammars. Don't do this: \n\n.. code-block:: python \n\n    # BAD! \n    msg = _(\"He told her \") \n    msg += _(\"not to go outside.\") \n\nbut this is perfectly acceptable: \n\n.. code-block:: python \n\n    # GOOD \n    msg = _(\"He told her not to go outside\") \n\nThe controller has now been internationalized, but it will raise a \n``LanguageError`` until we have setup the alternative language catalogs. \n\nGNU gettext use three types of files in the translation framework. \n\nPOT (Portable Object Template) files \n------------------------------------\n\nThe first step in the localization process. A program is used to search \nthrough your project's source code and pick out every string passed to one \nof the translation functions, such as ``_()``. This list is put together in \na specially-formatted template file that will form the basis of all \ntranslations. This is the ``.pot`` file. \n\nPO (Portable Object) files \n--------------------------\n\nThe second step in the localization process. Using the POT file as a \ntemplate, the list of messages are translated and saved as a ``.po`` file. \n\nMO (Machine Object) files \n-------------------------\n\nThe final step in the localization process. The PO file is run through a \nprogram that turns it into an optimized machine-readable binary file, which \nis the ``.mo`` file. Compiling the translations to machine code makes the \nlocalized program much faster in retrieving the translations while it is \nrunning. \n\nGNU gettext provides a suite of command line programs for extracting messages \nfrom source code and working with the associated gettext catalogs. The `Babel \n<http://babel.edgewall.org/>`_ project provides pure Python alternative \nversions of these tools. Unlike the GNU gettext tool `xgettext`, Babel \nsupports extracting translatable strings from Python templating languages \n(currently Mako and Genshi). \n\nUsing Babel \n===========\n\n.. image:: _static/babel_logo.png \n\nTo use Babel, you must first install it via easy_install. Run the command: \n\n.. code-block:: bash \n\n    $ easy_install Babel \n\nPylons (as of 0.9.6) includes some sane defaults for Babel's distutils commands\nin the setup.cfg file. \n\nIt also includes an extraction method mapping in the setup.py file. It is \ncommented out by default, to avoid distutils warning about it being an \nunrecognized option when Babel is not installed. These lines should be \nuncommented before proceeding with the rest of this walk through: \n\n.. code-block :: python \n\n    message_extractors = {'translate_demo': [\n            ('**.py', 'python', None),\n            ('templates/**.mako', 'mako', None),\n            ('public/**', 'ignore', None)]},\n\n\nWe'll use Babel to extract messages to a ``.pot`` file in your project's \n``i18n`` directory. First, the directory needs to be created. Don't forget to \nadd it to your revision control system if one is in use: \n\n.. code-block:: bash \n\n    $ cd translate_demo \n    $ mkdir translate_demo/i18n \n    $ svn add translate_demo/i18n \n\nNext we can extract all messages from the project with the following command: \n\n.. code-block:: bash \n\n    $ python setup.py extract_messages \n    running extract_messages \n    extracting messages from translate_demo/__init__.py \n    extracting messages from translate_demo/websetup.py \n    ... \n    extracting messages from translate_demo/tests/functional/test_hello.py \n    writing PO template file to translate_demo/i18n/translate_demo.pot \n\nThis will create a ``.pot`` file in the ``i18n`` directory that looks something\nlike this: \n\n.. code-block:: pot \n\n    # Translations template for translate_demo. \n    # Copyright (C) 2007 ORGANIZATION \n    # This file is distributed under the same license as the translate_demo project. \n    # FIRST AUTHOR <EMAIL@ADDRESS>, 2007. \n    # \n    #, fuzzy \n    msgid \"\" \n    msgstr \"\" \n    \"Project-Id-Version: translate_demo 0.0.0\\n\" \n    \"Report-Msgid-Bugs-To: EMAIL@ADDRESS\\n\" \n    \"POT-Creation-Date: 2007-08-02 18:01-0700\\n\" \n    \"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\" \n    \"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\" \n    \"Language-Team: LANGUAGE <LL@li.org>\\n\" \n    \"MIME-Version: 1.0\\n\" \n    \"Content-Type: text/plain; charset=utf-8\\n\" \n    \"Content-Transfer-Encoding: 8bit\\n\" \n    \"Generated-By: Babel 0.9dev-r215\\n\" \n\n    #: translate_demo/controllers/hello.py:10 translate_demo/controllers/hello.py:13 \n    msgid \"Hello\" \n    msgstr \"\" \n\nThe ``.pot`` details that appear here can be customized via the \n``extract_messages`` configuration in your project's ``setup.cfg`` (See the \n`Babel Command-Line Interface Documentation \n<http://babel.edgewall.org/wiki/Documentation/cmdline.html#extract>`_ for all \nconfiguration options). \n\nNext, we'll initialize a catalog (``.po`` file) for the Spanish language: \n\n.. code-block:: bash \n\n    $ python setup.py init_catalog -l es \n    running init_catalog \n    creating catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' based on \n    'translate_demo/i18n/translate_demo.pot' \n\nThen we can edit the last line of the new Spanish ``.po`` file to add a \ntranslation of ``\"Hello\"``: \n\n.. code-block:: bash \n\n    msgid \"Hello\" \n    msgstr \"¡Hola!\" \n\nFinally, to utilize these translations in our application, we need to compile \nthe ``.po`` file to a ``.mo`` file: \n\n.. code-block:: bash \n\n    $ python setup.py compile_catalog \n    running compile_catalog \n    1 of 1 messages (100%) translated in 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' \n    compiling catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' to \n    'translate_demo/i18n/es/LC_MESSAGES/translate_demo.mo' \n\nWe can also use the ``update_catalog`` command to merge new messages from the \n``.pot`` to the ``.po`` files. For example, if we later added the following \nline of code to the end of HelloController's index method: \n\n.. code-block :: python \n\n    response.write('Goodbye: %s' % _('Goodbye')) \n\nWe'd then need to re-extract the messages from the project, then run the \n``update_catalog`` command: \n\n.. code-block:: bash \n\n    $ python setup.py extract_messages \n    running extract_messages \n    extracting messages from translate_demo/__init__.py \n    extracting messages from translate_demo/websetup.py \n    ... \n    extracting messages from translate_demo/tests/functional/test_hello.py \n    writing PO template file to translate_demo/i18n/translate_demo.pot \n    $ python setup.py update_catalog \n    running update_catalog \n    updating catalog 'translate_demo/i18n/es/LC_MESSAGES/translate_demo.po' based on \n    'translate_demo/i18n/translate_demo.pot' \n\nWe'd then edit our catalog to add a translation for \"Goodbye\", and recompile \nthe ``.po`` file as we did above. \n\nFor more information, see the `Babel documentation \n<http://babel.edgewall.org/wiki/Documentation/index.html>`_ and the `GNU \nGettext Manual <http://www.gnu.org/software/gettext/manual/gettext.html>`_. \n\nBack To Work \n============\n\nNext we'll need to repeat the process of creating a ``.mo`` file for the ``en``\nand ``fr`` locales: \n\n.. code-block:: bash \n\n    $ python setup.py init_catalog -l en \n    running init_catalog \n    creating catalog 'translate_demo/i18n/en/LC_MESSAGES/translate_demo.po' based on \n    'translate_demo/i18n/translate_demo.pot' \n    $ python setup.py init_catalog -l fr \n    running init_catalog \n    creating catalog 'translate_demo/i18n/fr/LC_MESSAGES/translate_demo.po' based on \n    'translate_demo/i18n/translate_demo.pot' \n\nModify the last line of the ``fr`` catalog to look like this: \n\n.. code-block:: po \n\n    #: translate_demo/controllers/hello.py:10 translate_demo/controllers/hello.py:13 \n    msgid \"Hello\" \n    msgstr \"Bonjour\" \n\nSince our original messages are already in English, the ``en`` catalog can stay\nblank; gettext will fallback to the original. \n\nOnce you've edited these new ``.po`` files and compiled them to ``.mo`` files, \nyou'll end up with an ``i18n`` directory containing: \n\n.. code-block:: text \n\n    i18n/translate_demo.pot \n    i18n/en/LC_MESSAGES/translate_demo.po \n    i18n/en/LC_MESSAGES/translate_demo.mo \n    i18n/es/LC_MESSAGES/translate_demo.po \n    i18n/es/LC_MESSAGES/translate_demo.mo \n    i18n/fr/LC_MESSAGES/translate_demo.po \n    i18n/fr/LC_MESSAGES/translate_demo.mo \n\nTesting the Application \n=======================\n\nStart the server with the following command: \n\n.. code-block:: bash \n\n    $ paster serve --reload development.ini \n\nTest your controller by visiting http://localhost:5000/hello. You should see \nthe following output: \n\n.. code-block:: text \n\n    Default: Hello \n    fr: Bonjour \n    en: Hello \n    es: ¡Hola! \n\nYou can now set the language used in a controller on the fly. \n\nFor example this could be used to allow a user to set which language they \nwanted your application to work in. You could save the value to the session \nobject: \n\n.. code-block:: python \n\n    session['lang'] = 'en' \n    session.save() \n\nthen on each controller call the language to be used could be read from the \nsession and set in your controller's ``__before__()`` method so that the pages \nremained in the same language that was previously set: \n\n.. code-block:: python \n\n    def __before__(self): \n        if 'lang' in session: \n            set_lang(session['lang']) \n\nPylons also supports defining the default language to be used in the \nconfiguration file. Set a ``lang`` variable to the desired default language in \nyour ``development.ini`` file, and Pylons will automatically call ``set_lang`` \nwith that language at the beginning of every request. \n\nE.g. to set the default language to Spanish, you would add ``lang = es`` to \nyour ``development.ini``: \n\n.. code-block:: ini \n\n    [app:main] \n    use = egg:translate_demo \n    lang = es \n\nIf you are running the server with the ``--reload`` option the server will \nautomatically restart if you change the ``development.ini`` file. Otherwise \nrestart the server manually and the output would this time be as follows: \n\n.. code-block:: text \n\n    Default: ¡Hola! \n    fr: Bonjour \n    en: Hello \n    es: ¡Hola! \n\nFallback Languages \n==================\n\nIf your code calls ``_()`` with a string that doesn't exist at all in your \nlanguage catalog, the string passed to ``_()`` is returned instead. \n\nModify the last line of the hello controller to look like this: \n\n.. code-block:: python \n\n    response.write(\"%s %s, %s\" % (_('Hello'), _('World'), _('Hi!'))) \n\n.. warning :: \n\n    Of course, in real life breaking up sentences in this way is very dangerous \n    because some grammars might require the order of the words to be different. \n\nIf you run the example again the output will be: \n\n.. code-block:: text \n\n    Default: ¡Hola! \n    fr: Bonjour World! \n    en: Hello World! \n    es: ¡Hola! World! \n\nThis is because we never provided a translation for the string ``'World!'`` so \nthe string itself is used. \n\nPylons also provides a mechanism for fallback languages, so that you can \nspecify other languages to be used if the word is omitted from the main \nlanguage's catalog. \n\nIn this example we choose ``fr`` as the main language but ``es`` as a fallback:\n\n.. code-block:: python \n\n    import logging \n\n    from pylons.i18n import set_lang \n\n    from translate_demo.lib.base import * \n\n    log = logging.getLogger(__name__) \n\n    class HelloController(BaseController): \n\n        def index(self): \n            set_lang(['fr', 'es']) \n            return \"%s %s, %s\" % (_('Hello'), _('World'), _('Hi!')) \n\nIf ``Hello`` is in the ``fr`` ``.mo`` file as ``Bonjour``, ``World`` is only in\n``es`` as ``Mundo`` and none of the catalogs contain ``Hi!``, you'll get the \nmultilingual message: ``Bonjour Mundo, Hi!``. This is a combination of the \nFrench, Spanish and original (English in this case, as defined in our source \ncode) words. \n\nYou can also add fallback languages after calling ``set_lang`` via the\n``pylons.i18n.add_fallback`` function. Translations will be tested in the order\nyou add them.\n\n.. note:: \n\n   Fallbacks are reset after calling ``set_lang(lang)`` -- that is, fallbacks\n   are associated with the currently selected language.\n\nOne case where using fallbacks in this way is particularly useful is when you \nwish to display content based on the languages requested by the browser in the \n``HTTP_ACCEPT_LANGUAGE`` header. Typically the browser may submit a number of \nlanguages so it is useful to be add fallbacks in the order specified by the \nbrowser so that you always try to display words in the language of preference \nand search the other languages in order if a translation cannot be found. The \nlanguages defined in the ``HTTP_ACCEPT_LANGUAGE`` header are available in \nPylons as ``request.languages`` and can be used like this: \n\n.. code-block:: python \n\n    for lang in request.languages: \n        add_fallback(lang) \n\n\nTranslations Within Templates \n============================= \n\nYou can also use the ``_()`` function within templates in exactly the same way \nyou do in code. For example, in a Mako template: \n\n.. code-block:: mako \n\n    ${_('Hello')} \n\nwould produce the string ``'Hello'`` in the language you had set. \n\nBabel currently supports extracting gettext messages from Mako and Genshi \ntemplates. The Mako extractor also provides support for translator comments. \nBabel can be extended to extract messages from other sources via a `custom \nextraction method plugin \n<http://babel.edgewall.org/wiki/Documentation/messages.html#writing-extraction-methods>`_. \n\nPylons (as of 0.9.6) automatically configures a Babel extraction mapping for \nyour Python source code and Mako templates. This is defined in your project's \nsetup.py file: \n\n.. code-block:: python \n\n    message_extractors = {'translate_demo': [\n            ('**.py', 'python', None),\n            ('templates/**.mako', 'mako', None),\n            ('public/**', 'ignore', None)]},\n\nFor a project using Genshi instead of Mako, the Mako line might be replaced with: \n\n.. code-block:: python \n\n    ('templates/**.html, 'genshi', None), \n\nSee `Babel's documentation on Message Extraction \n<http://babel.edgewall.org/wiki/Documentation/messages.html#message-extraction>`_ \nfor more information. \n\nLazy Translations \n================= \n\nOccasionally you might come across a situation when you need to translate a \nstring when it is accessed, not when the ``_()`` or other functions are called.\n\nConsider this example: \n\n.. code-block:: python \n\n    import logging \n\n    from pylons.i18n import get_lang, set_lang \n\n    from translate_demo.lib.base import * \n\n    log = logging.getLogger(__name__) \n\n    text = _('Hello') \n\n    class HelloController(BaseController): \n\n        def index(self): \n            response.write('Default: %s<br />' % _('Hello')) \n            for lang in ['fr','en','es']: \n                set_lang(lang) \n            response.write(\"%s: %s<br />\" % (get_lang(), _('Hello'))) \n            response.write('Text: %s<br />' % text) \n\nIf we run this we get the following output: \n\n.. code-block:: text \n\n    Default: Hello \n    ['fr']: Bonjour \n    ['en']: Good morning \n    ['es']: Hola \n    Text: Hello \n\nThis is because the function ``_('Hello')`` just after the imports is called \nwhen the default language is ``en`` so the variable ``text`` gets the value of \nthe English translation even though when the string was used the default \nlanguage was Spanish. \n\nThe rule of thumb in these situations is to try to avoid using the translation \nfunctions in situations where they are not executed on each request. For \nsituations where this isn't possible, perhaps because you are working with \nlegacy code or with a library which doesn't support internationalization, you \nneed to use lazy translations. \n\nIf we modify the above example so that the import statements and assignment to \n``text`` look like this: \n\n.. code-block:: python \n\n    from pylons.i18n import get_lang, lazy_gettext, set_lang \n\n    from helloworld.lib.base import * \n\n    log = logging.getLogger(__name__) \n\n    text = lazy_gettext('Hello') \n\nthen we get the output we expected: \n\n.. code-block:: text \n\n    Default: Hello \n    ['fr']: Bonjour \n    ['en']: Good morning \n    ['es']: Hola \n    Text: Hola \n\nThere are lazy versions of all the standard Pylons `translation functions \n<http://pylonshq.com/docs/module-pylons.i18n.translation.html>`_. \n\nThere is one drawback to be aware of when using the lazy translation functions:\nthey are not actually strings. This means that if our example had used the \nfollowing code it would have failed with an error ``cannot concatenate 'str' \nand 'LazyString' objects``: \n\n.. code-block:: python \n\n    response.write('Text: ' + text + '<br />') \n\nFor this reason you should only use the lazy translations where absolutely \nnecessary and should always ensure they are converted to strings by calling \n``str()`` or ``repr()`` before they are used in operations with real strings. \n\nProducing a Python Egg \n====================== \n\nFinally you can produce an egg of your project which includes the translation \nfiles like this: \n\n.. code-block:: bash \n\n    $ python setup.py bdist_egg \n\nThe ``setup.py`` automatically includes the ``.mo`` language catalogs your \napplication needs so that your application can be distributed as an egg. This \nis done with the following line in your ``setup.py`` file: \n\n.. code-block:: python \n\n    package_data={'translate_demo': ['i18n/*/LC_MESSAGES/*.mo']}, \n\nPlural Forms \n============ \n\nPylons also provides the ``ungettext()`` function. It's designed for \ninternationalizing plural words, and can be used as follows: \n\n.. code-block:: python \n\n    ungettext('There is %(num)d file here', 'There are %(num)d files here',\n              n) % {'num': n}\n\nPlural forms have a different type of entry in ``.pot``/``.po`` files, as \ndescribed in `The Format of PO Files \n<http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#PO-Files>`_ \nin `GNU Gettext's Manual \n<http://www.gnu.org/software/gettext/manual/gettext.html>`_: \n\n.. code-block:: pot \n\n    #: translate_demo/controllers/hello.py:12 \n    #, python-format \n    msgid \"There is %(num)d file here\" \n    msgid_plural \"There are %(num)d files here\" \n    msgstr[0] \"\" \n    msgstr[1] \"\" \n\nOne thing to keep in mind is that other languages don't have the same plural \nforms as English. While English only has 2 plural forms, singular and plural, \nSlovenian has 4! That means that you *must* use ugettext for proper \npluralization. Specifically, the following will not work: \n\n.. code-block:: python \n\n    # BAD! \n    if n == 1: \n        msg = _(\"There was no dog.\") \n    else: \n        msg = _(\"There were no dogs.\") \n\nSummary \n=======\n\nThis document only covers the basics of internationalizing and localizing a web\napplication. \n\nGNU Gettext is an extensive library, and the GNU Gettext Manual is highly \nrecommended for more information. \n\nBabel also provides support for interfacing to the CLDR (Common Locale Data \nRepository), providing access to various locale display names, localized number\nand date formatting, etc. \n\nYou should also be able to internationalize and then localize your application \nusing Pylons' support for GNU gettext. \n\nFurther Reading \n===============\n\nhttp://en.wikipedia.org/wiki/Internationalization \n\nPlease feel free to report any mistakes to the Pylons mailing list or to the \nauthor. Any corrections or clarifications would be gratefully received.\n\n.. note:: \n\n    This is a work in progress. We hope the internationalization, localization \n    and Unicode support in Pylons is now robust and flexible but we would \n    appreciate hearing about any issues we have. Just drop a line to the \n    pylons-discuss mailing list on Google Groups. \n\n:mod:`babel.core` -- Babel core classes\n===================================================\n\n.. module:: babel.core\n\n.. automodule:: babel\n\nModule Contents\n---------------\n\n.. autoclass:: Locale\n    :members:\n\n.. autofunction:: default_locale\n.. autofunction:: negotiate_locale\n.. autofunction:: parse_locale\n\n:mod:`babel.localedata` --- Babel locale data\n====================================================\n\n.. automodule:: babel.localedata\n\n.. autofunction:: exists\n.. autofunction:: exists\n\n:mod:`babel.dates` -- Babel date classes\n===================================================\n\n.. automodule:: babel.dates\n\nModule Contents\n---------------\n\n.. autoclass:: DateTimeFormat\n    :members:\n.. autoclass:: DateTimePattern\n    :members:\n\n:mod:`babel.numbers` -- Babel number classes\n===================================================\n\n.. automodule:: babel.numbers\n\nModule Contents\n---------------\n\n.. autoclass:: NumberFormatError\n    :members:\n\n.. autoclass:: NumberPattern\n    :members: __init__, apply\n\n.. autofunction:: format_number\n.. autofunction:: format_decimal\n.. autofunction:: format_percent\n.. autofunction:: format_scientific\n.. autofunction:: parse_number\n.. autofunction:: parse_decimal\n\n\n.. autofunction: format_currency\n"
  },
  {
    "path": "pylons/docs/en/index.rst",
    "content": "Pylons Reference Documentation\n==============================\n\n.. image:: _static/pylon1.jpg\n   :alt: The First Pylon of the Ramesseum, Thebes is approximately 69m long and 22m high, and marks the entrance to the Main Temple and the First Courtyard.\n   :align: center\n   :height: 255\n   :width: 780\n\nGetting Started with Pylons\n---------------------------\n\n.. toctree::\n    :maxdepth: 2\n    \n    gettingstarted\n    concepts\n\nMVC Reference\n-------------\n\n.. toctree::\n    :maxdepth: 2\n\n    controllers\n    views\n    models\n    advanced_models\n\nProject Configuration and Logging\n---------------------------------\n\n.. toctree::\n    :maxdepth: 2\n\n    configuration\n    logging\n\nForms, Validation, and Helpers\n------------------------------\n\n.. toctree::\n    :maxdepth: 2\n\n    helpers\n    forms\n\nInternationalization, Sessions, and Caching\n-------------------------------------------\n\n.. toctree::\n    :maxdepth: 2\n\n    i18n\n    sessions\n    caching\n\nTesting, Upgrading, and Deploying\n---------------------------------\n\n.. toctree::\n    :maxdepth: 2\n\n    testing\n    debugging\n    upgrading\n    deployment\n\nInstallation for Windows / Python 2.3\n-------------------------------------\n\n.. toctree::\n    :maxdepth: 2\n\n    python23_install\n    windowsnotes\n\nPylons on Jython\n----------------\n\n.. toctree::\n    :maxdepth: 2\n\n    jython\n\nAdvanced Pylons\n---------------\n\n.. toctree::\n    :maxdepth: 2\n\n    security_policy_for_bugs\n    wsgi_support\n    advanced_pylons/index\n    execution\n\n\nModule Listing\n--------------\n\n.. toctree::\n    :maxdepth: 2\n\n    modules/index\n    thirdparty/index\n    glossary\n\nFor further information, indices are available:\n\nIndices\n=======\n\n* :ref:`genindex`\n* :ref:`modindex`\n* :ref:`search`\n* :ref:`glossary`\n"
  },
  {
    "path": "pylons/docs/en/jython.rst",
    "content": ".. _jython:\n\n================\nPylons on Jython\n================\n\nPylons supports `Jython <http://www.jython.org>`_ as of v0.9.7.\n\nInstallation\n============\n\nThe installation process is the same as CPython, as described in\n:ref:`getting_started`. At least Jython 2.5b2 is required.\n\n.. _java_deployment:\n\nDeploying to Java Web servers\n=============================\n\nThe Java platform defines the `Servlet API`_ for creating web applications. The\n`modjy`_ library included with Jython provides a gateway between Java Servlets\nand WSGI applications.\n\nThe `snakefight`_ tool can create a `WAR file`_ from a Pylons application (and\nmodjy) that's suitable for deployment to the various `Servlet containers`_ (such\nas `Apache Tomcat`_ or `Sun's Glassfish`_).\n\nCreating .wars with snakefight\n------------------------------\n\nFirst, install snakefight:\n\n.. code-block :: bash\n\n    $ easy_install snakefight\n\nThis adds an additional command to distutils: :command:`bdist_war`.\n\nPylons applications are loaded from Paste, via its ``paste.app_factory`` entry\npoint and a Paste style configuration file. :command:`bdist_war` knows how to\nsetup Paste apps for deployment when specified the :option:`--paste-config`\noption:\n\n.. code-block :: bash\n\n    $ paster make-config MyApp production.ini\n    $ jython setup.py bdist_war --paste-config production.ini\n\nAs with any distutils command the preferred options can instead be added to the\n:file:`setup.cfg` in the root directory of the project:\n\n.. code-block :: ini\n\n    [bdist_war]\n    paste-config = production.ini\n\nThen we can simply run:\n\n.. code-block :: bash\n\n    $ jython setup.py bdist_war\n\n:command:`bdist_war` creates a :file:`.war` with the following:\n\n- Jython's :file:`jar` files in :file:`WEB-INF/lib`\n- Jython's stdlib in :file:`WEB-INF/lib-python`\n- Your application's required eggs in :file:`WEB-INF/lib-python`\n\nWith the :option:`--paste-config` option, it also:\n\n- Creates a simple loader for the application/config\n- Generates a :file:`web.xml` deployment descriptor configuring modjy to load\n  the application with the simple loader\n\nFor further information/usages, see `snakefight's documentation`_.\n\n\n.. _`Servlet API`: http://en.wikipedia.org/wiki/Java_Servlet\n.. _`modjy`: http://modjy.xhaus.com/\n.. _`snakefight`: http://pypi.python.org/pypi/snakefight\n.. _`snakefight's documentation`: http://pypi.python.org/pypi/snakefight\n.. _`WAR file`: http://en.wikipedia.org/wiki/Sun_WAR_(file_format)\n.. _`Servlet containers`: http://en.wikipedia.org/wiki/Servlet_container\n.. _`Apache Tomcat`: http://tomcat.apache.org/\n.. _`Sun's Glassfish`: http://glassfish.org/\n"
  },
  {
    "path": "pylons/docs/en/logging.rst",
    "content": ".. _logging:\n\n=======\nLogging\n=======\n\nLogging messages \n----------------\n \nAs of Pylons 0.9.6, Pylons controllers (created via ``paster \ncontroller/restcontroller``) and ``websetup.py`` create their own Logger objects \nvia `Python's logging module <http://docs.python.org/lib/module-logging.html>`_. \n\nFor example, in the helloworld project's hello controller \n(``helloworld/controllers/hello.py``): \n\n.. code-block:: python \n\n    import logging \n\n    from pylons import request, response, session, tmpl_context as c, url\n    from pylons.controllers.util import abort, redirect\n\n    log = logging.getLogger(__name__) \n\n    class HelloController(BaseController): \n\n        def index(self): \n            ...\n\nPython's special ``__name__`` variable refers to the current module's fully \nqualified name; in this case, ``helloworld.controllers.hello``. \n\nTo log messages, simply use methods available on that Logger object: \n\n.. code-block:: python \n\n    import logging \n\n    from pylons import request, response, session, tmpl_context as c, url\n    from pylons.controllers.util import abort, redirect\n\n    log = logging.getLogger(__name__) \n\n    class HelloController(BaseController): \n\n        def index(self): \n            content_type = 'text/plain' \n            content = 'Hello World!' \n\n            log.debug('Returning: %s (content-type: %s)', content, content_type) \n            response.content_type = content_type \n            return content \n\nWhich will result in the following printed to the console, on stderr: \n\n.. code-block:: text \n\n    16:20:20,440 DEBUG [helloworld.controllers.hello] Returning: Hello World!\n                       (content-type: text/plain) \n\n\nBasic Logging configuration \n---------------------------\n \nAs of Pylons 0.9.6, the default ini files include a basic configuration for the \nlogging module. Paste ini files use the Python standard `ConfigParser format \n<http://docs.python.org/lib/module-ConfigParser.html>`_; the same format used \nfor the Python `logging module's Configuration file format \n<http://docs.python.org/lib/logging-config-fileformat.html>`_. \n\n``paster``, when loading an application via the ``paster`` ``serve``, ``shell`` \nor ``setup-app`` commands, calls the `logging.fileConfig function \n<http://docs.python.org/lib/logging-config-api.html>`_ on that specified ini \nfile if it contains a 'loggers' entry. ``logging.fileConfig`` reads the logging \nconfiguration from a ``ConfigParser`` file. \n\nLogging configuration is provided in both the default ``development.ini`` and \nthe production ini file (created via ``paster make-config <package_name> \n<ini_file>``). The production ini's logging setup is a little simpler than the \n``development.ini``'s, and is as follows: \n\n.. code-block:: ini \n\n    # Logging configuration \n    [loggers] \n    keys = root \n\n    [handlers] \n    keys = console \n\n    [formatters] \n    keys = generic \n\n    [logger_root] \n    level = INFO \n    handlers = console \n\n    [handler_console] \n    class = StreamHandler \n    args = (sys.stderr,) \n    level = NOTSET \n    formatter = generic \n\n    [formatter_generic] \n    format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s \n\nOne root Logger is created that logs only messages at a level above or equal to \nthe ``INFO`` level to stderr, with the following format: \n\n.. code-block:: text \n\n    2007-08-17 15:04:08,704 INFO [helloworld.controllers.hello] Loading resource, id: 86 \n\nFor those familiar with the ``logging.basicConfig`` function, this configuration \nis equivalent to the code: \n\n.. code-block:: python \n\n    logging.basicConfig(level=logging.INFO, \n    format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s') \n\n\nThe default ``development.ini``'s logging section has a couple of differences: \nit uses a less verbose timestamp, and defaults your application's log messages \nto the ``DEBUG`` level (described in the next section). \n\nPylons and many other libraries (such as Beaker, SQLAlchemy, Paste) log a number \nof messages for debugging purposes. Switching the root Logger level to ``DEBUG`` \nreveals them: \n\n.. code-block:: ini \n\n    [logger_root] \n    #level = INFO \n    level = DEBUG \n    handlers = console \n\nFiltering log messages\n----------------------\n\nOften there's too much log output to sift through, such as when switching \nthe root Logger's level to ``DEBUG``. \n\nAn example: you're diagnosing database connection issues in your application and \nonly want to see SQLAlchemy's ``DEBUG`` messages in relation to database \nconnection pooling. You can leave the root Logger's level at the less verbose \n``INFO`` level and set that particular SQLAlchemy Logger to ``DEBUG`` on its \nown, apart from the root Logger: \n\n.. code-block:: ini \n\n    [logger_sqlalchemy.pool] \n    level = DEBUG \n    handlers = \n    qualname = sqlalchemy.pool \n\nthen add it to the list of Loggers: \n\n.. code-block:: ini \n\n    [loggers] \n    keys = root, sqlalchemy.pool \n\nNo Handlers need to be configured for this Logger as by default non root Loggers \nwill propagate their log records up to their parent Logger's Handlers. The root \nLogger is the top level parent of all Loggers. \n\nThis technique is used in the default ``development.ini``. The root Logger's \nlevel is set to ``INFO``, whereas the application's log level is set to \n``DEBUG``: \n\n.. code-block:: ini \n\n    # Logging configuration \n    [loggers] \n    keys = root, helloworld \n\n.. code-block:: ini \n\n    [logger_helloworld] \n    level = DEBUG \n    handlers = \n    qualname = helloworld \n\nAll of the child Loggers of the helloworld Logger will inherit the ``DEBUG`` \nlevel unless they're explicitly set differently. Meaning the \n``helloworld.controllers.hello``, ``helloworld.websetup`` (and all your app's \nmodules') Loggers by default have an effective level of ``DEBUG`` too. \n\nFor more advanced filtering, the logging module provides a `Filter \n<http://docs.python.org/lib/node423.html>`_ object; however it cannot be used \ndirectly from the configuration file. \n\nAdvanced Configuration \n----------------------\n\nTo capture log output to a separate file, use a `FileHandler \n<http://docs.python.org/lib/node412.html>`_ (or a `RotatingFileHandler \n<http://docs.python.org/lib/node413.html>`_): \n\n.. code-block:: ini \n\n    [handler_accesslog] \n    class = FileHandler \n    args = ('access.log','a') \n    level = INFO \n    formatter = generic \n\nBefore it's recognized, it needs to be added to the list of Handlers: \n\n.. code-block:: ini \n\n    [handlers] \n    keys = console, accesslog \n\nand finally utilized by a Logger. \n\n.. code-block:: ini \n\n    [logger_root] \n    level = INFO \n    handlers = console, accesslog \n\nThese final 3 lines of configuration directs all of the root Logger's output to \nthe access.log as well as the console; we'll want to disable this for the next \nsection. \n\nRequest logging with Paste's TransLogger \n----------------------------------------\n\nPaste provides the `TransLogger \n<http://pythonpaste.org/module-paste.translogger.html>`_ middleware for logging \nrequests using the `Apache Combined Log Format \n<http://httpd.apache.org/docs/2.2/logs.html#combined>`_. TransLogger combined \nwith a FileHandler can be used to create an ``access.log`` file similar to \nApache's. \n\nLike any standard middleware with a Paste entry point, TransLogger can be \nconfigured to wrap your application in the ``[app:main]`` section of the ini \nfile: \n\n.. code-block:: ini \n\n    filter-with = translogger \n\n    [filter:translogger] \n    use = egg:Paste#translogger \n    setup_console_handler = False \n\nThis is equivalent to wrapping your app in a TransLogger instance via the bottom \nof your project's ``config/middleware.py`` file: \n\n.. code-block:: python \n\n    from paste.translogger import TransLogger \n    app = TransLogger(app, setup_console_handler=False) \n    return app \n\nTransLogger will automatically setup a logging Handler to the console when \ncalled with no arguments, so it 'just works' in environments that don't \nconfigure logging. Since we've configured our own logging Handlers, we need to \ndisable that option via ``setup_console_handler = False``. \n\nWith the filter in place, TransLogger's Logger (named the 'wsgi' Logger) will \npropagate its log messages to the parent Logger (the root Logger), sending its \noutput to the console when we request a page: \n\n.. code-block:: text \n\n    00:50:53,694 INFO [helloworld.controllers.hello] Returning: Hello World!\n                      (content-type: text/plain) \n    00:50:53,695 INFO [wsgi] 192.168.1.111 - - [11/Aug/2007:20:09:33 -0700] \"GET /hello\n    HTTP/1.1\" 404 - \"-\" \n    \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725\n    Firefox/2.0.0.6\" \n\nTo direct TransLogger to the ``access.log`` FileHandler defined above, we need \nto add that FileHandler to the wsgi Logger's list of Handlers: \n\n.. code-block:: ini \n\n    # Logging configuration \n    [loggers] \n    keys = root, wsgi \n\n.. code-block:: ini \n\n    [logger_wsgi] \n    level = INFO \n    handlers = handler_accesslog \n    qualname = wsgi \n    propagate = 0 \n\nAs mentioned above, non-root Loggers by default propagate their log Records to \nthe root Logger's Handlers (currently the console Handler). Setting \n``propagate`` to 0 (false) here disables this; so the ``wsgi`` Logger directs \nits records only to the ``accesslog`` Handler. \n\nFinally, there's no need to use the ``generic`` Formatter with TransLogger as \nTransLogger itself provides all the information we need. We'll use a Formatter \nthat passes-through the log messages as is: \n\n.. code-block:: ini \n\n    [formatters] \n    keys = generic, accesslog \n\n.. code-block:: ini \n\n    [formatter_accesslog] \n    format = %(message)s \n\nThen wire this new ``accesslog`` Formatter into the FileHandler: \n\n.. code-block:: ini \n\n    [handler_accesslog] \n    class = FileHandler \n    args = ('access.log','a') \n    level = INFO \n    formatter = accesslog \n\nLogging to wsgi.errors \n---------------------- \nPylons provides a custom logging Handler class, `pylons.log.WSGIErrorsHandler \n<http://pylonshq.com/docs/class-pylons.log.WSGIErrorsHandler.html>`_, for \nlogging output to ``environ['wsgi.errors']``: the WSGI server's error stream \n(see the `WSGI Spefification, PEP 333 \n<http://www.python.org/dev/peps/pep-0333/>`_ for more \ninformation). ``wsgi.errors`` can be useful to log to in certain situations, \nsuch as when deployed under Apache mod_wsgi/mod_python, where the \n``wsgi.errors`` stream is the Apache error log. \n\nTo configure logging of only ``ERROR`` (and ``CRITICAL``) messages to \n``wsgi.errors``, add the following to the ini file: \n\n.. code-block:: ini \n\n    [handlers] \n    keys = console, wsgierrors \n\n.. code-block:: ini \n\n    [handler_wsgierrors] \n    class = pylons.log.WSGIErrorsHandler \n    args = () \n    level = ERROR \n    format = generic \n\nthen add the new Handler name to the list of Handlers used by the root Logger: \n\n.. code-block:: ini \n\n    [logger_root] \n    level = INFO \n    handlers = console, wsgierrors \n\n.. warning :: \n\n    ``WSGIErrorsHandler`` does not receive log messages created during\n    application startup. This is due to the ``wsgi.errors`` stream only being\n    available through the ``environ`` dictionary; which isn't available until a\n    request is made. \n\nLumberjacking with log4j's Chainsaw \n=================================== \nJava's ``log4j`` project provides the Java GUI application `Chainsaw \n<http://logging.apache.org/log4j/docs/chainsaw.html>`_ for viewing and managing \nlog messages. Among its features are the ability to filter log messages on the \nfly, and customizable color highlighting of log messages. \n\nWe can configure Python's logging module to output to a format parsable by \nChainsaw, ``log4j``'s `XMLLayout \n<http://logging.apache.org/log4j/docs/api/org/apache/log4j/xml/XMLLayout.html>`_ \nformat. \n\nTo do so, we first need to install the `Python XMLLayout package \n<http://pypi.python.org/pypi/XMLLayout>`_: \n\n.. code-block:: bash \n\n    $ easy_install XMLLayout \n\nIt provides a log Formatter that generates ``XMLLayout`` XML. It also provides \n``RawSocketHandler``; like the logging module's ``SocketHandler``, it sends log \nmessages across the network, but does not pickle them. \n\nThe following is an example configuration for sending ``XMLLayout`` log messages \nacross the network to Chainsaw, if it were listening on `localhost` port `4448`: \n\n.. code-block:: ini \n\n    [handlers] \n    keys = console, chainsaw \n\n    [formatters] \n    keys = generic, xmllayout \n\n    [logger_root] \n    level = INFO \n    handlers = console, chainsaw \n\n.. code-block:: ini \n\n    [handler_chainsaw] \n    class = xmllayout.RawSocketHandler \n    args = ('localhost', 4448) \n    level = NOTSET \n    formatter = xmllayout \n\n.. code-block:: ini \n\n    [formatter_xmllayout] \n    class = xmllayout.XMLLayout \n\nThis configures any log messages handled by the root Logger to also be sent to \nChainsaw. The default ``development.ini`` configures the root Logger to the \n``INFO`` level, however in the case of using Chainsaw, it is preferable to \nconfigure the root Logger to ``NOTSET`` so *all* log messages are sent to \nChainsaw. Instead, we can restrict the console handler to the ``INFO`` level: \n\n.. code-block:: ini \n\n    [logger_root] \n    level = NOTSET \n    handlers = console \n\n    [handler_console] \n    class = StreamHandler \n    args = (sys.stderr,) \n    level = INFO \n    formatter = generic \n\nChainsaw can be downloaded from its `home page \n<http://logging.apache.org/log4j/docs/chainsaw.html>`_, but can also be launched \ndirectly from a Java-enabled browser via the link: `Chainsaw web start \n<http://logging.apache.org/log4j/docs/webstart/chainsaw/chainsawWebStart.jnlp>`_.\n\nIt can be configured from the GUI, but it also supports reading its \nconfiguration from a ``log4j.xml`` file. \n\nThe following ``log4j.xml`` file configures Chainsaw to listen on port `4448` \nfor ``XMLLayout`` style log messages. It also hides Chainsaw's own logging \nmessages under the ``WARN`` level, so only your app's log messages are \ndisplayed: \n\n.. code-block:: xml \n\n    <?xml version=\"1.0\" encoding=\"UTF-8\" ?> \n    <!DOCTYPE configuration> \n    <configuration xmlns=\"http://logging.apache.org/\"> \n\n    <plugin name=\"XMLSocketReceiver\" class=\"org.apache.log4j.net.XMLSocketReceiver\"> \n        <param name=\"decoder\" value=\"org.apache.log4j.xml.XMLDecoder\"/> \n        <param name=\"port\" value=\"4448\"/> \n    </plugin> \n\n    <logger name=\"org.apache.log4j\"> \n        <level value=\"warn\"/> \n    </logger> \n\n    <root> \n        <level value=\"debug\"/> \n    </root> \n\n    </configuration> \n\nChainsaw will prompt for a configuration file upon startup. The configuration \ncan also be loaded later by clicking `File`/`Load Log4J File...`. You should see \nan XMLSocketReceiver instance loaded in Chainsaw's Receiver list, configured at \nport `4448`, ready to receive log messages. \n\nHere's how the Pylons stack's log messages can look with colors defined (using \nChainsaw on OS X): \n\n.. image:: _static/Pylons_Stack-Chainsaw-OSX.png \n    :width: 750px\n    :height: 469px\n\nAlternate Logging Configuration style\n=====================================\n\nPylons' default ini files include a basic configuration for Python's logging\nmodule. Its format matches the standard Python :mod:`logging` module's `config file format <http://docs.python.org/lib/logging-config-fileformat.html>`_ . If a \nmore concise format is preferred, here is Max Ischenko's demonstration of \nan alternative style to setup logging.\n\nThe following function is called at the application start up (e.g. Global ctor):\n\n.. code-block:: python\n\n    def setup_logging():\n        logfile = config['logfile']\n        if logfile == 'STDOUT': # special value, used for unit testing\n            logging.basicConfig(stream=sys.stdout, level=logging.DEBUG,\n                   #format='%(name)s %(levelname)s %(message)s',\n                   #format='%(asctime)s,%(msecs)d %(levelname)s %(message)s',\n                   format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',\n                   datefmt='%H:%M:%S')\n        else:\n            logdir = os.path.dirname(os.path.abspath(logfile))\n            if not os.path.exists(logdir):\n                os.makedirs(logdir)\n            logging.basicConfig(filename=logfile, mode='at+',\n                 level=logging.DEBUG,\n                 format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',\n                 datefmt='%Y-%b-%d %H:%M:%S')\n        setup_thirdparty_logging()\n\nThe setup_thirdparty_logging function searches through the certain keys of the\napplication ``.ini`` file which specify logging level for a particular logger\n(module).\n\n.. code-block:: python\n\n    def setup_thirdparty_logging():\n        for key in config:\n            if not key.endswith('logging'):\n                continue\n            value = config.get(key)\n            key = key.rstrip('.logging')\n            loglevel = logging.getLevelName(value)\n            log.info('Set %s logging for %s', logging.getLevelName(loglevel), key)\n            logging.getLogger(key).setLevel(loglevel)\n\nRelevant section of the .ini file (example):\n\n.. code-block:: ini\n\n    sqlalchemy.logging = WARNING\n    sqlalchemy.orm.unitofwork.logging = INFO\n    sqlalchemy.engine.logging = DEBUG\n    sqlalchemy.orm.logging = INFO\n    routes.logging = WARNING\n\nThis means that routes logger (and all sub-loggers such as routes.mapper) only\npasses through messages of at least WARNING level; sqlalachemy defaults to\nWARNING level but some loggers are configured with more verbose level to aid\ndebugging.\n"
  },
  {
    "path": "pylons/docs/en/models.rst",
    "content": ".. _models:\n\n======\nModels\n======\n\nAbout the model\n===============\n\n.. image:: _static/pylon3.jpg\n   :alt: \n   :align: left\n   :height: 450px\n   :width: 368px\n\nIn the MVC paradigm the *model* manages the behavior and data of the application domain, responds to requests for information about its state and responds to instructions to change state.\n\nThe model represents enterprise data and business rules. It is where most of the processing takes place when using the MVC design pattern. Databases are in the remit of the model, as are component objects such as :term:`EJBs` and :term:`ColdFusion Components`.\n\nThe data returned by the model is display-neutral, i.e. the model applies no formatting. A single model can provide data for any number of display interfaces. This reduces code duplication as model code is written only once and is then reused by all of the views.\n\nBecause the model returns data without applying any formatting, the same components can be used with any interface. For example, most data is typically formatted with HTML but it could also be formatted with Macromedia Flash or WAP.\n\nThe model also isolates and handles state management and data persistence. For example, a Flash site or a wireless application can both rely on the same session-based shopping cart and e-commerce processes.\n\nBecause the model is self-contained and separate from the controller and the view, changing the data layer or business rules is less painful. If it proves necessary to switch databases, e.g. from MySQL to Oracle, or change a data source from an RDBMS to LDAP, the only required task is that of altering the model. If the view is written correctly, it won’t care at all whether a list of users came from a database or an LDAP server.\n\nThis freedom arises from the way that the three parts of an MVC-based application act as `black boxes`, the inner workings of each one are hidden from, and are independent of, the other two. The approach promotes well-defined interfaces and self-contained components.\n\n.. note:: *adapted from an Oct 2002 TechRepublic article by by Brian Kotek: \"MVC design pattern brings about better organization and code reuse\"* - http://articles.techrepublic.com.com/5100-10878_11-1049862.html\n\nModel Basics\n============\n\nPylons provides a :data:`model` package to put your database code in but does not offer a database engine or API.  Instead there are several third-party APIs to choose from.\n\nThe recommended and most commonly-adopted approach used in Pylons applications is to use SQLAlchemy with the declarative configuration style and develop with a relational database (Postgres, MySQL, etc). \n\n**This is the documented and recommended approach for creating a Pylons project with a SQL database**.\n\nInstall SQLAlchemy\n------------------\n\nWe'll assume you've already installed Pylons and have the `easy_install` command. At the command line, run: \n\n.. code-block:: bash\n\n    easy_install SQLAlchemy \n\n\nNext you'll have to install a database engine and its Python bindings. If you don't know which one to choose, SQLite is a good one to start with. It's small and easy to install, and Python 2.5 includes bindings for it. Installing the database engine is beyond the scope of this article, but here are the Python bindings you'll need for the most popular engines: \n\n.. code-block:: bash\n\n    easy_install pysqlite # If you use SQLite and Python 2.4 (not needed for Python 2.5) \n    easy_install MySQL-python # If you use MySQL \n    easy_install psycopg2 # If you use PostgreSQL \n\n\nSee the `Python Package Index <http://pypi.python.org/>`_ (formerly the Cheeseshop) for other database drivers. \n\n.. tip:: Checking Your Version\n\n    To see which version of SQLAlchemy you have, go to a Python shell and look at ``sqlalchemy.__version__`` :\n    \n    .. code-block:: pycon\n\n        >>> import sqlalchemy \n        >>> sqlalchemy.__version__ \n        0.5.8\n\nCreate a Pylons Project with SQLAlchemy\n---------------------------------------\n\nWhen creating a Pylons project, one of the questions asked as part of the project creation dialogue is whether the project should be configured with SQLAlchemy. Before continuing, ensure that the project was created with this option, if it's missing the :file:`model/meta.py` file, then the project should be re-created with this option.\n    \n.. tip::\n    \n    The project doesn't need to be deleted to add this option, just re-run\n    the `paster` command in the project's parent directory and answer \"yes\"\n    to the SQLAlchemy prompt. The files will then be added and existing\n    files will present a prompt on whether to replace them or leave the\n    current file.\n\nConfigure SQLAlchemy\n--------------------\n\nWhen your Pylons application runs, it needs to know which database to connect to. Normally you put this information in *development.ini* and activate the model in *environment.py*: put the following in *development.ini* in the `\\[app:main\\]` section, depending on your database, \n\nFor SQLite \n^^^^^^^^^^\n\n\n.. code-block:: ini\n\n    sqlalchemy.url = sqlite:///%(here)s/mydatabasefilename.sqlite \n\n\nWhere `mydatabasefilename.db` is the path to your SQLite database file. \"%(here)s\" represents the directory containing the development.ini file. If you're using an absolute path, use four slashes after the colon: \"sqlite:////var/lib/myapp/database.sqlite\". Don't use a relative path (three slashes) because the current directory could be anything. The example has three slashes because the value of \"%(here)s\" always starts with a slash (or the platform equivalent; e.g., \"C:\\\\foo\" on Windows). \n\nFor MySQL \n^^^^^^^^^\n\n.. code-block:: ini\n\n    sqlalchemy.url = mysql://username:password@host:port/database \n    sqlalchemy.pool_recycle = 3600 \n\nEnter your username, password, host (localhost if it is on your machine), port number (usually 3306) and the name of your database. The second line is an example of setting `engine options <http://www.sqlalchemy.org/docs/04/dbengine.html#dbengine_options>`_. \n\nIt's important to set \"pool_recycle\" for MySQL to prevent \"MySQL server has gone away\" errors. This is because MySQL automatically closes idle database connections without informing the application. Setting the connection lifetime to 3600 seconds (1 hour) ensures that the connections will be expired and recreated before MySQL notices they're idle. \n\nDon't be tempted to use the \".echo\" option to enable SQL logging because it may cause duplicate log output. Instead see the `Logging`_ section below to integrate MySQL logging into Paste's logging system. \n\nFor PostgreSQL \n^^^^^^^^^^^^^^\n\n.. code-block:: ini\n\n    sqlalchemy.url = postgres://username:password@host:port/database \n\n\nEnter your username, password, host (localhost if it is on your machine), \nport number (usually 5432) and the name of your database. \n\n\nOrganizing\n==========\n\nWhen you answer \"yes\" to the SQLAlchemy question when creating a Pylons\nproject, it configures a simple default model.  The model consists of two\nfiles: :file:`model/__init__.py` and :file:`model/meta.py`.\n\n:file:`model/__init__.py`\n-------------------------\nThe file :file:`model/__init__.py` contains the table definitions, the ORM \nclasses and an :func:`init_model` function. This :func:`init_model` function \nmust be called at application startup. In the Pylons default project template\nthis call is made in the :func:`load_environment` function (in the file \n:file:`config/environment.py`).\n\n:file:`model/meta.py`\n---------------------\n:file:`model/meta.py` is merely a container for a few housekeeping objects \nrequired by SQLAlchemy such as :class:`Session`, ``metadata`` and ``engine``\nto avoid import issues. In the context of the default Pylons application, only\nthe :class:`Session` object is instantiated. \n\nThe objects are optional in the context of other applications that do not make \nuse of them and so if you answer \"no\" to the SQLAlchemy question when creating \na Pylons project, the creation of :file:`model/meta.py` is simply skipped.\n\nIt is recommended that, for each model, a new module inside the ``model/``\ndirectory should be created. This keeps the models tidy when they get \nlarger as more domain specific code is added to each one.\n\nCreating a Model\n================\n\nSQLAlchemy 0.5 has an optional `Declarative` syntax which offers the \nconvenience of defining the table and the ORM class in one step. This\nis the recommended usage of SQLAlchemy.\n\nCreate a :file:`model/person.py` module::\n\n    \"\"\"Person model\"\"\"\n    from sqlalchemy import Column\n    from sqlalchemy.types import Integer, String\n\n    from myapp.model.meta import Base\n\n    class Person(Base):\n        __tablename__ = \"person\"\n\n        id = Column(Integer, primary_key=True)\n        name = Column(String(100))\n        email = Column(String(100))\n        \n        def __init__(self, name='', email=''):\n            self.name = name\n            self.email = email\n        \n        def __repr__(self):\n            return \"<Person('%s')\" % self.name\n\n.. note::\n    \n    ``Base`` is imported from :file:`model/meta.py` to prevent recursive\n    import problems when added to :file:`model/__init__.py` in the next\n    step.\n\nThen for convenience when using the models, import it in :file:`model/__init__.py`::\n    \n    \"\"\"The application's model objects\"\"\"\n    from myapp.model.meta import Session, Base\n    \n    from myapp.model.person import Person\n\n    def init_model(engine):\n        \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n        Session.configure(bind=engine)\n\nAdding a Relation\n=================\n\nHere's an example of a :class:`Person` and an :class:`Address` class with a \none-to-many relationship on `person.addresses`.\n\nFirst, add a :file:`model/address.py` module::\n    \n    \"\"\"Address model\"\"\"\n    from sqlalchemy import Column, ForeignKey\n    from sqlalchemy.types import Integer, String\n    from sqlalchemy.orm import relation, backref\n\n    from myapp.model.meta import Base\n\n    class Address(Base):\n        __tablename__ = \"address\"\n\n        id = Column(Integer, primary_key=True)\n        address = Column(String(100))\n        city = Column(String(100))\n        state = Column(String(2))\n        person_id = Column(Integer, ForeignKey('person.id'))\n        \n        person = relation('Person', backref=backref('addresses', order_by=id))\n\n        def __repr__(self):\n            return \"<Person('%s')\" % self.name\n\nWhen models are created using the declarative ``Base``, each one is added by\nname to a mapping. This allows the ``relation`` option above to locate the\nmodel it should be related to based on the text string ``'Person'``.\n\nThen add the import to the :file:`model/__init__.py` file::\n    \n    \"\"\"The application's model objects\"\"\"\n    from myapp.model.meta import Session, Base\n    \n    from myapp.model.address import Address\n    from myapp.model.person import Person\n\n    def init_model(engine):\n        \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n        Session.configure(bind=engine)\n\n\n.. seealso::\n    `Building a Relation <http://www.sqlalchemy.org/docs/05/ormtutorial.html#building-a-relation>`_\n    and \n    `SQLAlchemy manual`_\n\nCreating the Database\n=====================\n\nTo actually create the tables in the database, you call the metadata's `.create_all()` method. You can do this interactively or use `paster`'s application initialization feature. To do this, put the code in :file:`myapp/websetup.py`. After the `load_environment()` call, put: \n\n.. code-block:: python\n\n    from myapp.model.meta import Base, Session\n    log.info(\"Creating tables\")\n    Base.metadata.drop_all(checkfirst=True, bind=Session.bind)\n    Base.metadata.create_all(bind=Session.bind)\n    log.info(\"Successfully setup\")\n\nThen run the following on the command line: \n\n.. code-block:: bash\n\n    $ paster setup-app development.ini\n\nA brief guide to using model objects in the Controller\n======================================================\n\nIn which we: query a model, update a model entity, create a model entity and delete several model entities, all inside a Pylons controller.\n\nTo illustrate some typical ways of handling model objects in the Controller, we will draw from the example :class:`PagesController` code of the :ref:`QuickWiki Tutorial`.\n\nThe :class:`Session`\n--------------------\n\nThe SQLAlchemy-provided :class:`Session` object is a crucially important facet when working with models and model object entities.\n\nThe SQLAlchemy documentation describes the :class:`Session` thus: \"In the most general sense, the Session establishes all conversations with the database and represents a \"holding zone\" for all the mapped instances which you’ve loaded or created during its lifespan.\"\n\nAll of the model access that takes place in a Pylons controller is done in the context of a :class:`Session` providing a database connection reference that is created at the start of the processing of each request and destroyed at the end of the processing of the request.\n\nThese creation and destruction operations are performed automatically by the :class:`BaseController` instantiated in :file:`MYAPP/lib/base.py` which is in turn subclassed for each standard Pylons controller, ensuring that subclassed controllers can access the database only in a request-specific context which, in turn, protects against data accidentally leaking across requests.\n\n.. seeAlso:: \n    SQLAlchemy documentation for the `Session object <http://www.sqlalchemy.org/docs/session.html>`_\n\nThe net effect of this is that a fully-instantiated :class:`Session` object is available for import and immediate use in the controller for, e.g. querying the model.\n\nQuerying the model\n------------------\n\nThe :class:`Session` object provides a :func:`query` function that, when applied to a class of mapped model object, returns a SQLAlchemy :class:`Query` object that can be passed around and repeatedly consulted.\n\n.. seealso:: \n        SQLAlchemy documentation for the `Query object <http://www.sqlalchemy.org/docs/reference/orm/query.html>`_\n\nStandard usage is illustrated in this code for the :func:`__before__` function of the QuickWiki :class:`PagesController` in which ``self.page_q`` is bound to the :class:`Query` object returned by ``Session.query(Page)`` - where :class:`Page` is the class of mapped model object that will be the subject of the queries.\n\n.. code-block:: python\n\n    from MYAPP.lib.base import Session\n    from MYAPP.model import Page\n\n    class PagesController(BaseController):\n\n        def __before__(self):\n            self.page_q = Session.query(Page)\n\n        # [ ... ]\n\nThe :class:`Query` object that is bound to ``self.page_q`` is now specialised to perform queries of the :class:`Page` declarative base entity / mapped model entity. \n\n.. seeAlso:: \n        SQLAlchemy documentation for the `Querying the database <http://www.sqlalchemy.org/docs/ormtutorial.html#querying>`_\n\nHere, in the context of a controller's :func:`index` action, it is used in a very straighforward manner - :func:`self.page_q.all` - to fuel a list comprehension that returns a list containing the ``title`` of every :class:`Page` object in the database:\n\n.. code-block:: python\n\n    def index(self):\n        c.titles = [page.title for page in self.page_q.all()]\n        return render('/pages/index.mako')\n\nand ``self.page_q`` is used in similarly direct manner for the :func:`show` action that retrieves a Page with a given value of ``title`` and then calls the Page's  :func:`get_wiki_content` class method. \n\n.. code-block:: python\n\n    def show(self, title):\n        page = self.page_q.filter_by(title=title).first()\n        if page:\n            c.content = page.get_wiki_content()\n            return render('/pages/show.mako')\n        elif wikiwords.match(title):\n            return render('/pages/new.mako')\n        abort(404)\n\n.. note:: the ``title`` argument to the function is bound when the request is dispatched by the Routes map, typically of the form:\n\n    .. code-block:: python\n\n        map.connect('show_page', '/page/show/{title}', controller='page', action='show')\n\nThe :class:`Query` object has many other features, including filtering on conditions, ordering the results, grouping, etc. These are excellently described in the `SQLAlchemy manual`_. See especially the `Data Mapping <http://www.sqlalchemy.org/docs/datamapping.html>`_ and `Session / Unit of Work <http://www.sqlalchemy.org/docs/unitofwork.html>`_ chapters. \n\n\nCreating, updating and deleting model entities\n----------------------------------------------\n\nWhen performing operations that change the state of the database, the recommended approach is for Pylons users to take full advantage of the abstraction provided by the SQLAlchemy ORM and simply treat the retrieved or created model entities as Python objects, make changes to them in a conventional Pythonic way, add them to or delete them from the :class:`Session` \"holding zone\" and call :func:`Session.commit` to commit the changes to the database.\n\nThe three examples shown below are condensed illustrations of how these operations are typically performed in controller actions.\n\nCreating a model entity\n^^^^^^^^^^^^^^^^^^^^^^^\n\nSQLAlchemy's Declarative Base syntax allows model entity classes to act as constructors, accepting keyworded args and values. In this example, a new Page is created with the given title, the created model entity object is then added to the :class:`Session` and then the change is committed.\n\n.. code-block:: python\n\n    def create(self, title):\n        page = Page(title=title)\n        Session.add(page)\n        Session.commit()\n        redirect_to('show_page', title=title)\n\nUpdating a model entity\n^^^^^^^^^^^^^^^^^^^^^^^\n\nPerhaps the most straighforward use - a model entity object is retrieved from the database, a field value is updated and the change committed. \n\n(Note, this example is considerably abbreviated as a controller action - preliminary content checking has been omitted, as has exception handling for the database query.)\n\n.. code-block:: python\n\n    def save(self, title):\n        page = self.page_q.filter_by(title=title).first()\n        page.content=escape(request.POST.getone('content'))\n        Session.commit()\n        redirect_to('show_page', title=title)\n\nDeleting a model entity\n^^^^^^^^^^^^^^^^^^^^^^^\n\nThis example of shows the freedom that the Pylons user has to make repeated changes to the model (in this instance, repeatedly deleting entities from the database) before finally committing those changes by calling :func:`Session.commit`.\n\n.. code-block:: python\n\n    def delete(self):\n        titles = request.POST.getall('title')\n        pages = self.page_q.filter(Page.title.in_(titles))\n        for page in pages:\n            Session.delete(page)\n        Session.commit()\n        redirect_to('pages')\n\nThe `Object Relational tutorial <http://www.sqlalchemy.org/docs/ormtutorial.html>`_ in the SQLAlchemy documentation covers a basic SQLAlchemy object-relational mapping scenario in much more detail and the `SQL Expression tutorial <http://www.sqlalchemy.org/docs/sqlexpression.html>`_ covers the details of manipulating and marshalling the model entity objects.\n\n\nUsing multiple databases\n------------------------\n\nIn order to use multiple databases, in :file:`MYAPP/model/meta.py` create as many instances of :class:`Base` as there are databases to connect to:\n\n.. code-block:: python\n\n    \"\"\"SQLAlchemy Metadata and Session object\"\"\"\n    from sqlalchemy.ext.declarative import declarative_base\n    from sqlalchemy.orm import scoped_session, sessionmaker\n\n    __all__ = ['Base','Base2', 'Session']\n\n    # SQLAlchemy session manager. Updated by model.init_model()\n    Session = scoped_session(sessionmaker())\n\n    # The declarative Base\n    Base = declarative_base()\n    Base2 = declarative_base()\n\nDeclare the different database URLs in :file:`development.ini`, appending an integer to the ``sqlalchemy`` keyword in order to differentiate between them.\n\n.. code-block:: ini\n\n    sqlalchemy.url = sqlite:///%(here)s/database_one.sqlite\n    sqlalchemy.echo = true\n    sqlalchemy2.url = sqlite:///%(here)s/database_two.sqlite\n    sqlalchemy2.echo = false\n\nIn :file:`MYAPP/config/environment.py`, pick up those db URL declarations by using the different keywords (in this example: `sqlalchemy` and `sqlalchemy2`). Create the engines and call :func:`model.init_model`, passing through both engines as parameters.\n\n.. code-block:: python\n\n    # Setup the SQLAlchemy database engine\n    # Engine 0\n    engine = engine_from_config(config, 'sqlalchemy.')\n    engine2 = engine_from_config(config, 'sqlalchemy2.')\n    model.init_model(engine, engine2)\n\nBind the engines appropriately to the :class:`Base`-specific metadata in :file:`MYAPP/model/\\_\\_init\\_\\_.py` - note :func:`init_model` is expecting both engines to be supplied as formal parameters.\n\n.. code-block:: python\n\n    def init_model(engine, engine2):\n        meta.Base.metadata.bind = engine\n        meta.Base2.metadata.bind = engine2\n\nThen import :class:`Base` and/or :class:`Base2`\n\n.. code-block:: python\n\n    from MYAPP.model.meta import Base, Base2\n\nand use as required, e.g.\n\n.. code-block:: python\n\n    class Author(Base2):\n        __tablename__ = 'authors'\n        id = Column(Integer, primary_key=True)\n        keywords = relation(\"Keyword\", secondary=keywords)\n\nAvoiding the \"circular imports\" problem of model interdependency\n----------------------------------------------------------------\n\nClosely-interdependent models can sometimes cause \"circular import\" problems, where importing one model file causes a dependent model file to be imported, which then cause the first model file to be imported, and so on round and round in circles.\n\nIn order to break the circle, define the model entities as globals in  :file:`MYAPP/model/meta.py`\n\n.. code-block:: python\n\n    \"\"\"The application's model objects\"\"\"\n    import sqlalchemy as sa\n    from MYAPP.model import meta\n    from sqlalchemy.orm import scoped_session, sessionmaker\n\n    def init_model(engine):\n        \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n        meta.Base.metadata.bind = engine\n    \n        import MYAPP.model.user\n        User = MYAPP.model.user.User\n        global User\n    \n        import MYAPP.model.newsletter\n        Newsletter = MYAPP.model.newsletter.Newsletter\n        global Newsletter\n    \n        import MYAPP.model.submission\n        Submission = MYAPP.model.submission.Submission\n        global Submission\n\n\nTesting the Models\n------------------\n\nNormal model usage works fine in model tests, however to use the metadata you must specify an engine connection for it. To have your tables created for every unit test in your project, use a :file:`test_models.py` such as: \n\n.. code-block:: python\n\n    from myapp.tests import * \n    from myapp import model \n    from myapp.model import meta \n\n    class TestModels(TestController):\n\n        def setUp(self): \n            meta.Session.remove() \n            meta.Base.metadata.create_all(meta.engine) \n\n        def test_index(self): \n            # test your models \n            pass\n\n\n.. note:: Notice that the tests inherit from TestController. This is to ensure that the application is setup so that the models will work. \n\n\n\"nosetests --with-pylons=/path/to/test.ini ...\" is another way to ensure that your model is properly initialized before the tests are run. This can be used when running non-controller tests. \n\nLogging\n=======\n\nSQLAlchemy has several loggers that chat about the various aspects of its operation. To log all SQL statements executed along with their parameter values, put the following in :file:`development.ini`: \n\n.. code-block:: ini\n\n    [logger_sqlalchemy] \n    level = INFO\n    handlers = \n    qualname = sqlalchemy.engine \n\nThen modify the \"[loggers]\" section to enable your new logger: \n\n.. code-block:: ini\n\n    [loggers] \n    keys = root, myapp, sqlalchemy \n\n\nTo log the results along with the SQL statements, set the level to DEBUG. This can cause a lot of output! To stop logging the SQL, set the level to WARN or ERROR. \n\nSQLAlchemy has several other loggers you can configure in the same way. \"sqlalchemy.pool\" level INFO tells when connections are checked out from the engine's connection pool and when they're returned. \"sqlalchemy.orm\" and buddies log various ORM operations. See \"Configuring Logging\" in the `SQLAlchemy manual`_. \n\nAbout SQLAlchemy\n================\n\n`SQLAlchemy <http://www.sqlalchemy.org/>`_ is by far the most common approach for Pylons databases.  It provides a connection pool, a SQL statement builder, an object-relational mapper (ORM), and transaction support.  SQLAlchemy works with several database engines (MySQL, PostgreSQL, SQLite, Oracle, Firebird, MS-SQL, Access via ODBC, etc) and understands the peculiar SQL dialect of each, making it possible to port a program from one engine to another by simply changing the connection string.  Although its API is still changing gradually, SQLAlchemy is well tested, widely deployed, has excellent documentation, and its mailing list is quick with answers.\n\nSQLAlchemy lets you work at three different levels, and you can even use\nmultiple levels in the same program:\n\n* The object-relational mapper (ORM) lets you interact with the database using your own object classes rather than writing SQL code. \n* The SQL expression language has many methods to create customized SQL statements, and the result cursor is more friendly than DBAPI's. \n* The low-level execute methods accept literal SQL strings if you find something the SQL builder can't do, such as adding a column to an existing table or modifying the column's type. If they return results, you still get the benefit of SQLAlchemy's result cursor. \n\nThe first two levels are *database neutral*, meaning they hide the differences between the databases' SQL dialects. Changing to a different database is merely a matter of supplying a new connection URL. Of course there are limits to this, but SQLAlchemy is 90% easier than rewriting all your SQL queries. \n\nThe `SQLAlchemy manual`_ should be your next stop for questions not covered here. It's very well written and thorough.\n\nSQLAlchemy add-ons\n------------------\n\nMost of these provide a higher-level ORM, either by combining the table definition and ORM class definition into one step, or supporting an \"active record\" style of access.  \n\n*Please take the time to learn how to do things \"the regular way\" before using these shortcuts in a production application*.  \n\nUnderstanding what these add-ons do behind the scenes will help if you have to troubleshoot a database error or work around a limitation in the add-on later.\n\n`SQLSoup <http://www.sqlalchemy.org/docs/05/plugins.html#plugins_sqlsoup>`_, an extension to SQLAlchemy, provides a quick way to generate ORM classes based on existing database tables.\n\nIf you're familiar with ActiveRecord, used in Ruby on Rails, then you may want to use the `Elixir <http://elixir.ematia.de/>`_ layer on top of SQLAlchemy. This approach is less common since the introduction of the declarative extension, but has other features the declarative does not.\n\n.. _`SQLAlchemy manual`: http://www.sqlalchemy.org/docs/\n"
  },
  {
    "path": "pylons/docs/en/modules/commands.rst",
    "content": ":mod:`pylons.commands` -- Command line functions\n================================================\n\n.. automodule:: pylons.commands\n\nModule Contents\n---------------\n\n.. autoclass:: ControllerCommand\n.. autoclass:: RestControllerCommand\n.. autoclass:: ShellCommand\n"
  },
  {
    "path": "pylons/docs/en/modules/configuration.rst",
    "content": ":mod:`pylons.configuration` -- Configuration object and defaults setup\n======================================================================\n\n.. automodule:: pylons.configuration\n\nModule Contents\n---------------\n\n.. autoclass:: PylonsConfig\n    :members: init_app\n"
  },
  {
    "path": "pylons/docs/en/modules/controllers.rst",
    "content": ":mod:`pylons.controllers` -- Controllers\n========================================\n\n.. module:: pylons.controllers\n\nThis module makes available the\n:class:`~pylons.controllers.core.WSGIController` and\n:class:`~pylons.controllers.xmlrpc.XMLRPCController` for easier importing.\n"
  },
  {
    "path": "pylons/docs/en/modules/controllers_core.rst",
    "content": ":mod:`pylons.controllers.core` -- WSGIController Class\n======================================================\n\n.. automodule:: pylons.controllers.core\n\nModule Contents\n---------------\n\n.. autoclass:: WSGIController\n    :members: _perform_call, _inspect_call, _get_method_args, _dispatch_call, __call__\n"
  },
  {
    "path": "pylons/docs/en/modules/controllers_util.rst",
    "content": ":mod:`pylons.controllers.util` -- Controller Utility functions\n======================================================================\n\n.. automodule:: pylons.controllers.util\n\nModule Contents\n---------------\n\n.. autoclass:: Request\n    :members:\n    :undoc-members:\n    :show-inheritance:\n.. autoclass:: Response\n    :members:\n    :undoc-members:\n    :show-inheritance:\n.. autofunction:: abort\n.. autofunction:: etag_cache\n.. autofunction:: forward\n.. autofunction:: redirect\n"
  },
  {
    "path": "pylons/docs/en/modules/controllers_xmlrpc.rst",
    "content": ":mod:`pylons.controllers.xmlrpc` -- XMLRPCController Class\n==========================================================\n\n.. automodule:: pylons.controllers.xmlrpc\n\nModule Contents\n---------------\n\n.. autoclass:: XMLRPCController\n    :members: __call__, system_listMethods, system_methodSignature, system_methodHelp\n"
  },
  {
    "path": "pylons/docs/en/modules/decorators.rst",
    "content": ":mod:`pylons.decorators` -- Decorators\n======================================\n\n.. automodule:: pylons.decorators\n\nModule Contents\n---------------\n\n.. autofunction:: jsonify\n.. autofunction:: validate\n"
  },
  {
    "path": "pylons/docs/en/modules/decorators_cache.rst",
    "content": ":mod:`pylons.decorators.cache` -- Cache Decorators\n======================================================================\n\n.. automodule:: pylons.decorators.cache\n\nModule Contents\n---------------\n\n.. autofunction:: beaker_cache\n"
  },
  {
    "path": "pylons/docs/en/modules/decorators_rest.rst",
    "content": ":mod:`pylons.decorators.rest` -- REST-ful Decorators\n====================================================\n\n.. automodule:: pylons.decorators.rest\n\nModule Contents\n---------------\n\n.. autofunction:: dispatch_on\n.. autofunction:: restrict\n"
  },
  {
    "path": "pylons/docs/en/modules/decorators_secure.rst",
    "content": ":mod:`pylons.decorators.secure` -- Secure Decorators\n====================================================\n\n.. automodule:: pylons.decorators.secure\n\nModule Contents\n---------------\n\n.. autofunction:: authenticate_form\n.. autofunction:: https\n"
  },
  {
    "path": "pylons/docs/en/modules/error.rst",
    "content": ":mod:`pylons.error` -- Error handling support\n=============================================\n\n.. automodule:: pylons.error\n"
  },
  {
    "path": "pylons/docs/en/modules/i18n_translation.rst",
    "content": ":mod:`pylons.i18n.translation` -- Translation/Localization functions\n====================================================================\n\n.. automodule:: pylons.i18n.translation\n\nModule Contents\n---------------\n\n.. autoexception:: LanguageError\n.. autoclass:: LazyString\n.. autofunction:: lazify\n.. autofunction:: gettext_noop\n.. autofunction:: gettext\n.. autofunction:: ugettext\n.. autofunction:: ngettext\n.. autofunction:: ungettext\n.. autofunction:: set_lang\n.. autofunction:: get_lang\n.. autofunction:: add_fallback\n"
  },
  {
    "path": "pylons/docs/en/modules/index.rst",
    "content": ".. _modules:\n\n==============\nPylons Modules\n==============\n\n.. toctree::\n   :maxdepth: 2\n\n   commands\n   configuration\n   controllers\n   controllers_core\n   controllers_util\n   controllers_xmlrpc\n   decorators\n   decorators_cache\n   decorators_rest\n   decorators_secure\n   error\n   i18n_translation\n   log\n   middleware\n   templating\n   test\n   util\n   wsgiapp\n\n"
  },
  {
    "path": "pylons/docs/en/modules/log.rst",
    "content": ":mod:`pylons.log` -- Logging for WSGI errors\n============================================\n\n.. automodule:: pylons.log\n\nModule Contents\n---------------\n\n.. autoclass:: WSGIErrorsHandler\n    :members:\n"
  },
  {
    "path": "pylons/docs/en/modules/middleware.rst",
    "content": ":mod:`pylons.middleware` -- WSGI Middleware\n===========================================\n\n.. automodule:: pylons.middleware\n\nModule Contents\n---------------\n\n.. autoclass:: StatusCodeRedirect\n    :members: __init__\n.. autoclass:: StaticJavascripts\n.. autofunction:: ErrorHandler\n\n.. note::\n\n    The :data:`errorware` dictionary is constructed from the settings in the `DEFAULT` section of development.ini. the recognised keys and settings at initialization are:\n     * :data:`error_email` = conf.get('email_to')\n     * :data:`error_log` = conf.get('error_log', None)\n     * :data:`smtp_server` = conf.get('smtp_server','localhost')\n     * :data:`error_subject_prefix` = conf.get('error_subject_prefix', 'WebApp Error: ')\n     * :data:`from_address` = conf.get('from_address', conf.get('error_email_from', 'pylons@yourapp.com'))\n     * :data:`error_message` = conf.get('error_message', 'An internal server error occurred')\n\nReferenced classes\n------------------\nPylons middleware uses :class:`WebError` to effect the error-handling. The two classes implicated are:\n\nErrorMiddleware\n^^^^^^^^^^^^^^^\n\n:mod:`weberror.errormiddleware`\n:class:`weberror.errormiddleware.ErrorMiddleware`\n\n\nEvalException\n^^^^^^^^^^^^^\n\n:mod:`weberror.evalexception`\n:class:`weberror.evalexception.EvalException`\n"
  },
  {
    "path": "pylons/docs/en/modules/templating.rst",
    "content": ":mod:`pylons.templating` -- Render functions and helpers\n========================================================\n\n.. automodule:: pylons.templating\n\nModule Contents\n---------------\n\n.. autofunction:: pylons_globals\n.. autofunction:: cached_template\n.. autofunction:: render_mako\n.. autofunction:: render_mako_def\n.. autofunction:: render_genshi\n"
  },
  {
    "path": "pylons/docs/en/modules/test.rst",
    "content": ":mod:`pylons.test` -- Test related functionality\n================================================\n\n.. automodule:: pylons.test\n\nModule Contents\n---------------\n\n.. autoclass:: PylonsPlugin\n"
  },
  {
    "path": "pylons/docs/en/modules/util.rst",
    "content": ":mod:`pylons.util` -- Paste Template and Pylons utility functions\n=================================================================\n\n.. automodule:: pylons.util\n\nModule Contents\n---------------\n\n.. autoclass:: PylonsContext\n.. autoclass:: ContextObj\n.. autoclass:: AttribSafeContextObj\n"
  },
  {
    "path": "pylons/docs/en/modules/wsgiapp.rst",
    "content": ":mod:`pylons.wsgiapp` -- PylonsWSGI App Creator\n===============================================\n\n.. automodule:: pylons.wsgiapp\n\nModule Contents\n---------------\n\n.. autoclass:: PylonsApp\n    :members:\n    \n    .. automethod:: PylonsApp.__call__\n"
  },
  {
    "path": "pylons/docs/en/objects.inv",
    "content": ""
  },
  {
    "path": "pylons/docs/en/python23_install.rst",
    "content": ".. _python23_installation:\n\n====================================\nPython 2.3 Installation Instructions\n====================================\n\nAdvice of **end of support for Python 2.3**\n-------------------------------------------\n\n.. warning:: **END OF SUPPORT FOR PYTHON 2.3** This is the **LAST** version to support Python 2.3 **BEGIN UPGRADING OR DIE**\n\nPreparation\n-----------\n\nFirst, please note that Python 2.3 users on Windows will need to install `subprocess.exe`__ before beginning the installation (whereas Python 2.4 users on Windows do not). All windows users also should read the section :ref:`windows_notes` after installation. Users of Ubuntu/debian will also likely need to install the python-dev package.\n\nSystem-wide Install\n-------------------\n\nTo install Pylons so it can be used by everyone (you'll need root access).\n\nIf you already have easy install:\n\n.. code-block:: bash\n\n    $ easy_install Pylons==0.9.7\n\n.. note::\n    On rare occasions, the python.org Cheeseshop goes down. It is still \n    possible to install Pylons and its dependencies however by specifying our\n    local package directory for installation with:\n    \n    .. code-block:: bash\n    \n        $ easy_install -f http://pylonshq.com/download/ Pylons==0.9.7\n    \n    Which will use the packages necessary for the latest release. If you're \n    using an older version of Pylons, you can get the packages that went with\n    it by specifying the version desired:\n    \n    .. code-block:: bash\n    \n        $ easy_install -f http://pylonshq.com/download/0.9.7/ Pylons==0.9.7\n\nOtherwise: \n\n#. Download the easy install setup file from http://peak.telecommunity.com/dist/ez_setup.py\n#. Run:\n\n.. code-block:: bash\n\n    $ python ez_setup.py Pylons==0.9.7\n\n\n.. __: http://www.pylonshq.com/download/subprocess-0.1-20041012.win32-py2.3.exe\n\n.. warning:: **END OF SUPPORT FOR PYTHON 2.3** This is the **LAST** version to support Python 2.3 **BEGIN UPGRADING OR DIE**\n"
  },
  {
    "path": "pylons/docs/en/security_policy_for_bugs.rst",
    "content": ".. _security_policy_for_bugs:\n\n========================\nSecurity policy for bugs\n========================\n\nReceiving Security Updates \n========================== \n\nThe Pylons team have set up a mailing list at wsgi-security-announce@googlegroups.com to which any security vulnerabilities that affect Pylons will be announced. Anyone wishing to be notified of vulnerabilities in Pylons should subscribe to this list. Security announcements will only be made once a solution to the problem has been discovered. \n\nReporting Security Issues \n========================= \n\nPlease report security issues by email to both the lead developers of Pylons at the following addresses: \n\nben\\ \n|at|\\ \ngroovie.org \n\nsecurity\\ \n|at|\\ \n3aims.com \n\nPlease DO NOT announce the vulnerability to any mailing lists or on the ticket system because we would not want any malicious person to be aware of the problem before a solution is available. \n\nIn the event of a confirmed vulnerability in Pylons itself, we will take the following actions: \n\n* Acknowledge to the reporter that we've received the report and that a fix is forthcoming. We'll give a rough timeline and ask the reporter to keep the issue confidential until we announce it. \n* Halt all other development as long as is needed to develop a fix, including patches against the current release. \n* Publicly announce the vulnerability and the fix as soon as it is available to the WSGI security list at wsgi-security-announce@googlegroups.com. \n\nThis will probably mean a new release of Pylons, but in some cases it may simply be the release of documentation explaining how to avoid the vulnerability. \n\nIn the event of a confirmed vulnerability in one of the components that Pylons uses, we will take the following actions: \n\n* Acknowledge to the reporter that we've received the report and ask the reporter to keep the issue confidential until we announce it. \n* Contact the developer or maintainer of the package containing the vulnerability. \n* If the developer or maintainer fails to release a new version in a reasonable time-scale and the vulnerability is serious we will either create documentation explaining how to avoid the problem or as a last resort, create a patched version. \n* Publicly announce the vulnerability and the fix as soon as it is available to the WSGI security list at wsgi-security-announce@googlegroups.com. \n\nMinimising Risk \n=============== \n\n* Only use official production versions of Pylons released publicly on the `Python Package Index <http://python.org/pypi>`_. \n* Only use stable releases of third party software not development, alpha, beta or release candidate code. \n* Do not assume that related software is of the same quality as Pylons itself, even if Pylons users frequently make use of it. \n* Subscribe to the wsgi-security-announce@googlegroups.com mailing list to be informed of security issues and their solutions. \n\n.. |at| image:: _static/at.png \n"
  },
  {
    "path": "pylons/docs/en/sessions.rst",
    "content": ".. _sessions:\n\n========\nSessions\n========\n\nSessions\n========\n\nPylons includes a session object: a session is a server-side, semi-permanent\nstorage for data associated with a client.\n\nThe session object is provided by the `Beaker library`_ which also provides\ncaching functionality as described in :ref:`caching`.\n\nThe Session Object\n==================\n\nThe Pylons session object is available at :data:`pylons.session`. Controller\nmodules created via :command:`paster controller/restcontroller` import the\nsession object by default.\n\nThe basic session API is simple, it implements a dict-like interface with a few\nadditional methods. The following is an example of using the session to store a\ntoken identifying if a client is logged in.\n\n.. code-block :: python\n\n    class LoginController(BaseController):\n\n        def authenicate(self):\n            name = request.POST['name']\n            password = request.POST['password']\n            user = Session.query(User).filter_by(name=name,\n                                                 password=password).first()\n            if user:\n                msg = 'Successfully logged in as %s' % name\n                location = url('index')\n                session['logged_in'] = True\n                session.save()\n            else:\n                msg = 'Invalid username/password'\n                location = url('login')\n            flash(msg)\n            redirect(location)\n\n        def logout(self):\n            # Clear all values in the session associated with the client\n            session.clear()\n            session.save()\n\nSubsequent requests can then determine if a client is logged in or not by\nchecking the session:\n\n.. code-block :: python \n\n    if not session.get('logged_in'):\n        flash('Please login')\n        redirect(url('login'))\n        \nThe session object acts lazily: it does not load the session data (from disk or\nwhichever backend is used) until the data is first accessed. This lazyness is\nfacilitated via an intermediary :class:`beaker.session.SessionObject` that\nwraps the actual :class:`beaker.session.Session` object. Furthermore the\nsession will not write changes to its backend without an explicit call to its\n:meth:`beaker.session.Session.save` method (unless configured with the ``auto``\noption).\n\nSession data is generally serialized for storage via the Python :mod:`pickle`\nmodule, so anything stored in the session must be pickleable.\n\nThe lightweight SessionObject wrapper is created by the:\n:class:`beaker.middleware.SessionMiddleware` WSGI middleware. SessionMiddleware\nstores the wrapper in the WSGI environ where Pylons sets a reference to it from\npylons.session.\n\nSessions are associated with a client via a client-side cookie. The WSGI\nmiddleware is also responsible for sending said cookie to the client.\n\nConfiguring the Session\n=======================\n\nThe basic session defaults are:\n\n* File based sessions (session data is stored on disk)\n* Session cookies have no expiration date (cookies expire at the end of the browser session)\n* Session cookie domain/path matches the current host/path\n\nPylons projects by default sets the following couple of session options via\ntheir .ini files. All Beaker specific session options in the ini file are\nprefixed with `beaker.session`:\n\n.. code-block :: ini\n\n    cache_dir = %(here)s/data\n    beaker.session.key = foo\n    beaker.session.secret = somesecret\n\n``cache_dir`` acts a base directory for both session and cache storage. Session\ndata is stored in this location under a :file:`sessions/` sub-directory.\n\n``session.key`` is the name attribute of the cookie sent to the browser. This\ndefaults to your project's name.\n\n``session.secret`` is the secret token used to hash the cookie data sent to the\nclient. This should be a secret, ideally randomly generated value on production\nenvironments. :command:`paster make-config` will generate a random secret for\nyou when creating a production ini file.\n\n\nOther Session Options\n---------------------\n\nSome other commonly used session options are:\n\n* ``type``\n  The type of the back-end for storing session data. Beaker supports many\n  different backends, see `Beaker Configuration Documentation`_ for the\n  choices. Defaults to 'file'.\n\n* ``cookie_domain``\n  The domain name to use for the session Cookie. For example, when using\n  sub-domains, set this to the parent domain name so that the cookie is valid\n  for all sub-domains.\n\nTo enable pure `Cookie-based Sessions`_ and force the cookie domain to be valid\nfor all sub-domains of 'example.com', add the following to your Pylons ini\nfile:\n\n.. code-block :: ini\n\n    beaker.session.type = cookie\n    beaker.session.cookie_domain = .example.com\n\nSee the `Beaker Configuration Documentation`_ for an exhaustive list of Session\noptions.\n\n\nStoring SQLAlchemy mapped objects in Beaker sessions\n====================================================\n\nMapped objects from SQLAlchemy can be serialized into the beaker session, but\ncare must be taken when retrieving these objects back from the beaker\nsession. They will not be associated with the SQLAlchemy Unit-of-Work Session,\nhowever these objects can be reconciled via the SQLAlchemy Session's ``merge``\nmethod, as follows:\n\n    .. code-block:: python\n\n        address = DBSession.query(Address).get(id)\n        session[id] = address\n        ...\n        address = session.get(id)\n        address = DBSession.merge(address)\n\n\nCustom and caching middleware\n=============================\n\nCare should be taken when deciding in which layer to place custom\nmiddleware. In most cases middleware should be placed between the\nPylons WSGI application instantiation and the Routes middleware; however,\nif the middleware should run *before* the session object or routing is handled:\n\n.. code-block:: python\n\n    # Routing/Session Middleware\n    app = RoutesMiddleware(app, config['routes.map'])\n    app = SessionMiddleware(app, config)\n    \n    # MyMiddleware can only see the cache object, nothing *above* here\n    app = MyMiddleware(app)\n    \n    app = CacheMiddleware(app, config)\n\nSome of the Pylons middleware layers such as the ``Session``, ``Routes``, and ``Cache`` middleware, only add\nobjects to the `environ` dict, or add HTTP headers to the response (the Session middleware for \nexample adds the session cookie header). Others, such as the ``Status Code Redirect``, and the ``Error \nHandler`` may fully intercept the request entirely, and change how its responded to.\n\nUsing `Session` in Internationalization\n=======================================\n\nHow to set the language used in a controller on the fly. \n\nFor example this could be used to allow a user to set which language they \nwanted your application to work in. Save the value to the session object: \n\n.. code-block:: python \n\n    session['lang'] = 'en' \n    session.save() \n\nthen on each controller call the language to be used could be read from the \nsession and set in the controller's ``__before__()`` method so that the pages \nremained in the same language that was previously set: \n\n.. code-block:: python \n\n    def __before__(self): \n        if 'lang' in session: \n            set_lang(session['lang']) \n\n\nUsing `Session` in Secure Forms\n===============================\n\nAuthorization tokens are stored in the client's session. The web app can then\nverify the request's submitted authorization token with the value in the\nclient's session.\n\nThis ensures the request came from the originating page. See the wikipedia entry\nfor `Cross-site request forgery`__ for more information.\n\n.. __: http://en.wikipedia.org/wiki/Cross-site_request_forgery\n\nPylons provides an ``authenticate_form`` decorator that does this verification\non the behalf of controllers.\n\nThese helpers depend on Pylons' ``session`` object.  Most of them can be easily \nported to another framework by changing the API calls.\n\nHacking the session for no cookies\n==================================\n\n(From a `paste #441 <http://pylonshq.com/pasties/441>`_ baked by Ben Bangert)\n\nSet the session to not use cookies in the dev.ini file\n\n.. code-block:: ini \n\n    beaker.session.use_cookies = False\n\nwith this as the *mode d'emploi* in the controller action\n\n.. code-block:: python\n\n    from beaker.session import Session as BeakerSession\n\n    # Get the actual session object through the global proxy\n    real_session = session._get_current_obj()\n\n    # Duplicate the session init options to avoid screwing up other sessions in \n    # other threads\n    params = real_session.__dict__['_params']\n\n    # Now set the id param used to make a session to our session maker, \n    # if id is None, a new id will be made automatically\n    params['id'] = find_id_func()\n    real_session.__dict__['_sess'] = BeakerSession({}, **params)\n\n    # Now we can use the session as usual\n    session['fred'] = 42\n    session.save()\n\n    # At the end, we need to see if the session was used and handle its id\n    if session.is_new:\n        # do something with session.id to make sure its around next time\n        pass\n\nUsing middleware (Beaker) with a composite app\n==============================================\n\nHow to allow called WSGI apps to share a common session management utility. \n\n(From a `paste #616 <http://pylonshq.com/pasties/616>`_ baked by Mark Luffel)\n\n.. code-block:: ini \n\n    # Here's an example of configuring multiple apps to use a common \n    # middleware filter\n    # The [app:home] section is a standard pylons app\n    # The ``/servicebroker`` and ``/proxy`` apps both want to be able \n    # to use the same session management\n\n    [server:main]\n    use = egg:Paste#http\n    host = 0.0.0.0\n    port = 5000\n\n    [filter-app:main]\n    use = egg:Beaker#beaker_session\n    next = sessioned\n    beaker.session.key = my_project_key\n    beaker.session.secret = i_wear_two_layers_of_socks\n\n    [composite:sessioned]\n    use = egg:Paste#urlmap\n    / = home\n    /servicebroker = servicebroker\n    /proxy = cross_domain_proxy\n\n    [app:servicebroker]\n    use = egg:Appcelerator#service_broker\n\n    [app:cross_domain_proxy]\n    use = egg:Appcelerator#cross_domain_proxy\n\n    [app:home]\n    use = egg:my_project\n    full_stack = true\n    cache_dir = %(here)s/data\n\n\n.. _`Beaker library`: http://beaker.groovie.org\n.. _`Beaker Configuration Documentation`: http://beaker.groovie.org/configuration.html#session-options\n.. _`Cookie-based Sessions`: http://beaker.groovie.org/sessions.html#cookie-based\n"
  },
  {
    "path": "pylons/docs/en/testing.rst",
    "content": ".. _testing:\n\n===========================\nUnit and functional testing\n===========================\n\nUnit Testing with :mod:`webtest`\n================================\n\nPylons provides powerful unit testing capabilities for your web application \nutilizing `webtest <http://pythonpaste.org/webtest/>`_ \nto emulate requests to your web application. You can then ensure that the \nresponse was handled appropriately and that the controller set things up \nproperly. \n\nTo run the test suite for your web application, Pylons utilizes the `nose \n<http://somethingaboutorange.com/mrl/projects/nose/>`_ test runner/discovery \npackage. Running ``nosetests`` in your project directory will run all the \ntests you create in the tests directory. If you don't have nose installed on \nyour system, it can be installed via setuptools with: \n\n.. code-block:: bash \n\n    $ easy_install -U nose \n\nTo avoid conflicts with your development setup, the tests use the `test.ini` configuration file when run. This means **you must configure any databases, etc. in your test.ini file or your tests will not be able to find the database configuration**. \n\n.. warning:: \n\n    Nose can trigger errors during its attempt to search for doc tests since it will try and import all your modules one at a time *before* your app was loaded. This will cause files under models/ that rely on your app to be running, to fail. \n\nPylons 0.9.6.1 and later includes a plugin for nose that loads the app before \nthe doctests scan your modules, allowing models to be doctested. You can use \nthis option from the command line with nose: \n\n.. code-block:: bash \n\n    nosetests --with-pylons=test.ini \n\nOr by setting up a `[nosetests]` block in your setup.cfg: \n\n.. code-block:: ini \n\n    [nosetests] \n    verbose=True \n    verbosity=2 \n    with-pylons=test.ini \n    detailed-errors=1 \n    with-doctest=True \n\nThen just run: \n\n.. code-block:: bash \n\n    python setup.py nosetests \n\nto run the tests. \n\nExample: Testing a Controller \n============================= \n\nFirst let's create a new project and controller for this example: \n\n.. code-block:: bash \n\n    $ paster create -t pylons TestExample \n    $ cd TestExample \n    $ paster controller comments \n\nYou'll see that it creates two files when you create a controller. The stub controller, and a test for it under ``testexample/tests/functional/``. \n\nModify the ``testexample/controllers/comments.py`` file so it looks like this: \n\n.. code-block:: python \n\n    from testexample.lib.base import * \n\n    class CommentsController(BaseController): \n\n        def index(self): \n            return 'Basic output' \n\n        def sess(self): \n            session['name'] = 'Joe Smith' \n            session.save() \n            return 'Saved a session' \n\nThen write a basic set of tests to ensure that the controller actions are functioning properly, modify ``testexample/tests/functional/test_comments.py`` to match the following: \n\n.. code-block:: python \n\n    from testexample.tests import * \n\n    class TestCommentsController(TestController): \n        def test_index(self): \n            response = self.app.get(url(controller='/comments')) \n            assert 'Basic output' in response \n\n        def test_sess(self): \n            response = self.app.get(url(controller='/comments', action='sess')) \n            assert response.session['name'] == 'Joe Smith' \n            assert 'Saved a session' in response \n\nRun ``nosetests`` in your main project directory and you should see them all pass: \n\n.. code-block:: pycon \n\n    .. \n    ---------------------------------------------------------------------- \n    Ran 2 tests in 2.999s \n\n    OK \n\nUnfortunately, a plain assert does not provide detailed information about the results of an assertion should it fail, unless you specify it a second argument. For example, add the following test to the ``test_sess`` function: \n\n.. code-block:: python \n\n    assert response.session.has_key('address') == True \n\nWhen you run ``nosetests`` you will get the following, not-very-helpful result:\n\n.. code-block:: pycon \n\n    .F \n    ====================================================================== \n    FAIL: test_sess (testexample.tests.functional.test_comments.TestCommentsController) \n    ---------------------------------------------------------------------- \n    Traceback (most recent call last): \n    File \"~/TestExample/testexample/tests/functional/test_comments.py\", line 12, in test_sess \n    assert response.session.has_key('address') == True \n    AssertionError: \n\n\n    ---------------------------------------------------------------------- \n    Ran 2 tests in 1.417s \n\n    FAILED (failures=1) \n\nYou can augment this result by doing the following: \n\n.. code-block:: python \n\n    assert response.session.has_key('address') == True, \"address not found in session\" \n\nWhich results in: \n\n.. code-block:: pycon \n\n    .F \n    ====================================================================== \n    FAIL: test_sess (testexample.tests.functional.test_comments.TestCommentsController) \n    ---------------------------------------------------------------------- \n    Traceback (most recent call last): \n    File \"~/TestExample/testexample/tests/functional/test_comments.py\", line 12, in test_sess \n    assert response.session.has_key('address') == True \n    AssertionError: address not found in session \n\n\n    ---------------------------------------------------------------------- \n    Ran 2 tests in 1.417s \n\n    FAILED (failures=1) \n\nBut detailing every assert statement could be time consuming. Our TestController subclasses the standard Python ``unittest.TestCase`` class, so we can use utilize its helper methods, such as ``assertEqual``, that can automatically provide a more detailed AssertionError. The new test line looks like this: \n\n.. code-block:: python \n\n    self.assertEqual(response.session.has_key('address'), True) \n\nWhich provides the more useful failure message: \n\n.. code-block:: pycon \n\n    .F \n    ====================================================================== \n    FAIL: test_sess (testexample.tests.functional.test_comments.TestCommentsController) \n    ---------------------------------------------------------------------- \n    Traceback (most recent call last): \n    File \"~/TestExample/testexample/tests/functional/test_comments.py\", line 12, in test_sess \n    self.assertEqual(response.session.has_key('address'), True) \n    AssertionError: False != True \n\n\nTesting Pylons Objects \n====================== \n\nPylons will provide several additional attributes for the :mod:`webtest` :class:`webtest.TestResponse` object that let you access various objects that were created during the web request: \n\n``config``\n    The configured Pylons applications.\n``session`` \n    Session object \n``req`` \n    Request object \n``tmpl_context`` \n    Object containing variables passed to templates \n``app_globals`` \n    Globals object \n\nTo use them, merely access the attributes of the response *after* you've used \na get/post command: \n\n.. code-block:: python \n\n    response = app.get('/some/url') \n    assert response.session['var'] == 4 \n    assert 'REQUEST_METHOD' in response.req.environ \n\n.. note:: \n\n    The :class:`response <webtest.TestResponse>` object already has a\n    TestRequest object assigned to it, therefore Pylons assigns its\n    ``request`` object to the response as ``req``. \n\n\nAccessing Special Globals\n-------------------------\n\nSometimes, you might wish to modify or check a global Pylons variable such as :term:`app_globals` before running the rest of your unit tests. The non-request specific variables are available from a special URL that will respond only in unit testing situations.\n\nFor example, to get the :term:`app_globals` object without sending a request to your actual applications::\n    \n    response = app.get('/_test_vars')\n    app_globals = response.app_globals\n\nTesting Your Own Objects \n======================== \n\nWebTest's fixture testing allows you to designate your own objects that you'd \nlike to access in your tests. This powerful functionality makes it easy to \ntest the value of objects that are normally only retained for the duration of \na single request. \n\nBefore making objects available for testing, its useful to know when your \napplication is being tested. WebTest will provide an environ variable called \n``paste.testing`` that you can test for the presence and truth of so that your \napplication only populates the testing objects when it has to. \n\nPopulating the :mod:`webtest` response object with your objects is done by \nadding them to the environ dict under the key ``paste.testing_variables``. \nPylons creates this dict before calling your application, so testing for its \nexistence and adding new values to it is recommended. All variables assigned \nto the ``paste.testing_variables`` dict will be available on the response \nobject with the key being the attribute name. \n\n.. note::\n\n    WebTest is an extracted stand-alone version of a Paste component called\n    paste.fixture. For backwards compatibility, WebTest continues to honor\n    the ``paste.testing_variables`` key in the environ.\n\nExample: \n\n.. code-block:: python \n\n    # testexample/lib/base.py \n\n    from pylons import request\n    from pylons.controllers import WSGIController\n    from pylons.templating import render_mako as render\n\n    class BaseController(WSGIController): \n        def __call__(self, environ, start_response): \n            # Create a custom email object \n            email = MyCustomEmailObj() \n            email.name = 'Fred Smith' \n            if 'paste.testing_variables' in request.environ: \n                request.environ['paste.testing_variables']['email'] = email \n            return WSGIController.__call__(self, environ, start_response) \n\n\n    # testexample/tests/functional/test_controller.py \n    from testexample.tests import * \n\n    class TestCommentsController(TestController): \n        def test_index(self): \n            response = self.app.get(url(controller='/')) \n            assert response.email.name == 'Fred Smith' \n\n\n.. seealso::\n\n    `WebTest Documentation <http://pythonpaste.org/webtest/>`_\n        Documentation covering webtest and its usage\n    \n    :mod:`WebTest Module docs <webtest>`\n        Module API reference for methods available for use when testing\n        the application\n\n.. _unit_testing:\n\nUnit Testing\n============\n\nXXX: Describe unit testing an applications models, libraries\n\n\n.. _functional_testing:\n\nFunctional Testing\n==================\n\nXXX: Describe functional/integrated testing, WebTest\n"
  },
  {
    "path": "pylons/docs/en/thirdparty/formencode_api.rst",
    "content": ".. _formencode:\n\n==========\nFormEncode\n==========\n\nFormEncode is a validation and form generation package. The validation can be used separately from the form generation. The validation works on compound data structures, with all parts being nestable. It is separate from HTTP or any other input mechanism.\n\nThese module API docs are divided into section by category.\n\nCore API\n========\n\n:mod:`formencode.api`\n---------------------\n\nThese functions are used mostly internally by FormEncode.\n\n.. automodule:: formencode.api\n\n.. function:: is_validator(obj)\n\n    Returns whether ``obj`` is a validator object or not.\n\n.. autoclass:: Invalid\n    :members:\n    \n    .. automethod:: __init__\n\n.. autoclass:: Validator\n    :members:\n\n.. autoclass:: FancyValidator\n    :members:\n\n\n:mod:`formencode.schema`\n------------------------\n\nThe FormEncode schema is one of the most important parts of using FormEncode,\nas it lets you organize validators into parts that can be re-used between\nschemas. Generally, a single schema will represent an entire form, but may\ninherit other schemas for re-usable validation parts (ie, maybe multiple \nforms all requires first and last name).\n\n.. module:: formencode.schema\n\n.. autoclass:: Schema\n.. autoclass:: SimpleFormValidator\n\n\nValidators\n==========\n\n.. automodule:: formencode.validators\n\n.. autoclass:: Bool\n.. autoclass:: CIDR\n.. autoclass:: CreditCardValidator\n.. autoclass:: CreditCardExpires\n.. autoclass:: CreditCardSecurityCode\n.. autoclass:: DateConverter\n.. autoclass:: DateValidator\n.. autoclass:: DictConverter\n.. autoclass:: Email\n.. autoclass:: Empty\n.. autoclass:: FieldsMatch\n.. autoclass:: FieldStorageUploadConverter\n.. autoclass:: FileUploadKeeper\n.. autoclass:: FormValidator\n.. autoclass:: IndexListConverter\n.. autoclass:: Int\n.. autoclass:: IPhoneNumberValidator\n.. autoclass:: MACAddress\n.. autoclass:: MaxLength\n.. autoclass:: MinLength\n.. autoclass:: Number\n.. autoclass:: NotEmpty\n.. autoclass:: OneOf\n.. autoclass:: PhoneNumber\n.. autoclass:: PlainText\n.. autoclass:: PostalCode\n.. autoclass:: Regex\n.. autoclass:: RequireIfMissing\n.. autoclass:: Set\n.. autoclass:: SignedString\n.. autoclass:: StateProvince\n.. autoclass:: String\n.. autoclass:: StringBool\n.. autoclass:: StripField\n.. autoclass:: TimeConverter\n.. autoclass:: UnicodeString\n.. autoclass:: URL\n\n\nWrapper Validators\n------------------\n\n.. autoclass:: ConfirmType\n.. autoclass:: Wrapper\n.. autoclass:: Constant\n\n\nValidator Modifiers\n===================\n\n:mod:`formencode.compound`\n--------------------------\n\n.. automodule:: formencode.compound\n\n.. autoclass:: Any\n\n.. autoclass:: All\n\n\n:mod:`formencode.foreach`\n-------------------------\n\n.. automodule:: formencode.foreach\n\n.. autoclass:: ForEach\n\n\nHTML Parsing and Form Filling\n=============================\n\n:mod:`formencode.htmlfill`\n--------------------------\n\n.. automodule:: formencode.htmlfill\n\n.. autofunction:: render\n.. autofunction:: default_formatter\n.. autofunction:: none_formatter\n.. autofunction:: escape_formatter\n.. autofunction:: escapenl_formatter\n.. autoclass:: FillingParser\n\n"
  },
  {
    "path": "pylons/docs/en/thirdparty/index.rst",
    "content": ".. _third_party_components:\n\n======================\nThird-party components\n======================\n\n.. toctree::\n   :maxdepth: 1\n\n   formencode_api\n   weberror\n   webtest\n   webob\n"
  },
  {
    "path": "pylons/docs/en/thirdparty/weberror.rst",
    "content": ":mod:`weberror` -- Weberror\n===========================\n\n.. automodule:: weberror\n\n:mod:`weberror.errormiddleware`\n-------------------------------\n.. currentmodule:: weberror.errormiddleware\n.. automodule:: weberror.errormiddleware\n.. autoclass:: ErrorMiddleware\n    :members:\n\n:mod:`weberror.evalcontext`\n---------------------------\n.. currentmodule:: weberror.evalcontext\n.. automodule:: weberror.evalcontext\n\n.. autoclass:: weberror.evalcontext.EvalContext\n    :members:\n\n:mod:`weberror.evalexception`\n-----------------------------\n.. currentmodule:: weberror.evalexception\n.. automodule:: weberror.evalexception\n\n.. autoclass:: weberror.evalexception.EvalException\n    :members:\n\n:mod:`weberror.formatter`\n-------------------------\n.. currentmodule:: weberror.formatter\n.. automodule:: weberror.formatter\n.. autoclass:: AbstractFormatter\n    :members:\n.. autoclass:: TextFormatter\n    :members:\n.. autoclass:: HTMLFormatter\n    :members:\n.. autoclass:: XMLFormatter\n    :members:\n.. autofunction:: create_text_node\n.. autofunction:: html_quote\n.. autofunction:: format_html\n.. autofunction:: format_text\n.. autofunction:: format_xml\n.. autofunction:: str2html\n.. autofunction:: _str2html\n.. autofunction:: truncate\n.. autofunction:: make_wrappable\n.. autofunction:: make_pre_wrappable\n\n\n:mod:`weberror.reporter`\n------------------------\n.. currentmodule:: weberror.reporter\n.. automodule:: weberror.reporter\n.. autoclass:: Reporter\n    :members:\n.. autoclass:: EmailReporter\n    :members:\n.. autoclass:: LogReporter\n    :members:\n.. autoclass:: FileReporter\n    :members:\n.. autoclass:: WSGIAppReporter\n    :members:\n\n\n\n:mod:`weberror.collector`\n-------------------------\n.. currentmodule:: weberror.collector\n.. automodule:: weberror.collector\n\n.. autoclass:: ExceptionCollector\n    :members:\n\n.. autoclass:: ExceptionFrame\n    :members:\n\n.. autofunction:: collect_exception\n\n"
  },
  {
    "path": "pylons/docs/en/thirdparty/webob.rst",
    "content": ":mod:`webob` -- Request/Response objects\n========================================\n\n.. automodule:: webob\n\nRequest\n-------\n\n.. autoclass:: Request\n\n.. automodule:: webob.acceptparse\n.. autoclass:: Accept\n.. autoclass:: MIMEAccept\n\n.. automodule:: webob.byterange\n.. autoclass:: Range\n\n.. automodule:: webob.cachecontrol\n.. autoclass:: CacheControl\n\n.. automodule:: webob.datastruct\n.. autoclass:: EnvironHeaders\n\n.. automodule:: webob.etag\n.. autoclass:: ETagMatcher\n.. autoclass:: IfRange\n\n\nResponse\n--------\n\n.. autoclass:: webob.Response\n\n.. autoclass:: webob.byterange.ContentRange\n\n.. autoclass:: webob.cachecontrol.CacheControl\n\n.. automodule:: webob.headerdict\n.. autoclass:: HeaderDict\n\n\nMisc Functions\n--------------\n\n.. autofunction:: webob.html_escape\n\n.. comment:\n   not sure what to do with these constants; not autoclass\n   .. autoclass:: webob.day\n   .. autoclass:: webob.week\n   .. autoclass:: webob.hour\n   .. autoclass:: webob.minute\n   .. autoclass:: webob.second\n   .. autoclass:: webob.month\n   .. autoclass:: webob.year\n\n.. autoclass:: webob.response.AppIterRange\n\n.. automodule:: webob.multidict\n.. autoclass:: MultiDict\n.. autoclass:: UnicodeMultiDict\n.. autoclass:: NestedMultiDict\n.. autoclass:: NoVars\n\n.. automodule:: webob.updatedict\n.. autoclass:: webob.updatedict.UpdateDict\n\n\nDescriptors\n-----------\n\n.. autoclass:: webob.descriptors.environ_getter\n.. autoclass:: webob.descriptors.header_getter\n.. autoclass:: webob.descriptors.converter\n.. autoclass:: webob.descriptors.deprecated_property\n"
  },
  {
    "path": "pylons/docs/en/thirdparty/webtest.rst",
    "content": ":mod:`webtest` -- WebTest\n=========================\n\n.. currentmodule:: webtest\n.. automodule:: webtest\n\n.. autoclass:: TestApp\n    :members:\n\n.. autoclass:: TestResponse\n    :members:\n\n.. autoclass:: Form\n    :members:\n"
  },
  {
    "path": "pylons/docs/en/tutorials/index.rst",
    "content": ".. _tutorials:\n\nPylons Tutorials\n================\n\nA small collection of relevant tutorials.\n\n.. toctree::\n    :maxdepth: 2\n\n    quickwiki_tutorial\n    understanding_unicode\n"
  },
  {
    "path": "pylons/docs/en/tutorials/quickwiki_tutorial.rst",
    "content": ".. _quickwiki_tutorial:\n\n==================\nQuickwiki tutorial\n==================\n\nIntroduction \n============ \n\nIf you haven't done so already, please first read the :ref:`getting_started` guide. \n\nIn this tutorial we are going to create a working wiki from scratch using Pylons 1.0 and `SQLAlchemy`_. Our wiki will allow visitors to add, edit or delete formatted wiki pages. \n\nStarting at the End \n=================== \n\nPylons is designed to be easy for everyone, not just developers, so let's start by downloading and installing the finished QuickWiki in exactly the same way that end users of QuickWiki might do. Once we have explored its features we will set about writing it from scratch.\n\nAfter you have :ref:`installed Pylons <installing_pylons>`, install the QuickWiki project: \n\n.. code-block :: bash \n\n    $ easy_install QuickWiki==0.1.8\n    $ paster make-config QuickWiki test.ini \n\nNext, ensure that the ``sqlalchemy.url`` variable in the ``[app:main]`` section of the configuration file (``development.ini``) specifies a value that is suitable for your setup. The data source name points to the database you wish to use.\n\n.. note :: \n\n    The default ``sqlite:///%(here)s/quickwiki.db`` uses a (file-based) SQLite database named ``quickwiki.db`` in the ini's top-level directory. This SQLite database will be created for you when running the :command:`paster setup-app` command below, but you could also use MySQL, Oracle or PostgreSQL. Firebird and MS-SQL may also work. See the `SQLAlchemy documentation <http://www.sqlalchemy.org/docs/05/dbengine.html#create-engine-url-arguments>`_ for more information on how to connect to different databases. SQLite for example requires additional forward slashes in its URI, where the client/server databases should only use two. You will also need to make sure you have the appropriate Python driver for the database you wish to use. If you're using Python 2.5, a version of the `pysqlite adapter <http://www.initd.org/tracker/pysqlite/wiki/pysqlite>`_ is already included, so you can jump right in with the tutorial. You may need to get `SQLite itself <http://www.sqlite.org/download.html>`_. \n\nFinally create the database tables and serve the finished application: \n\n.. code-block :: bash \n\n    $ paster setup-app test.ini \n    $ paster serve test.ini \n\nThat's it! Now you can visit http://127.0.0.1:5000 and experiment with the finished Wiki. \n\nWhen you've finished, stop the server with :kbd:`Control-C` so we can start developing our own version. \n\nIf you are interested in looking at the latest version of the QuickWiki source code it can be browsed online at http://bitbucket.org/bbangert/quickwiki/src/ or can be checked out using `Mercurial <http://www.selenic.com/mercurial/>`_:\n\n.. code-block :: bash \n\n    $ hg clone http://bitbucket.org/bbangert/quickwiki \n\n.. Note::\n\n    To run the QuickWiki checked out from the repository, you'll need to first run :command:`python setup.py develop` from the project's root directory. This will install its dependencies and generate `Python Egg <http://peak.telecommunity.com/DevCenter/PythonEggs>`_ metadata in a :file:`QuickWiki.egg-info` directory. The latter is required for the :command:`paster` command (among other things) .\n\n    .. code-block :: bash \n\n        $ cd QuickWiki\n        $ python setup.py develop\n\nDeveloping QuickWiki \n==================== \n\nIf you skipped the \"Starting at the End\" section you will need to assure yourself that you have Pylons installed. See the :ref:`getting_started`.\n\nThen create your project: \n\n.. code-block :: bash \n\n    $ paster create -t pylons QuickWiki\n\nWhen prompted for which templating engine to use, simply hit enter for the default (Mako). When prompted for SQLAlchemy configuration, enter ``True``.\n\nNow let's start the server and see what we have: \n\n.. code-block :: bash \n\n    $ cd QuickWiki \n    $ paster serve --reload development.ini \n\n.. note :: We have started :command:`paster serve` with the :option:`--reload` option. This means any changes that we make to code will cause the server to restart (if necessary); your changes are immediately reflected on the live site. \n\nVisit http://127.0.0.1:5000 where you will see the introduction page. Now delete the file :file:`public/index.html` so we can see the front page of the wiki instead of this welcome page. If you now refresh the page, the Pylons built-in error document support will kick in and display an ``Error 404`` page, indicating the file could not be found. We'll setup a controller to handle this location later.\n\n\nThe Model \n========= \n\nPylons uses a Model-View-Controller architecture; we'll start by creating the model. We could use any system we like for the model, including `SQLAlchemy`_ or `SQLObject <http://www.sqlobject.org>`_. Optional SQLAlchemy integration is provided for new Pylons projects, which we enabled when creating the project, and thus we'll be using SQLAlchemy for the QuickWiki. \n\n.. note :: `SQLAlchemy`_ is a powerful Python SQL toolkit and Object Relational Mapper (ORM) that is widely used by the Python community. \n\nSQLAlchemy provides a full suite of well known enterprise-level persistence patterns, designed for efficient and high-performance database access, adapted into a simple and Pythonic domain language. It has full and detailed documentation available on the SQLAlchemy website: http://sqlalchemy.org/docs/.\n\nThe most basic way of using SQLAlchemy is with explicit sessions where you create :class:`Session` objects as needed.\n\nPylons applications typically employ a slightly more sophisticated setup, using SQLAlchemy's \"contextual\" thread-local sessions created via the :meth:`sqlalchemy.orm.scoped_session` function. With this configuration, the application can use a single :class:`Session` instance per web request, avoiding the need to pass it around explicitly. Instantiating a new scoped :class:`Session` will actually find an existing one in the current thread if available. Pylons has setup a :class:`Session` for us in the :file:`model/meta.py` file. For further details, refer to the `SQLAlchemy documentation on the Session <http://www.sqlalchemy.org/docs/05/session.html#contextual-thread-local-sessions>`_.\n\n.. note :: It is important to recognize the difference between SQLAlchemy's (or possibly another DB abstraction layer's) :class:`Session` object and Pylons' standard :dfn:`session` (with a lowercase 's') for web requests. See :mod:`beaker` for more on the latter. It is customary to reference the database session by :class:`model.Session` or (more recently) :class:`Session` outside of model classes.\n\nThe :file:`model/__init__.py` file starts out rather bare-bones. It initializes the SQLAlchemy database engine, and imports the Session object.\n\nAt the top, add the following imports::\n    \n    from sqlalchemy import orm, Column, Unicode, UnicodeText\n    from quickwiki.model.meta import Session, Base\n\nThen add the following to the end of the :file:`model/__init__.py` file: \n\n.. code-block :: python \n    \n    class Page(Base):\n        __tablename__ = 'pages'\n        title = Column(Unicode(40), primary_key=True)\n        content = Column(UnicodeText(), default=u'')\n\nWe've defined a table called ``pages`` which has two columns: ``title`` (the primary key), a Unicode VARCHAR of 40 characters, and ``content`` a Unicode TEXT column of variable sized length. \n\n.. note :: A primary key is a unique ID for each row in a database table. In the example above we are using the page title as a natural primary key. Some prefer to integer primary keys for all tables, so-called surrogate primary keys. The author of this tutorial uses both methods in his own code and is not advocating one method over the other, what's important is to choose the best database structure for your application. See the Pylons Cookbook for `a quick general overview of relational databases <http://wiki.pylonshq.com/display/pylonscookbook/Relational+databases+for+people+in+a+hurry>`_ if you're not familiar with these concepts. \n\nA core philosophy of ORMs is that tables and domain classes are different beasts. So next we'll create the Python class that represents the pages of our wiki, and map these domain objects to rows in the ``pages`` table via the :func:`sqlalchemy.orm.mapper` function. In a more complex application, you could break out model classes into separate ``.py`` files in your :file:`model` directory, but for sake of simplicity in this case, we'll just stick to :file:`__init__.py`. \n\nAdd this to the bottom of ``model/__init__.py``: \n\n.. code-block :: python \n\n    class Page(object): \n\n        def __init__(self, title, content=None):\n            self.title = title\n            self.content = content\n\n        def __unicode__(self):\n            return self.title\n\n        __str__ = __unicode__\n\n    orm.mapper(Page, pages_table) \n\nA :class:`Page` object represents a row in the ``pages`` table, so ``self.title`` and ``self.content`` will be the values of the ``title`` and ``content`` columns.\n\nLooking ahead, our wiki could use a way of marking up the ``content`` field into HTML. Also, any 'WikiWords' (words made by joining together two or more capitalized words) should be converted to hyperlinks to wiki pages.\n\nWe can use Python's `docutils <http://docutils.sourceforge.net/>`_ library to allow marking up ``content`` as `reStructuredText`_. So next we'll add a method to our :class:`Page` class that formats ``content`` as HTML and converts the WikiWords to hyperlinks. Add the following at the top of the :file:`model/__init__.py` file: \n\n.. code-block :: python \n\n    import logging\n    import re\n    import sets\n    from docutils.core import publish_parts\n\n    from pylons import url\n    from quickwiki.lib.helpers import link_to\n    from quickwiki.model import meta\n\n    log = logging.getLogger(__name__)\n\n    # disable docutils security hazards:\n    # http://docutils.sourceforge.net/docs/howto/security.html\n    SAFE_DOCUTILS = dict(file_insertion_enabled=False, raw_enabled=False)\n    wikiwords = re.compile(r\"\\b([A-Z]\\w+[A-Z]+\\w+)\", re.UNICODE)\n\nthen add a :meth:`get_wiki_content` method to the :class:`Page` class:\n\n.. code-block :: python \n\n    class Page(object):\n\n        def __init__(self, title, content=None):\n            self.title = title\n            self.content = content\n\n        def get_wiki_content(self):\n            \"\"\"Convert reStructuredText content to HTML for display, and\n            create links for WikiWords\n            \"\"\"\n            content = publish_parts(self.content, writer_name='html',\n                                    settings_overrides=SAFE_DOCUTILS)['html_body']\n            titles = sets.Set(wikiwords.findall(content))\n            for title in titles:\n                title_url = url(controller='pages', action='show', title=title)\n                content = content.replace(title, link_to(title, title_url))\n            return content\n\n        def __unicode__(self):\n            return self.title\n\n        __str__ = __unicode__\n\nThe :class:`Set` object provides us with only unique WikiWord names, so we don't try replacing them more than once (a \"wikiword\" is of course defined by the regular expression set globally).\n\n.. note :: \n\n    Pylons uses a **Model View Controller** architecture and so the formatting of objects into HTML should properly be handled in the View, i.e. in a template. However in this example, converting `reStructuredText`_ into HTML in a template is inappropriate so we are treating the HTML representation of the content as part of the model. It also gives us the chance to demonstrate that SQLAlchemy domain classes are real Python classes that can have their own methods. \n\nThe :func:`link_to` and :func:`url` functions referenced in the controller code are respectively: a helper imported from the :mod:`webhelpers.html` module indirectly via :file:`lib/helpers.py`, and a utility function imported directly from the :mod:`pylons` module. They are utilities for creating links to specific controller actions. In this case we have decided that all WikiWords should link to the :meth:`show` action of the ``pages`` controller which we'll create later. However, we need to ensure that the :func:`link_to` function is made available as a helper by adding an import statement to :file:`lib/helpers.py`:\n\n.. code-block :: python\n\n    \"\"\"Helper functions\n\n    Consists of functions to typically be used within templates, but also\n    available to Controllers. This module is available to templates as 'h'.\n    \"\"\"\n    from webhelpers.html.tags import *\n\nSince we have used docutils and SQLAlchemy, both third party packages, we need to edit our :file:`setup.py` file so that anyone installing QuickWiki with `Easy Install <http://peak.telecommunity.com/DevCenter/EasyInstall>`_ will automatically have these dependencies installed too. Edit your :file:`setup.py` in your project root directory and add a docutils entry to the ``install_requires`` line (there will already be one for SQLAlchemy): \n\n.. code-block :: python \n\n    install_requires=[\n        \"Pylons>=0.9.7\",\n        \"SQLAlchemy>=0.5\",\n        \"docutils==0.4\",\n    ],\n\nWhile we are we are making changes to :file:`setup.py` we might want to complete some of the other sections too. Set the version number to 0.1.6 and add a description and URL which will be used on PyPi when we release it: \n\n.. code-block :: python \n\n    version='0.1.6', \n    description='QuickWiki - Pylons 0.9.7 Tutorial application', \n    url='http://docs.pylonshq.com/tutorials/quickwiki_tutorial.html', \n\nWe might also want to make a full release rather than a development release in which case we would remove the following lines from :file:`setup.cfg`: \n\n.. code-block :: ini \n\n    [egg_info] \n    tag_build = dev \n    tag_svn_revision = true \n\nTo test the automatic installation of the dependencies, run the following command which will also install docutils and SQLAlchemy if you don't already have them: \n\n.. code-block :: bash \n\n    $ python setup.py develop \n\n.. note :: \n\n    The command :command:`python setup.py develop` installs your application in a special mode so that it behaves exactly as if it had been installed as an egg file by an end user. This is really useful when you are developing an application because it saves you having to create an egg and install it every time you want to test a change. \n\nApplication Setup \n=================\n\nEdit :file:`websetup.py`, used by the :command:`paster setup-app` command, to look like this: \n\n.. code-block :: python \n\n    \"\"\"Setup the QuickWiki application\"\"\"\n    import logging\n\n    from quickwiki import model\n    from quickwiki.config.environment import load_environment\n    from quickwiki.model import meta\n    \n    log = logging.getLogger(__name__)\n\n    def setup_app(command, conf, vars):\n        \"\"\"Place any commands to setup quickwiki here\"\"\"\n        load_environment(conf.global_conf, conf.local_conf)\n\n        # Create the tables if they don't already exist\n        log.info(\"Creating tables...\")\n        meta.metadata.create_all(bind=meta.engine)\n        log.info(\"Successfully set up.\")\n\n        log.info(\"Adding front page data...\")\n        page = model.Page(title=u'FrontPage',\n                          content=u'**Welcome** to the QuickWiki front page!')\n        meta.Session.add(page)\n        meta.Session.commit()\n        log.info(\"Successfully set up.\")\n\n\nYou can see that :file:`config/environment.py`'s :func:`load_environment` function is called (which calls :file:`model/__init__.py`'s :func:`init_model` function), so our engine is ready for binding and we can import the model. A SQLAlchemy :class:`MetaData` object -- which provides some utility methods for operating on database schema -- usually needs to be connected to an engine, so the line  \n\n.. code-block :: python\n\n    meta.metadata.bind = meta.engine\n\ndoes exactly that and then\n\n.. code-block :: python\n\n    model.metadata.create_all(checkfirst=True)\n\nuses the connection we've just set up and, creates the table(s) we've defined ... if they don't already exist. After the tables are created, the other lines add some data for the simple front page to our wiki.\n\nBy default, SQLAlchemy specifies ``autocommit=False`` when creating the :class:`Session`, which means that operations will be wrapped in a transaction and :func:`commit`'ed atomically (unless your DB doesn't support transactions, like MySQL's default MyISAM tables -- but that's beyond the scope of this tutorial). \n\nThe database SQLAlchemy will use is specified in the ``ini`` file, under the ``[app:main]`` section, as ``sqlalchemy.url``. We'll customize the ``sqlalchemy.url`` value to point to a SQLite database named :file:`quickwiki.db` that will reside in your project's root directory. Edit the :file:`development.ini` file in the root directory of your project:\n\n.. note :: \n\n    If you've decided to use a different database other than SQLite, see the SQLAlchemy note in the `Starting at the End`_ section for information on supported database URIs.\n\n.. code-block :: ini\n\n    [app:main] \n    use = egg:QuickWiki \n    #... \n    # Specify the database for SQLAlchemy to use. \n    # SQLAlchemy database URL\n    sqlalchemy.url = sqlite:///%(here)s/quickwiki.db \n\nYou can now run the :command:`paster setup-app` command to setup your tables in the same way an end user would, remembering to drop and recreate the database if the version tested earlier has already created the tables: \n\n.. code-block :: bash \n\n    $ paster setup-app development.ini\n\nYou should see the SQL sent to the database as the default :file:`development.ini` is setup to log SQLAlchemy's SQL statements.\n\nAt this stage you will need to ensure you have the appropriate Python database drivers for the database you chose, otherwise you might find SQLAlchemy complains it can't get the DBAPI module for the dialect it needs. \n\nYou should also edit :file:`quickwiki/config/deployment.ini_tmpl` so that when users run :command:`paster make-config` the configuration file that is produced for them will also use :file:`quickwiki.db`. In the ``[app:main]`` section: \n\n.. code-block :: ini \n\n    # Specify the database for SQLAlchemy to use. \n    sqlalchemy.url = sqlite:///%(here)s/quickwiki.db \n\nTemplates \n========= \n\n.. note :: \n\n    Pylons uses the `Mako templating engine <http://www.makotemplates.org>`_ by default, although as is the case with most aspects of Pylons, you are free to deviate from the default if you prefer.\n\nIn our project we will make use of the `Mako inheritance feature <http://www.makotemplates.org/docs/inheritance.html>`_. Add the main page template in :file:`templates/base.mako`: \n\n.. code-block :: html+mako \n\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n      \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n    <html>\n      <head>\n        <title>QuickWiki</title>\n        ${h.stylesheet_link('/quick.css')}\n      </head>\n\n      <body>\n        <div class=\"content\">\n          <h1 class=\"main\">${self.header()}</h1>\n          ${next.body()}\\\n          <p class=\"footer\">\n            Return to the ${h.link_to('FrontPage', url('FrontPage'))}\n            | ${h.link_to('Edit ' + c.title, url('edit_page', title=c.title))}\n          </p>\n        </div>\n      </body>\n    </html>\n\nWe'll setup all our other templates to inherit from this one: they will be automatically inserted into the ``${next.body()}`` line. Thus the whole page will be returned when we call the :func:`render` global from our controller. This lets us easily apply a consistent theme to all our templates. \n\nIf you are interested in learning some of the features of Mako templates have a look at the comprehensive `Mako Documentation <http://www.makotemplates.org/docs/>`_. For now we just need to understand that :func:`next.body` is replaced with the child template and that anything within ``${...}`` brackets is executed and replaced with the result. By default, the replacement content is HTML-escaped in order to meet modern standards of basic protection from accidentally making the app vulnerable to XSS exploit.\n\nThis :file:`base.mako` also makes use of various helper functions attached to the ``h`` object. These are described in the `WebHelpers documentation <http://pylonshq.com/WebHelpers/module-index.html>`_. We need to add some helpers to the ``h`` by importing them in the :file:`lib/helpers.py` module (some are for later use):\n\n.. code-block :: python\n\n    \"\"\"Helper functions\n\n    Consists of functions to typically be used within templates, but also\n    available to Controllers. This module is available to templates as 'h'.\n    \"\"\"\n    from webhelpers.html import literal\n    from webhelpers.html.tags import *\n    from webhelpers.html.secure_form import secure_form\n \n\nNote that the :file:`helpers` module is available to templates as 'h', this is a good place to import or define directly any convenience functions that you want to make available to all templates. \n\nRouting \n======= \n\nBefore we can add the actions we want to be able to route the requests to them correctly. Edit :file:`config/routing.py` and adjust the 'Custom Routes' section to look like this: \n\n.. code-block :: python \n\n    # CUSTOM ROUTES HERE\n\n    map.connect('home', '/', controller='pages', action='show',\n                title='FrontPage')\n    map.connect('pages', '/pages', controller='pages', action='index')\n    map.connect('show_page', '/pages/show/{title}', controller='pages',\n                action='show')\n    map.connect('edit_page', '/pages/edit/{title}', controller='pages',\n                action='edit')\n    map.connect('save_page', '/pages/save/{title}', controller='pages',\n                action='save', conditions=dict(method='POST'))\n    map.connect('delete_page', '/pages/delete', controller='pages',\n                action='delete')\n\n    # A bonus example - the specified defaults allow visiting\n    # example.com/FrontPage to view the page titled 'FrontPage':\n    map.connect('/{title}', controller='pages', action='show')\n\n    return map\n\nNote that the default route has been replaced. This tells Pylons to route the root URL ``/`` to the :meth:`show()` method of the :class:`PageController` class in :file:`controllers/pages.py` and specify the ``title`` argument as ``'FrontPage'``. It also says that any URL of the form ``/SomePage`` should be routed to the same method but the ``title`` argument will contain the value of the first part of the URL, in this case ``SomePage``. Any other URLs that can't be matched by these maps are routed to the error controller as usual where they will result in a 404 error page being displayed. \n\nOne of the main benefits of using the Routes system is that you can also create URLs automatically, simply by specifying the routing arguments. For example if I want the URL for the page ``FrontPage`` I can create it with this code: \n\n.. code-block :: python \n\n    url(title='FrontPage') \n\nAlthough the URL would be fairly simple to create manually, with complicated URLs this approach is much quicker. It also has the significant advantage that if you ever deploy your Pylons application at a URL other than ``/``, all the URLs will be automatically adjusted for the new path without you needing to make any manual modifications. This flexibility is a real advantage. \n\nFull information on the powerful things you can do to route requests to controllers and actions can be found in the `Routes manual <http://routes.groovie.org/manual.html>`_. \n\nControllers \n=========== \n\nQuick Recap: We've setup the model, configured the application, added the routes and setup the base template in :file:`base.mako`, now we need to write the application logic and we do this with controllers. In your project's root directory, add a controller called ``pages`` to your project with this command: \n\n.. code-block :: bash \n\n    $ paster controller pages\n\nIf you are using Subversion, this will automatically be detected and the new controller and tests will be automatically added to your subversion repository.\n\nWe are going to need the following actions: \n\n``show(self, title)``\ndisplays a page based on the title \n\n``edit(self, title)`` \ndisplays a from for editing the page ``title`` \n\n``save(self, title)`` \nsave the page ``title`` and show it with a saved message \n\n``index(self)`` \nlists all of the titles of the pages in the database\n\n``delete(self, title)`` \ndeletes a page\n\n:meth:`show` \n--------------- \n\nLet's get to work on the new controller in :file:`controllers/pages.py`. First we'll import the :class:`Page` class from our :mod:`model`, and the :class:`Session` class from the :mod:`model.meta` module. We'll also import the ``wikiwords`` regular expression object, which we'll use in the :meth:`show` method. Add this line with the imports at the top of the file: \n\n.. code-block :: python \n\n    from quickwiki.model import Page, wikiwords\n    from quickwiki.model.meta import Session\n\nNext we'll add the convenience method :meth:`__before__` to the :class:`PagesController`, which is a special method Pylons always calls before calling the actual action method. We'll have :meth:`__before__` obtain and make available the relevant query object from the database, ready to be queried. Our other action methods will need this query object, so we might as well create it one place.\n\n.. code-block :: python \n\n    class PagesController(BaseController):\n\n        def __before__(self):\n            self.page_q = Session.query(Page)\n\nNow we can query the database using the query expression language provided by SQLAlchemy.\nAdd the following :meth:`show` method to :class:`PagesController`:\n\n.. code-block :: python \n\n    def show(self, title):\n        page = self.page_q.filter_by(title=title).first()\n        if page:\n            c.content = page.get_wiki_content()\n            return render('/pages/show.mako')\n        elif wikiwords.match(title):\n            return render('/pages/new.mako')\n        abort(404)\n\nAdd a template called :file:`templates/pages/show.mako` that looks like this: \n\n.. code-block :: html+mako \n\n    <%inherit file=\"/base.mako\"/>\\\n\n    <%def name=\"header()\">${c.title}</%def>\n\n    ${h.literal(c.content)}\n\nThis template simply displays the page title and content. \n\n.. note :: Pylons automatically assigns all the action parameters to the Pylons context object ``c`` so that you don't have to assign them yourself. In this case, the value of ``title`` will be automatically assigned to ``c.title`` so that it can be used in the templates. We assign ``c.content`` manually in the controller. \n\nWe also need a template for pages that don't already exist. The template needs to display a message and link to the :meth:`edit` action so that they can be created. Add a template called :file:`templates/new.mako` that looks like this: \n\n.. code-block :: html+mako \n\n    <%inherit file=\"/base.mako\"/>\\\n\n    <%def name=\"header()\">${c.title}</%def>\n\n    <p>This page doesn't exist yet.\n      <a href=\"${url('edit_page', title=c.title)}\">Create the page</a>.\n    </p>\n\nAt this point we can test our QuickWiki to see how it looks. If you don't already have a server running, start it now with: \n\n.. code-block :: bash \n\n    $ paster serve --reload development.ini \n\nWe can spruce up the appearance of page a little by adding the stylesheet we linked to in the :file:`templates/base.mako` file earlier. Add the file :file:`public/quick.css` with the following content and refresh the page to reveal a better looking wiki: \n\n.. code-block :: css \n\n    body {\n      background-color: #888;\n      margin: 25px;\n    }\n\n    div.content {\n      margin: 0;\n      margin-bottom: 10px;\n      background-color: #d3e0ea;\n      border: 5px solid #333;\n      padding: 5px 25px 25px 25px;\n    }\n\n    h1.main {\n      width: 100%;\n    }\n\n    p.footer{\n      width: 100%;\n      padding-top: 8px;\n      border-top: 1px solid #000;\n    }\n\n    a {\n      text-decoration: none;\n    }\n\n    a:hover {\n      text-decoration: underline;\n    }\n\nWhen you run the example you will notice that the word ``QuickWiki`` has been turned into a hyperlink by the :func:`get_wiki_content` method we added to our :class:`Page` domain object earlier. You can click the link and will see an example of the new page screen from the :file:`new.mako` template. If you follow the ``Create the page`` link you will see the Pylons automatic error handler kick in to tell you ``Action edit is not implemented``. Well, we better write it next, but before we do, have a play with the :ref:`interactive_debugging`, try clicking on the ``+`` or ``>>`` arrows and you will be able to interactively debug your application. It is a tremendously useful tool.\n\n:meth:`edit` \n------------\n\nTo edit the wiki page we need to get the content from the database without changing it to HTML to display it in a simple form for editing. Add the :meth:`edit` action: \n\n.. code-block :: python \n\n    def edit(self, title):\n        page = self.page_q.filter_by(title=title).first()\n        if page:\n            c.content = page.content\n        return render('/pages/edit.mako')\n\nand then create the :file:`templates/edit.mako` file: \n\n.. code-block :: html+mako  \n\n    <%inherit file=\"/base.mako\"/>\\\n\n    <%def name=\"header()\">Editing ${c.title}</%def>\n\n    ${h.secure_form(url('save_page', title=c.title))}\n      ${h.textarea(name='content', rows=7, cols=40, content=c.content)} <br />\n      ${h.submit(value='Save changes', name='commit')}\n    ${h.end_form()}\n\n.. note :: You may have noticed that we only set ``c.content`` if the page exists but that it is accessed in :func:`h.text_area` even for pages that don't exist and yet it doesn't raise an :class:`AttributeError`. \n\nWe are making use of the fact that the ``c`` object returns an empty string ``\"\"`` for any attribute that is accessed which doesn't exist. This can be a very useful feature of the ``c`` object, but can catch you on occasions where you don't expect this behavior. It can be disabled by setting ``config['pylons.strict_c'] = True`` in your project's :file:`config/environment.py`. \n\nWe are making use of the ``h`` object to create our form and field objects. This saves a bit of manual HTML writing. The form submits to the :meth:`save()` action to save the new or updated content so let's write that next. \n\n:meth:`save` \n--------------\n\nThe first thing the :meth:`save` action has to do is to see if the page being saved already exists. If not it creates it with ``page = model.Page(title)``. Next it needs the updated content. In Pylons you can get request parameters from form submissions via ``GET`` and ``POST`` requests from the appropriately named ``request`` object. For form submissions from *only* ``GET`` or ``POST`` requests, use ``request.GET`` or ``request.POST``. Only ``POST`` requests should generate side effects (like changing data), so the save action will only reference ``request.POST`` for the parameters.\n\nThen add the :meth:`save` action: \n\n.. code-block :: python \n\n    @authenticate_form\n    def save(self, title):\n        page = self.page_q.filter_by(title=title).first()\n        if not page:\n            page = Page(title)\n        # In a real application, you should validate and sanitize\n        # submitted data throughly! escape is a minimal example here.\n        page.content = escape(request.POST.getone('content'))\n        Session.add(page)\n        Session.commit()\n        flash('Successfully saved %s!' % title)\n        redirect_to('show_page', title=title)\n\n.. note :: \n    ``request.POST`` is a MultiDict object: an ordered dictionary that may contain multiple values for each key. The MultiDict will always return one value for any existing key via the normal dict accessors ``request.POST[key]`` and :meth:`request.POST.get`. When multiple values are expected, use the :meth:`request.POST.getall` method to return all values in a list. :meth:`request.POST.getone` ensures one value for key was sent, raising a :class:`KeyError` when there are 0 or more than 1 values. \n\nThe :func:`@authenticate_form` decorator that appears immediately before the  :meth:`save` action checks the value of the hidden form field placed there by the :func:`secure_form` helper that we used in :file:`templates/edit.mako` to create the form. The hidden form field carries an authorization token for prevention of certain `Cross-site request forgery (CSRF) <http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks.\n\nUpon a successful save, we want to redirect back to the :meth:`show` action and 'flash' a ``Successfully saved`` message at the top of the page. 'Flashing' a status message immediately after an action is a common requirement, and the `WebHelpers` package provides the :class:`webhelpers.pylonslib.Flash` class that makes it easy. To utilize it, we'll create a flash object at the bottom of our :file:`lib/helpers.py` module:\n\n.. code-block :: python\n\n    from webhelpers.pylonslib import Flash as _Flash\n\n    flash = _Flash()\n\nAnd import it into our :file:`controllers/pages.py`. Our new :meth:`show` method\nis escaping the content via Python's :func:`cgi.escape` function, so we need to\nimport that too, and also :func:`@authenticate_form`.\n\n.. code-block :: python \n\n    from cgi import escape\n\n    from pylons.decorators.secure import authenticate_form\n\n    from quickwiki.lib.helpers import flash\n\nAnd finally utilize the ``flash`` object in our :file:`templates/base.mako` template:\n\n.. code-block :: html+mako\n\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n      \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n    <html>\n      <head>\n        <title>QuickWiki</title>\n        ${h.stylesheet_link('/quick.css')}\n      </head>\n\n      <body>\n        <div class=\"content\">\n          <h1 class=\"main\">${self.header()}</h1>\n\n          <% flashes = h.flash.pop_messages() %>\n          % if flashes:\n            % for flash in flashes:\n            <div id=\"flash\">\n              <span class=\"message\">${flash}</span>\n            </div>\n            % endfor\n          % endif\n\n          ${next.body()}\\\n          <p class=\"footer\"> \n            Return to the ${h.link_to('FrontPage', url('FrontPage'))}\n            | ${h.link_to('Edit ' + c.title, url('edit_page', title=c.title))}\n          </p> \n        </div>\n      </body>\n    </html>\n\nAnd add the following to the :file:`public/quick.css` file: \n\n.. code-block :: css \n\n    div#flash .message {\n      color: orangered;\n    }\n\nThe ``%`` syntax is used for control structures in mako -- conditionals and loops. You must 'close' them with an 'end' tag as shown here. At this point we have a fully functioning wiki that lets you create and edit pages and can be installed and deployed by an end user with just a few simple commands. \n\nVisit http://127.0.0.1:5000 and have a play. \n\nIt would be nice to get a title list and to be able to delete pages, so that's what we'll do next! \n\n:meth:`index`\n-------------\nAdd the :meth:`index` action:\n\n.. code-block :: python \n\n    def index(self):\n        c.titles = [page.title for page in self.page_q.all()]\n        return render('/pages/index.mako')\n\nThe :meth:`index` action simply gets all the pages from the database. Create the :file:`templates/index.mako` file to display the list:\n\n.. code-block:: html+mako\n\n    <%inherit file=\"/base.mako\"/>\\\n\n    <%def name=\"header()\">Title List</%def>\n\n    ${h.secure_form(url('delete_page'))}\n\n    <ul id=\"titles\">\n      % for title in c.titles:\n      <li>\n        ${h.link_to(title, url('show_page', title=title))} -\n        ${h.checkbox('title', title)}\n      </li>\n      % endfor\n    </ul>\n\n    ${h.submit('delete', 'Delete')}\n\n    ${h.end_form()}\n\nThis displays a form listing a link to all pages along with a checkbox. When submitted, the selected titles will be sent to a :meth:`delete` action we'll create in the next step.\n\nWe need to edit :file:`templates/base.mako` to add a link to the title list in the footer, but while we're at it, let's introduce a Mako function to make the footer a little smarter. Edit :file:`base.mako` like this: \n\n.. code-block :: html+mako  \n\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n      \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n    <html>\n      <head>\n        <title>QuickWiki</title>\n        ${h.stylesheet_link('/quick.css')}\n      </head>\n\n      <body>\n        <div class=\"content\">\n          <h1 class=\"main\">${self.header()}</h1>\n      \n          <% flashes = h.flash.pop_messages() %>\n          % if flashes:\n            % for flash in flashes:\n            <div id=\"flash\">\n              <span class=\"message\">${flash}</span>\n            </div>\n            % endfor\n          % endif\n      \n          ${next.body()}\\\n      \n          <p class=\"footer\">\n            ${self.footer(request.environ['pylons.routes_dict']['action'])}\\\n          </p>\n        </div>\n      </body>\n    </html>\n\n    ## Don't show links that are redundant for particular pages\n    <%def name=\"footer(action)\">\\\n      Return to the ${h.link_to('FrontPage', url('home'))}\n      % if action == \"index\":\n        <% return %>\n      % endif\n      % if action != 'edit':\n        | ${h.link_to('Edit ' + c.title, url('edit_page', title=c.title))}\n      % endif\n      | ${h.link_to('Title List', url('pages'))}\n    </%def>\n\nThe ``<%def name=\"footer(action\">`` creates a Mako function for display logic. As you can see, the function builds the HTML for the footer, but doesn't display the 'Edit' link when you're on the 'Title List' page or already on an edit page. It also won't show a 'Title List' link when you're already on that page. The ``<% ... %>`` tags shown on the :keyword:`return` statement are the final new piece of Mako syntax: they're used much like the ``${...}`` tags, but for arbitrary Python code that does not directly render HTML. Also, the double hash (``##``) denotes a single-line comment in Mako. \n\nSo the :func:`footer` function is called in place of our old 'static' footer markup. We pass it a value from ``pylons.routes_dict`` which holds the name of the action for the current request. The trailing `\\\\` character just tells Mako not to render an extra newline. \n\nIf you visit http://127.0.0.1:5000/pages you should see the full titles list and you should be able to visit each page. \n\n:meth:`delete` \n----------------\n\nWe need to add a :meth:`delete` action that deletes pages submitted from :file:`templates/index.mako`, then returns us back to the list of titles (excluding those that were deleted): \n\n.. code-block :: python \n\n    @authenticate_form\n    def delete(self):\n        titles = request.POST.getall('title')\n        pages = self.page_q.filter(Page.title.in_(titles))\n        for page in pages:\n            Session.delete(page)\n        Session.commit()\n        # flash only after a successful commit\n        for title in titles:\n            flash('Deleted %s.' % title)\n        redirect_to('pages')\n\nAgain we use the :func:`@authenticate_form` decorator along with :func:`secure_form` used in :file:`templates/index.mako`. We're expecting potentially multiple titles, so we use :meth:`request.POST.getall` to return a list of titles. The titles are used to identify and load the :class:`Page` objects, which are then deleted.\n\nWe use the SQL ``IN`` operator to match multiple titles in one query. We can do this via the more flexible :meth:`filter` method which can accept an :meth:`in_` clause created via the title column's attribute.\n\nThe :meth:`filter_by` method we used in previous methods is a shortcut for the most typical filtering clauses. For example, the :meth:`show` method's:\n\n.. code-block :: python \n\n    self.page_q.filter_by(title=title)\n\nis equivalent to:\n\n.. code-block :: python \n\n    self.page_q.filter(Page.title == title)\n\nAfter deleting the pages, the changes are committed, and only after successfully committing do we flash deletion messages. That way if there was a problem with the commit no flash messages are shown. Finally we redirect back to the index page, which re-renders the list of remaining titles.\n\nVisit http://127.0.0.1:5000/index and have a go at deleting some pages. You may need to go back to the FrontPage and create some more if you get carried away! \n\nThat's it! A working, production-ready wiki in 20 mins. You can visit http://127.0.0.1:5000/ once more to admire your work. \n\nPublishing the Finished Product \n=============================== \n\nAfter all that hard work it would be good to distribute the finished package wouldn't it? Luckily this is really easy in Pylons too. In the project root directory run this command: \n\n.. code-block :: bash \n\n    $ python setup.py bdist_egg \n\nThis will create an egg file in the :file:`dist` directory which contains everything anyone needs to run your program. They can install it with: \n\n.. code-block :: bash \n\n    $ easy_install QuickWiki-0.1.6-py2.5.egg \n\nYou should probably make eggs for each version of Python your users might require by running the above commands with both Python 2.4 and 2.5 to create both versions of the eggs. \n\nIf you want to register your project with PyPi at http://www.python.org/pypi you can run the command below. *Please only do this with your own projects though because QuickWiki has already been registered!* \n\n.. code-block :: bash \n\n    $ python setup.py register \n\n.. warning:: The PyPi authentication is very weak and passwords are transmitted in plain text. Don't use any sign in details that you use for important applications as they could be easily intercepted. \n\nYou will be asked a number of questions and then the information you entered in :file:`setup.py` will be used as a basis for the page that is created. \n\nNow visit http://www.python.org/pypi to see the new index with your new package listed. \n\n.. note :: A `CheeseShop Tutorial <http://wiki.python.org/moin/CheeseShopTutorial>`_ has been written and `full documentation on setup.py <http://docs.python.org/dist/dist.html>`_ is available from the Python website. You can even use `reStructuredText`_ in the ``description`` and ``long_description`` areas of :file:`setup.py` to add formatting to the pages produced on PyPi (PyPi used to be called \"the CheeseShop\"). There is also `another tutorial here <http://www.python.org/~jeremy/weblog/030924.html>`_. \n\nFinally you can sign in to PyPi with the account details you used when you registered your application and upload the eggs you've created. If that seems too difficult you can even use this command which should be run for each version of Python supported to upload the eggs for you: \n\n.. code-block :: bash \n\n    $ python setup.py bdist_egg upload \n\nBefore this will work you will need to create a :file:`.pypirc` file in your home directory containing your username and password so that the :command:`upload` command knows who to sign in as. It should look similar to this: \n\n.. code-block :: ini\n\n    [server-login] \n    username: james \n    password: password \n\n.. note :: This works on windows too but you will need to set your :envvar:`HOME` environment variable first. If your home directory is :file:`C:\\Documents and Settings\\James` you would put your :file:`.pypirc` file in that directory and set your :envvar:`HOME` environment variable with this command: \n\n.. code-block :: bash \n\n    > SET HOME=C:\\Documents and Settings\\James \n\nYou can now use the :command:`python setup.py bdist_egg upload` as normal. \n\nNow that the application is on PyPi anyone can install it with the :command:`easy_install` command exactly as we did right at the very start of this tutorial. \n\nSecurity \n======== \n\nA final word about security. \n\n.. warning :: Always set ``debug = false`` in configuration files for production sites and make sure your users do too. \n\nYou should NEVER run a production site accessible to the public with debug mode on. If there was a problem with your application and an interactive error page was shown, the visitor would be able to run any Python commands they liked in the same way you can when you are debugging. This would obviously allow them to do all sorts of malicious things so it is very important you turn off interactive debugging for production sites by setting ``debug = false`` in configuration files and also that you make users of your software do the same. \n\nSummary \n======= \n\nWe've gone through the whole cycle of creating and distributing a Pylons application looking at setup and configuration, routing, models, controllers and templates. Hopefully you have an idea of how powerful Pylons is and, once you get used to the concepts introduced in this tutorial, how easy it is to create sophisticated, distributable applications with Pylons. \n\nThat's it, I hope you found the tutorial useful. You are encouraged to email any comments to the `Pylons mailing list <http://groups.google.com/group/pylons-discuss>`_ where they will be welcomed. \n\nThanks \n====== \nA big thanks to Ches Martin for updating this document and the QuickWiki project for Pylons 0.9.6 / Pylons 0.9.7 / QuickWiki 0.1.5 / QuickWiki 0.1.6, Graham Higgins, and others in the Pylons community who contributed bug fixes and suggestions. \n\nTodo \n==== \n\n* Provide :command:`paster shell` examples\n* Incorporate testing into the tutorial\n* Explain Ches's :meth:`validate_title` method in the actual QuickWiki project\n* Provide snapshots of every file modified at each step, to help resolve mistakes\n\n.. _`SQLAlchemy`: http://www.sqlalchemy.org\n.. _`reStructuredText`: http://docutils.sourceforge.net/rst.html\n"
  },
  {
    "path": "pylons/docs/en/tutorials/understanding_unicode.rst",
    "content": ".. _unicode:\n\n=====================\nUnderstanding Unicode \n===================== \n\nIf you've ever come across text in a foreign language that contains lots of ``????`` characters or have written some Python code and received a message such as ``UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6: ordinal not in range(128)`` then you have run into a problem with character sets, encodings, Unicode and the like. \n\nThe truth is that many developers are put off by Unicode because most of the time it is possible to muddle through rather than take the time to learn the basics. To make the problem worse if you have a system that manages to fudge the issues and just about work and then start trying to do things properly with\nUnicode it often highlights problems in other parts of your code. \n\nThe good news is that Python has great Unicode support, so the rest of \nthis article will show you how to correctly use Unicode in Pylons to avoid \nunwanted ``?`` characters and ``UnicodeDecodeErrors``. \n\nWhat is Unicode? \n---------------- \n\nWhen computers were first being used the characters that were most important \nwere unaccented English letters. Each of these letters could be represented by \na number between 32 and 127 and thus was born ASCII, a character set where \nspace was 32, the letter \"A\" was 65 and everything could be stored in 7 bits. \n\nMost computers in those days were using 8-bit bytes so people quickly realized \nthat they could use the codes 128-255 for their own purposes. Different people \nused the codes 128-255 to represent different characters and before long these \ndifferent sets of characters were also standardized into *code pages*. This \nmeant that if you needed some non-ASCII characters in a document you could also\nspecify a codepage which would define which extra characters were available. \nFor example Israel DOS used a code page called 862, while Greek users used 737.\nThis just about worked for Western languages provided you didn't want to write \nan Israeli document with Greek characters but it didn't work at all for Asian \nlanguages where there are many more characters than can be represented in 8 \nbits. \n\nUnicode is a character set that solves these problems by uniquely defining \n*every* character that is used anywhere in the world. Rather than defining a \ncharacter as a particular combination of bits in the way ASCII does, each \ncharacter is assigned a *code point*. For example the word ``hello`` is made \nfrom code points ``U+0048 U+0065 U+006C U+006C U+006F``. The full list of code \npoints can be found at http://www.unicode.org/charts/. \n\nThere are lots of different ways of encoding Unicode code points into bits but \nthe most popular encoding is UTF-8. Using UTF-8, every code point from 0-127 is\nstored in a single byte. Only code points 128 and above are stored using 2, 3, \nin fact, up to 6 bytes. This has the useful side effect that English text looks\nexactly the same in UTF-8 as it did in ASCII, because for every \nASCII character with hexadecimal value 0xXY, the corresponding Unicode \ncode point is U+00XY. This backwards compatibility is why if you are developing\nan application that is only used by English speakers you can often get away \nwithout handling characters properly and still expect things to work most of \nthe time. Of course, if you use a different encoding such as UTF-16 this \ndoesn't apply since none of the code points are encoded to 8 bits. \n\nThe important things to note from the discussion so far are that: \n\n* Unicode can represent pretty much any character in any writing system in widespread use today \n* Unicode uses code points to represent characters and the way these map to bits in memory depends on the encoding \n* The most popular encoding is UTF-8 which has several convenient properties\n    1. It can handle any Unicode code point \n    2. A Unicode string is turned into a string of bytes containing no embedded  zero bytes. This avoids byte-ordering issues, and means UTF-8 strings can be  processed by C functions such as strcpy() and sent through protocols that can't handle zero bytes \n    3. A string of ASCII text is also valid UTF-8 text \n    4. UTF-8 is fairly compact; the majority of code points are turned into two  bytes, and values less than 128 occupy only a single byte. \n    5. If bytes are corrupted or lost, it's possible to determine the start of  the next UTF-8-encoded code point and resynchronize. \n\n.. note:: Since Unicode 3.1, some extensions have even been defined so that the defined range is now U+000000 to U+10FFFF (21 bits), and formally, the character set is defined as 31-bits to allow for future expansion. It is a myth that there are 65,536 Unicode code points and that every Unicode letter can really be squeezed into two bytes. It is also incorrect to think that UTF-8 can represent less characters than UTF-16. UTF-8 simply uses a variable number of bytes for a character, sometimes just one byte (8 bits). \n\nUnicode in Python \n----------------- \n\nIn Python Unicode strings are expressed as instances of the built-in \n``unicode`` type. Under the hood, Python represents Unicode strings as either \n16 or 32 bit integers, depending on how the Python interpreter was compiled. \n\nThe ``unicode()`` constructor has the signature ``unicode(string[, encoding, \nerrors])``. All of its arguments should be 8-bit strings. The first argument is\nconverted to Unicode using the specified encoding; if you leave off the \nencoding argument, the ASCII encoding is used for the conversion, so characters\ngreater than 127 will be treated as errors: \n\n.. code-block:: pycon \n\n    >>> unicode('hello') \n    u'hello' \n    >>> s = unicode('hello') \n    >>> type(s) \n    <type 'unicode'> \n    >>> unicode('hello' + chr(255)) \n    Traceback (most recent call last): \n    File \"<stdin>\", line 1, in ? \n    UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6: \n    ordinal not in range(128) \n\nThe ``errors`` argument specifies what to do if the string can't be decoded to \nascii. Legal values for this argument are ``'strict'`` (raise a \n``UnicodeDecodeError`` exception), ``'replace'`` (replace the character that \ncan't be decoded with another one), or ``'ignore'`` (just leave the character \nout of the Unicode result). \n\n.. code-block:: pycon \n\n    >>> unicode('\\x80abc', errors='strict') \n    Traceback (most recent call last): \n    File \"<stdin>\", line 1, in ? \n    UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: \n    ordinal not in range(128) \n    >>> unicode('\\x80abc', errors='replace') \n    u'\\ufffdabc' \n    >>> unicode('\\x80abc', errors='ignore') \n    u'abc' \n\nIt is important to understand the difference between *encoding* and *decoding*.\nUnicode strings are considered to be the Unicode code points but any \nrepresentation of the Unicode string has to be encoded to something else, for \nexample UTF-8 or ASCII. So when you are converting an ASCII or UTF-8 string to \nUnicode you are *decoding* it and when you are converting from Unicode to UTF-8\nor ASCII you are *encoding* it. This is why the error in the example above says\nthat the ASCII codec cannot decode the byte ``0x80`` from ASCII to Unicode \nbecause it is not in the range(128) or 0-127. In fact ``0x80`` is hex for 128 \nwhich the first number outside the ASCII range. However if we tell Python that \nthe character ``0x80`` is encoded with the ``'latin-1'``, ``'iso_8859_1'`` or \n``'8859'`` character sets (which incidentally are different names for the same \nthing) we get the result we expected: \n\n.. code-block:: pycon \n\n    >>> unicode('\\x80', encoding='latin-1') \n    u'\\x80' \n\n.. note:: \n\n    The character encodings Python supports are listed at http://docs.python.org/lib/standard-encodings.html \n\nUnicode objects in Python have most of the same methods that normal Python \nstrings provide. Python will try to use the ``'ascii'`` codec to convert \nstrings to Unicode if you do an operation on both types: \n\n.. code-block:: pycon \n\n    >>> a = 'hello' \n    >>> b = unicode(' world!') \n    >>> print a + b \n    u'hello world!' \n\nYou can encode a Unicode string using a particular encoding like this: \n\n.. code-block:: pycon \n\n    >>> u'Hello World!'.encode('utf-8') \n    'Hello World!' \n\nUnicode Literals in Python Source Code \n-------------------------------------- \n\nIn Python source code, Unicode literals are written as strings prefixed with \nthe 'u' or 'U' character: \n\n.. code-block:: pycon \n\n    >>> u'abcdefghijk' \n    >>> U'lmnopqrstuv' \n\nYou can also use ``\"``, ``\"\"\"``` or ``'''`` versions too. For example: \n\n.. code-block:: pycon \n\n    >>> u\"\"\"This \n    ... is a really long \n    ... Unicode string\"\"\" \n\nSpecific code points can be written using the ``\\u`` escape sequence, which is \nfollowed by four hex digits giving the code point. If you use ``\\U`` instead \nyou specify 8 hex digits instead of 4. Unicode literals can also use the same \nescape sequences as 8-bit strings, including ``\\x``, but ``\\x`` only takes two \nhex digits so it can't express all the available code points. You can add \ncharacters to Unicode strings using the ``unichr()`` built-in function and find\nout what the ordinal is with ``ord()``. \n\nHere is an example demonstrating the different alternatives: \n\n.. code-block:: pycon \n\n    >>> s = u\"\\x66\\u0072\\u0061\\U0000006e\" + unichr(231) + u\"ais\" \n    >>> # ^^^^ two-digit hex escape \n    >>> # ^^^^^^ four-digit Unicode escape \n    >>> # ^^^^^^^^^^ eight-digit Unicode escape \n    >>> for c in s: print ord(c), \n    ... \n    97 102 114 97 110 231 97 105 115 \n    >>> print s \n    français \n\nUsing escape sequences for code points greater than 127 is fine in small doses \nbut Python 2.4 and above support writing Unicode literals in any encoding as \nlong as you declare the encoding being used by including a special comment as \neither the first or second line of the source file: \n\n.. code-block:: python \n\n    #!/usr/bin/env python \n    # -*- coding: latin-1 -*- \n    u = u'abcdé' \n    print ord(u[-1]) \n\nIf you don't include such a comment, the default encoding used will be ASCII. \nVersions of Python before 2.4 were Euro-centric and assumed Latin-1 as a \ndefault encoding for string literals; in Python 2.4, characters greater than \n127 still work but result in a warning. For example, the following program has \nno encoding declaration: \n\n.. code-block:: python \n\n    #!/usr/bin/env python \n    u = u'abcdé' \n    print ord(u[-1]) \n\nWhen you run it with Python 2.4, it will output the following warning: \n\n.. code-block:: pycon \n\n    sys:1: DeprecationWarning: Non-ASCII character '\\xe9' in file testas.py on line 2, but\n     no encoding declared; see http://www.python.org/peps/pep-0263.html for details \n\nand then the following output: \n\n.. code-block:: pycon \n\n    233 \n\nFor real world use it is recommended that you use the UTF-8 encoding for your \nfile but you must be sure that your text editor actually saves the file as \nUTF-8 otherwise the Python interpreter will try to parse UTF-8 characters but \nthey will actually be stored as something else. \n\n.. note :: \n\n    Windows users who use the `SciTE <http://www.scintilla.org/SciTE.html>`_ editor can specify the encoding of their file from the menu using the  ``File->Encoding``. \n\n.. note :: \n\n    If you are working with Unicode in detail you might also be interested in the ``unicodedata`` module which can be used to find out Unicode properties  such as a character's name, category, numeric value and the like. \n\n\nInput and Output \n---------------- \n\nWe now know how to use Unicode in Python source code but input and output can \nalso be different using Unicode. Of course, some libraries natively support \nUnicode and if these libraries return Unicode objects you will not have to do \nanything special to support them. XML parsers and SQL databases frequently \nsupport Unicode for example. \n\nIf you remember from the discussion earlier, Unicode data consists of code \npoints. In order to send Unicode data via a socket or write it to a file you \nusually need to encode it to a series of bytes and then decode the data back to\nUnicode when reading it. You can of course perform the encoding manually \nreading a byte at the time but since encodings such as UTF-8 can have variable \nnumbers of bytes per character it is usually much easier to use Python's \nbuilt-in support in the form of the ``codecs`` module. \n\nThe codecs module includes a version of the ``open()`` function that \nreturns a file-like object that assumes the file's contents are in a specified \nencoding and accepts Unicode parameters for methods such as ``.read()`` and \n``.write()``. \n\nThe function's parameters are open(filename, mode='rb', encoding=None, \nerrors='strict', buffering=1). ``mode`` can be 'r', 'w', or 'a', just like the \ncorresponding parameter to the regular built-in ``open()`` function. You can \nadd a ``+`` character to update the file. ``buffering`` is similar to the \nstandard function's parameter. ``encoding`` is a string giving the encoding to \nuse, if not specified or specified as ``None``, a regular Python file object \nthat accepts 8-bit strings is returned. Otherwise, a wrapper object is \nreturned, and data written to or read from the wrapper object will be converted\nas needed. ``errors`` specifies the action for encoding errors and can be one \nof the usual values of ``'strict'``, ``'ignore'``, or ``'replace'`` which we \nsaw right at the begining of this document when we were encoding strings in \nPython source files. \n\nHere is an example of how to read Unicode from a UTF-8 encoded file: \n\n.. code-block:: python \n\n    import codecs \n    f = codecs.open('unicode.txt', encoding='utf-8') \n    for line in f: \n        print repr(line) \n\nIt's also possible to open files in update mode, allowing both reading and writing: \n\n.. code-block:: python \n\n    f = codecs.open('unicode.txt', encoding='utf-8', mode='w+') \n    f.write(u\"\\x66\\u0072\\u0061\\U0000006e\" + unichr(231) + u\"ais\") \n    f.seek(0) \n    print repr(f.readline()[:1]) \n    f.close() \n\nNotice that we used the ``repr()`` function to display the Unicode data. This \nis very useful because if you tried to print the Unicode data directly, Python \nwould need to encode it before it could be sent the console and depending on \nwhich characters were present and the character set used by the console, an \nerror might be raised. This is avoided if you use ``repr()``. \n\nThe Unicode character ``U+FEFF`` is used as a byte-order mark or BOM, and is often written as the first character of a file in order to assist with auto-detection of the file's byte ordering. Some encodings, such as UTF-16, expect a BOM to be present at the start of a file, but with others such as UTF-8 it isn't necessary. \n\nWhen such an encoding is used, the BOM will be automatically written as the \nfirst character and will be silently dropped when the file is read. There are \nvariants of these encodings, such as 'utf-16-le' and 'utf-16-be' for \nlittle-endian and big-endian encodings, that specify one particular byte \nordering and don't skip the BOM. \n\n.. note :: \n\n    Some editors including SciTE will put a byte order mark (BOM) in the text \n    file when saved as UTF-8, which is strange because UTF-8 doesn't need BOMs. \n\nUnicode Filenames \n----------------- \n\nMost modern operating systems support the use of Unicode filenames. The \nfilenames are transparently converted to the underlying filesystem encoding. \nThe type of encoding depends on the operating system. \n\nOn Windows 9x, the encoding is ``mbcs``. \n\nOn Mac OS X, the encoding is ``utf-8``. \n\nOn Unix, the encoding is the user's preference according to the \nresult of nl_langinfo(CODESET), or None if the nl_langinfo(CODESET) failed. \n\nOn Windows NT+, file names are Unicode natively, so no conversion is performed.\ngetfilesystemencoding still returns ``mbcs``, as this is the encoding that \napplications should use when they explicitly want to convert Unicode strings to\nbyte strings that are equivalent when used as file names. \n\n``mbcs`` is a special encoding for Windows that effectively means \"use \nwhichever encoding is appropriate\". In Python 2.3 and above you can find out \nthe system encoding with ``sys.getfilesystemencoding()``. \n\nMost file and directory functions and methods support Unicode. For example: \n\n.. code-block:: python \n\n    filename = u\"\\x66\\u0072\\u0061\\U0000006e\" + unichr(231) + u\"ais\" \n    f = open(filename, 'w') \n    f.write('Some data\\n') \n    f.close() \n\nOther functions such as ``os.listdir()`` will return Unicode if you pass a \nUnicode argument and will try to return strings if you pass an ordinary 8 bit \nstring. For example running this example as ``test.py``: \n\n.. code-block:: python \n\n    filename = u\"Sample \" + unichar(5000) \n    f = open(filename, 'w') \n    f.close() \n\n    import os \n    print os.listdir('.') \n    print os.listdir(u'.') \n\nwill produce the following output: \n\n.. code-block:: python \n\n    ['Sample?', 'test.py'] \n    [u'Sample\\u1388', u'test.py'] \n\nApplying this to Web Programming \n================================ \n\nSo far we've seen how to use encoding in source files and seen how to decode \ntext to Unicode and encode it back to text. We've also seen that Unicode \nobjects can be manipulated in similar ways to strings and we've seen how to \nperform input and output operations on files. Next we are going to look at how \nbest to use Unicode in a web app. \n\nThe main rule is this: \n\n**Your application should use Unicode for all strings internally, decoding any \ninput to Unicode as soon as it enters the application and encoding the Unicode \nto UTF-8 or another encoding only on output.** \n\nIf you fail to do this you will find that ``UnicodeDecodeError`` s will start \npopping up in unexpected places when Unicode strings are used with normal 8-bit\nstrings because Python's default encoding is ASCII and it will try to decode \nthe text to ASCII and fail. It is always better to do any encoding or decoding \nat the edges of your application otherwise you will end up patching lots of \ndifferent parts of your application unnecessarily as and when errors pop up. \n\nUnless you have a very good reason not to it is wise to use UTF-8 as the \ndefault encoding since it is so widely supported. \n\nThe second rule is: \n\n**Always test your application with characters above 127 and above 255 wherever\npossible.** \n\nIf you fail to do this you might think your application is working fine, but as\nsoon as your users do put in non-ASCII characters you will have problems. \nUsing arabic is always a good test and www.google.ae is a good source of sample\ntext. \n\nThe third rule is: \n\n**Always do any checking of a string for illegal characters once it's in the \nform that will be used or stored, otherwise the illegal characters might be \ndisguised.** \n\nFor example, let's say you have a content management system that takes a \nUnicode filename, and you want to disallow paths with a '/' character. You \nmight write this code: \n\n.. code-block:: python \n\n    def read_file(filename, encoding): \n        if '/' in filename: \n            raise ValueError(\"'/' not allowed in filenames\") \n        unicode_name = filename.decode(encoding) \n        f = open(unicode_name, 'r') \n        # ... return contents of file ... \n\nThis is INCORRECT. If an attacker could specify the 'base64' encoding, they \ncould pass ``L2V0Yy9wYXNzd2Q=`` which is the base-64 encoded form of the string\n``'/etc/passwd'`` which is a file you clearly don't want an attacker to get \nhold of. The above code looks for ``/`` characters in the encoded form and \nmisses the dangerous character in the resulting decoded form. \n\nThose are the three basic rules so now we will look at some of the places you \nmight want to perform Unicode decoding in a Pylons application. \n\nRequest Parameters \n------------------ \n\nPylons automatically coerces incoming form parameters (``request.POST``, ``GET`` (quote GET) and ``params``) into unicode objects (as of Pylons 0.9.6). \n\nThe request object contains a ``charset`` (encoding) attribute defining what the parameters should be decoded to (via value.decode(charset, errors)), and the decoding ``errors`` handler. \n\nThe unicode conversion of parameters can be disabled when ``charset`` is set to\nNone. \n\n.. code-block:: python \n\n    def index(self): \n        #request.charset = 'utf-8' # utf-8 is the default charset \n        #request.errors = 'replace' # replace is the default error handler \n        # a MultiDict-like object of string names and unicode values \n        decoded_get = request.GET \n\n        # The raw data is always still available when charset is None \n        request.charset = None \n        raw_get = request.GET \n        raw_params = request.params \n\nPylons can also be configured to not coerece parameters to unicode objects by \ndefault. This is done by setting the following in the Pylons config object (at \nthe bottom of your project's ``config/environment.py``): \n\n.. code-block:: python \n\n    # Don't coerce parameters to unicode \n    config['pylons.request_options']['charset'] = None \n    # You can also change the default error handler \n    #config['pylons.request_options']['errors'] = 'strict' \n\nWhen the ``request`` object is instructed to always automatically decode to \nunicode via the ``request_settings`` dictionary, the dictionary's ``charset`` \nvalue acts as a fallback charset. If a ``charset`` was sent by the browser (via\nthe ``Content-Type`` header), the browser's value will take precedent: this \ntakes place when the ``request`` object is constructed. \n\n``FieldStorage`` (file upload) objects will be handled specially for unicode \nparameters: what's provided is a copy of the original ``FieldStorage`` object \nwith a unicode version of its ``filename`` attribute. \n\nSee :ref:`file_uploads` for more information on working with file uploads/``FieldStorage`` objects. \n\n.. note:: \n\n    Only parameter values (not their associated names) are decoded to unicode \n    by default. Since parameter names commonly map directly to Python variable \n    names (which are restricted to the ASCII character set), it's usually \n    preferable to handle them as strings. For example, passing form parameters \n    to a function as keyword arguments (e.g. \\*\\*request.params.mixed()) \n    doesn't work with unicode keys. \n\n    To make ``WSGIRequest`` decode parameter names anyway, enable the \n    ``decode_param_names`` option on either the WSGIRequest object or the \n    ``request_settings`` dictionary. ``FieldStorage's`` ``name`` attributes are \n    also decoded to unicode when this option is enabled. \n\nTemplating \n---------- \n\nPylons uses Mako as its default templating language. Mako handles all content \nas unicode internally. It only deals in raw strings upon the final rendering of\nthe template (the Mako ``render()`` function, used by the Pylons ``render()`` \nfunction/Buffet plugin). The encoding of the rendered string can be configured;\nPylons sets the default value to UTF-8. To change this value, edit your \nproject's ``config/environment.py`` file and add the following option: \n\n.. code-block:: python \n\n    # Customize templating options via this variable \n    tmpl_options = config['buffet.template_options'] \n\n    tmpl_options['mako.output_encoding'] = 'utf-8' \n\nreplacing ``utf-8`` with the encoding you wish to use. \n\nMore information can be found at `Mako's Unicode Chapter  <http://www.makotemplates.org/docs/unicode.html>`_. \n\nOutput Encoding \n--------------- \n\nWeb pages should be generated with a specific encoding, most likely UTF-8. At \nthe very least, that means you should specify the following in the ``<head>`` \nsection: \n\n.. code-block:: html \n\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> \n\nThe charset should also be specified in the ``Content-Type`` header (which \nPylons automatically does for you): \n\n.. code-block:: python \n\n    response.headers['Content-type'] = 'text/html; charset=utf-8' \n\nPylons has a notion of ``response_options``, complimenting the \n``request_options`` mentioned in the `Request Parameters`_ section above. The \ndefault request charset can be changed by setting the following in the Pylons \nconfig object (at the bottom of your project's ``config/environment.py``): \n\n.. code-block:: python \n\n    config['pylons.response_options']['charset'] = 'utf-8' \n\nreplacing ``utf-8`` with the charset you wish to use. \n\nIf you specify that your output is UTF-8, generally the web browser will \ngive you UTF-8. If you want the browser to submit data using a different \ncharacter set, you can set the encoding by adding the ``accept-encoding`` \ntag to your form. Here is an example: \n\n.. code-block:: html \n\n    <form accept-encoding=\"US-ASCII\" ...> \n\nHowever, be forewarned that if the user tries to give you non-ASCII \ntext, then: \n\n* Firefox will translate the non-ASCII text into HTML entities. \n\n* IE will ignore your suggested encoding and give you UTF-8 anyway. \n\nThe lesson to be learned is that if you output UTF-8, you had better be \nprepared to accept UTF-8 by decoding the data in ``request.params`` as \ndescribed in the section above entitled `Request Parameters`_'. \n\nAnother technique which is sometimes used to determine the character set is to \nuse an algorithm to analyse the input and guess the encoding based on \nprobabilities. \n\nFor instance, if you get a file, and you don't know what encoding it is encoded\nin, you can often rename the file with a .txt extension and then try to open it\nin Firefox. Then you can use the \"View->Character Encoding\" menu to try to \nauto-detect the encoding. \n\nDatabases \n--------- \n\nYour database driver should automatically convert from Unicode objects to a \nparticular charset when writing and back again when reading. Again it is normal\nto use UTF-8 which is well supported. \n\nYou should check your database's documentation for information on how it handles Unicode. \n\nFor example MySQL's Unicode documentation is here http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html \n\nAlso note that you need to consider both the encoding of the database and the encoding used by the database driver. \n\nIf you're using MySQL together with SQLAlchemy, see the following, as \nthere are some bugs in MySQLdb that you'll need to work around: \n\nhttp://www.mail-archive.com/sqlalchemy@googlegroups.com/msg00366.html \n\nSummary \n======= \n\nHopefully you now understand the history of Unicode, how to use it in Python  and where to apply Unicode encoding and decoding in a Pylons application. You  should also be able to use Unicode in your web app remembering the basic rule to use UTF-8 to talk to the world, do the encode and decode at the edge of your  application. \n\nFurther Reading \n=============== \n\nThis information is based partly on the following articles which can be \nconsulted for further information.: \n\nhttp://www.joelonsoftware.com/articles/Unicode.html \n\nhttp://www.amk.ca/python/howto/unicode \n\nPlease feel free to report any mistakes to the Pylons mailing list or to the \nauthor. Any corrections or clarifications would be gratefully received. \n"
  },
  {
    "path": "pylons/docs/en/upgrading.rst",
    "content": ".. _upgrading:\n\n=========\nUpgrading\n=========\n\n1.0 -> 1.0.1\n============\n\nNo changes are necessary, however to take advantage of MarkupSafe's faster\nHTML escaping, the default filter in ``environment.py`` that Mako is \nconfigured with should be changed from::\n    \n    from webhelpers.html import escape\n\nTo::\n    from markupsafe import escape\n\nMarkupSafe utilizes a C extension where available for faster escaping which\ncan help on larger pages with substantial variable substitutions.\n\n\n0.9.7 -> 1.0\n============\n\nUpgrading your project is slightly different depending on which versions you're upgrading from and to. It's recommended that upgrades be done in minor revision steps, as deprecation warnings are added between revisions to help in the upgrade process.\n\nFor any project prior to 0.9.7, you should first follow the applicable docs to upgrade to 0.9.7 before proceeding.\n\nTo upgrade to 1.0, first upgrade your project to 0.10. This is a Pylons release that is fully backwards-compatible with 0.9.7. However under 0.10 a variety of warnings will be issued about the various things that need to be changed before upgrading to 1.0.\n\n.. tip::\n    Since Pylons 0.10 is only out as a beta at this point, upgrade using the\n    actual URL, for example:\n    \n    .. code-block:: bash\n        \n        $ easy_install -U http://pylonshq.com/download/0.10/Pylons-0.10.tar.gz\n\n\nBeyond the warnings issued, you should also read the following list and ensure these changes have been applied.\n\nPylons changes from 0.9.7 to 1.0:\n\n* The config object created in ``environment.py`` is now passed around explicitly. There are also some other minor updates as follows.\n    \n    Update config/environment.py to initialize and return the config::\n    \n        # Add to the imports:\n        from pylons.configuration import PylonsConfig\n    \n        # Add under 'def load_environment':\n        config = PylonsConfig()\n        \n        # Replace the make_map / app globals line with\n        config['routes.map'] = make_map(config)\n        config['pylons.app_globals'] = app_globals.Globals(config)\n        \n        # Optionally, if removing the CacheMiddleware and using the\n        # cache in the new 1.0 style, add under the previous lines:\n        import pylons\n        pylons.cache._push_object(config['pylons.app_globals'].cache)\n        \n    \n        # Add at the end of the load_environment function:\n        return config\n    \n    Update config/middleware.py to use the returned :term:`config`::\n        \n        # modify the load_environment call:\n        config = load_environment(global_conf, app_conf)\n        \n        # update the middleware calls\n        \n        # The Pylons WSGI app\n        app = PylonsApp(config=config)\n\n        # Routing/Session/Cache Middleware\n        app = RoutesMiddleware(app, config['routes.map'])\n        app = SessionMiddleware(app, config)\n\n        # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n        \n        # Add right before 'return app':\n        app.config = config\n    \n    .. note::\n    \n        The CacheMiddleware is no longer setup by default through\n        middleware, its now setup under :term:`app_globals` inside its \n        instantiation in :file:`lib/app_globals.py`.\n    \n    Update config/routing.py to accept the :term:`config`::\n        \n        # Replace the def line with\n        def make_map(config):\n    \n    Update lib/app_globals.py to accept the :term:`config`::\n        \n        # Replace the __init__ line with\n        def __init__(self, config):\n        \n        # Optionally, if you decided to remove the CacheMiddleware\n        # Add these imports\n        from beaker.cache import CacheManager\n        from beaker.util import parse_cache_config_options\n        \n        # and add this line in __init__:\n        self.cache = CacheManager(**parse_cache_config_options(config))\n    \n    Update tests/__init__.py as needed::\n        \n        from unittest import TestCase\n\n        from paste.deploy import loadapp\n        from paste.script.appinstall import SetupCommand\n        from pylons import url\n        from routes.util import URLGenerator\n        from webtest import TestApp\n\n        import pylons.test\n\n        __all__ = ['environ', 'url', 'TestController']\n\n        # Invoke websetup with the current config file\n        SetupCommand('setup-app').run([pylons.test.pylonsapp.config['__file__']])\n\n        environ = {}\n\n        class TestController(TestCase):\n\n            def __init__(self, *args, **kwargs):\n                wsgiapp = pylons.test.pylonsapp\n                config = wsgiapp.config\n                self.app = TestApp(wsgiapp)\n                url._push_object(URLGenerator(config['routes.map'], environ))\n                TestCase.__init__(self, *args, **kwargs)\n\n    .. note::\n        \n        Change the use of ``url_for`` in your tests to use \n        :class:`url <routes.util.URLGenerator>`, which is imported from\n        :file:`tests/__init__.py` in your unit tests.\n\n    \n    Finally, update websetup.py to avoid the duplicate app creation that\n    previously could occur during the unit tests::\n        \n        # Add to the imports\n        import pylons.test\n        \n        # Add under the 'def setup_app':\n        \n        # Don't reload the app if it was loaded under the testing environment\n        if not pylons.test.pylonsapp:\n            load_environment(conf.global_conf, conf.local_conf)\n        \n        \n* Change all instances of ``redirect_to(...)`` -> ``redirect(url(...))``\n    \n    ``redirect_to`` processed arguments in a slightly 'magical' manner in that \n    some of them went to the ``url_for`` while sometimes... not. :func:`~pylons.controllers.util.redirect`\n    issues a redirect and nothing more, so to generate a url, the :class:`url <routes.util.URLGenerator>`\n    instance should be used (import: ``from pylons import url``).\n\n* Ensure that all use of ``g`` is switched to using the new name, :term:`app_globals`\n\n* Change all instances of ``url_for`` to :class:`url <routes.util.URLGenerator>`. \n    \n    Note that ``url`` does not retain the current route memory like\n    ``url_for`` did by default. To get a route generated using the \n    current route, call \n    :meth:`url.current <routes.util.URLGenerator.current>`.\n    \n    For example::\n        \n        # Rather than url_for() for the current route\n        url.current()\n    \n    :class:`url <routes.util.URLGenerator>` can be imported from ``pylons``.\n\n* Change ``config`` import statement if needed\n    \n    Previously, the config object could be imported as if it was a module::\n        \n        import pylons.config\n    \n    The config object is now an object in :file:`pylons/__init__.py` so the\n    import needs to be changed to::\n        \n        from pylons import config\n\n* Routes is now explicit by default\n    \n    This won't affect those already using :class:`url <routes.util.URLGenerator>` as it ignores route memory. This change does mean that some routes which relied on a default controller of 'content' and a default action of 'index' will not work.\n  \n    To restore the old behavior, in :file:`config/routing.py`, set the mapper\n    to explicit::\n    \n        map.explicit = True\n\n* By default, the :term:`tmpl_context` (a.k.a 'c'), is no longer a :class:`~pylons.util.AttribSafeContextObj`. This means accessing attributes that don't exist will raise an :exc:`AttributeError`. \n    \n    To use the attribute-safe :term:`tmpl_context`, add this line to the\n    :file:`config/environment.py`::\n        \n        config['pylons.strict_tmpl_context'] = False\n"
  },
  {
    "path": "pylons/docs/en/views.rst",
    "content": "﻿.. _views:\n\n=====\nViews\n=====\n\n\n.. image:: _static/pylon4.jpg\n   :alt: \n   :align: left\n   :height: 434px\n   :width: 368px\n\nIn the MVC paradigm the *view* manages the presentation of the model. \n\nThe view is the interface the user sees and interacts with. For Web applications, this has historically been an HTML interface. HTML remains the dominant interface for Web apps but new view options are rapidly appearing. \n\nThese include Macromedia Flash, JSON and views expressed in alternate markup languages like XHTML, XML/XSL, WML, and Web services. It is becoming increasingly common for web apps to provide specialised views in the form of a REST API that allows programmatic read/write access to the data model. \n\nMore complex APIs are quite readily implemented via SOAP services, yet another type of view on to the data model.\n\nThe growing adoption of RDF, the graph-based representation scheme that underpins the Semantic Web, brings a perspective that is strongly weighted towards machine-readability.\n\n.. NOTE: As much as I love RDF I think the following paragraph is too verbose for our intro docs, maybe we can put this elsewhere -pjenvey\n.. RDF model data is serialized into an undecorated, standardized format that can readily be processed and rendered by client applications of increasing sophistication, such as the MIT `Simile`__ project's \"`Fresnel`__\", \"`Longwell`__\" and \"`Welkin`__\" browser extensions.\n\n.. .. __: http://simile.mit.edu/\n.. .. __: http://simile.mit.edu/fresnel/\n.. .. __: http://simile.mit.edu/longwell/\n.. .. __: http://simile.mit.edu/welkin/\n\nHandling all of these interfaces in an application is becoming increasingly challenging. One big advantage of MVC is that it makes it easier to create these interfaces and develop a web app that supports many different views and thereby provides a broad range of services.\n\nTypically, no significant processing occurs in the view; it serves only as a means of outputting data and allowing the user (or the application) to act on that data, irrespective of whether it is an online store or an employee list.\n\n.. _templates:\n\n*********\nTemplates\n*********\n\nTemplate rendering engines are a popular choice for handling the task of view presentation.\n\nTo return a processed template, it must be rendered and returned by the controller::\n    \n    from helloworld.lib.base import BaseController, render\n\n    class HelloController(BaseController):\n        def sample(self):\n            return render('/sample.mako')\n\nUsing the default Mako template engine, this will cause Mako to look in the :file:`helloworld/templates` directory (assuming the project is called 'helloworld') for a template filed called :file:`sample.mako`.\n\nThe :func:`render` function used here is actually an alias defined in your projects' :file:`base.py` for Pylons' :func:`~pylons.templating.render_mako` function.\n\n\nDirectly-supported template engines\n===================================\n\nPylons provides pre-configured options for using the `Mako`__, `Genshi`__ and `Jinja2`__ template rendering engines. They are setup automatically during the creation of a new Pylons project, or can be added later manually.\n\n\n.. __: http://www.makotemplates.org/\n.. __: http://genshi.edgewall.org/\n.. __: http://jinja.pocoo.org/\n\n\n******************************\nPassing Variables to Templates\n******************************\n\nTo pass objects to templates, the standard Pylons method is to attach them to the :term:`tmpl_context` (aliased as `c` in controllers and templates, by default) object in the :ref:`controllers`::\n\n    import logging\n\n    from pylons import request, response, session, tmpl_context as c, url\n    from pylons.controllers.util import abort, redirect\n\n    from helloworld.lib.base import BaseController, render\n\n    log = logging.getLogger(__name__)\n    \n    class HelloController(BaseController):\n\n        def index(self):\n            c.name = \"Fred Smith\"\n            return render('/sample.mako')\n\nUsing the variable in the template:\n\n.. code-block:: html+mako\n    \n    Hi there ${c.name}!\n\nStrict vs Attribute-Safe tmpl_context objects\n=============================================\n\nThe :term:`tmpl_context` object is created at the beginning of every request, and by default is an instance of the :class:`~pylons.util.AttribSafeContextObj` class, which is an Attribute-Safe object. This means that accessing attributes on it that do **not** exist will return an empty string **instead** of raising an :exc:`AttributeError` error.\n\nThis can be convenient for use in templates since it can act as a default:\n\n.. code-block:: html+mako\n    \n    Hi there ${c.name}\n\nThat will work when `c.name` has not been set, and is a bit shorter than what would be needed with the strict :class:`~pylons.util.ContextObj` context object.\n\nSwitching to the strict version of the :term:`tmpl_context` object can be done in the :file:`config/environment.py` by adding (after the config.init_app)::\n    \n    config['pylons.strict_c'] = True\n\n\n.. _template-globals:\n\n**************************\nDefault Template Variables\n**************************\n\nBy default, all templates have a set of variables present in them to make it easier to get to common objects. The full list of available names present in the templates global scope:\n\n- :term:`c` -- Template context object (Alias for :term:`tmpl_context`)\n- :term:`tmpl_context` -- Template context object\n- :data:`config` -- Pylons :class:`~pylons.configuration.PylonsConfig`\n  object (acts as a dict)\n- :term:`g` -- Project application globals object (Alias for :term:`app_globals`)\n- :term:`app_globals` -- Project application globals object\n- :term:`h` -- Project helpers module reference\n- :data:`request` -- Pylons :class:`~pylons.controllers.util.Request`\n  object for this request\n- :data:`response` -- Pylons :class:`~pylons.controllers.util.Response`\n  object for this request\n- :class:`session` -- Pylons session object (unless Sessions are\n  removed)\n- :class:`translator` -- Gettext translator object configured for\n  current locale\n- :func:`ungettext` -- Unicode capable version of gettext's ngettext\n  function (handles plural translations)\n- :func:`_` -- Unicode capable gettext translate function\n- :func:`N_` -- gettext no-op function to mark a string for\n  translation, but doesn't actually translate\n- :class:`url <routes.util.URLGenerator>` -- An instance of the :class:`routes.util.URLGenerator` configured for this request.\n\n\n****************************\nConfiguring Template Engines\n****************************\n\nA new Pylons project comes with the template engine setup inside the projects' :file:`config/environment.py` file. This section creates the Mako template lookup object and attaches it to the :term:`app_globals` object, for use by the template rendering function.\n\n.. code-block:: python\n\n    # these imports are at the top\n    from mako.lookup import TemplateLookup\n    from pylons.error import handle_mako_error\n    \n    # this section is inside the load_environment function\n    # Create the Mako TemplateLookup, with the default auto-escaping\n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from webhelpers.html import escape'])\n\n\nUsing Multiple Template Engines\n===============================\n\nSince template engines are configured in the :file:`config/environment.py` section, then used by render functions, it's trivial to setup additional template engines, or even differently configured versions of a single template engine. However, custom render functions will frequently be needed to utilize the additional template engine objects.\n\nExample of additional Mako template loader for a different templates directory for admins, which falls back to the normal templates directory::\n    \n    # Add the additional path for the admin template\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, 'public'),\n                 templates=[os.path.join(root, 'templates')],\n                 admintemplates=[os.path.join(root, 'admintemplates'),\n                                 os.path.join(root, 'templates')])\n    \n    config['pylons.app_globals'].mako_admin_lookup = TemplateLookup(\n        directories=paths['admin_templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'admintemplates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from webhelpers.html import escape'])\n\nThat adds the additional template lookup instance, next a :ref:`custom render function <custom-render>` is needed that utilizes it::\n    \n    from pylons.templating import cached_template, pylons_globals\n    \n    def render_mako_admin(template_name, extra_vars=None, cache_key=None, \n                          cache_type=None, cache_expire=None):\n        # Create a render callable for the cache function\n        def render_template():\n            # Pull in extra vars if needed\n            globs = extra_vars or {}\n\n            # Second, get the globals\n            globs.update(pylons_globals())\n\n            # Grab a template reference\n            template = globs['app_globals'].mako_admin_lookup.get_template(template_name)\n\n            return template.render(**globs)\n\n        return cached_template(template_name, render_template, cache_key=cache_key,\n                               cache_type=cache_type, cache_expire=cache_expire)\n\nThe only change from the :func:`~pylons.templating.render_mako` function that comes with Pylons is to use the `mako_admin_lookup` rather than the `mako_lookup` that is used by default.\n\n\n.. _custom-render:\n\n*******************************\nCustom :func:`render` functions\n*******************************\n\nWriting custom render functions can be used to access specific features in a template engine, such as Genshi, that go beyond the default :func:`~pylons.templating.render_genshi` functionality or to add support for additional template engines.\n\nTwo helper functions for use with the render function are provided to make it easier to include the common Pylons globals that are useful in a template in addition to enabling easy use of cache capabilities. The :func:`pylons_globals` and :func:`cached_template` functions can be used if desired.\n\nGenerally, the custom render function should reside in the project's\n``lib/`` directory, probably in :file:`base.py`.\n\nHere's a sample Genshi render function as it would look in a project's\n``lib/base.py`` that doesn't fully render the result to a string, and\nrather than use :data:`c` assumes that a dict is passed in to be used\nin the templates global namespace. It also returns a Genshi stream\ninstead the rendered string.\n\n.. code-block:: python\n    \n    from pylons.templating import pylons_globals\n    \n    def render(template_name, tmpl_vars):\n        # First, get the globals\n        globs = pylons_globals()\n\n        # Update the passed in vars with the globals\n        tmpl_vars.update(globs)\n        \n        # Grab a template reference\n        template = globs['app_globals'].genshi_loader.load(template_name)\n        \n        # Render the template\n        return template.generate(**tmpl_vars)\n\nUsing the :func:`~pylons.templating.pylons_globals` function also makes it easy to get to the :term:`app_globals` object which is where the template engine was attached in :file:`config/environment.py`.\n\n.. versionchanged:: 0.9.7\n    Prior to 0.9.7, all templating was handled through a layer called 'Buffet'. This layer frequently made customization of the template engine difficult as any customization required additional plugin modules being installed. Pylons 0.9.7 now deprecates use of the Buffet plug-in layer.\n\n.. seealso::\n    :mod:`pylons.templating` - Pylons templating API\n\n\n********************\nTemplating with Mako\n********************\n\nIntroduction\n============\n\nThe template library deals with the *view*, presenting the model. It generates (X)HTML code, CSS and Javascript that is sent to the browser. *(In the examples for this section, the project root is ``myapp``.)* \n\nStatic vs. dynamic\n------------------\n\nTemplates to generate dynamic web content are stored in `myapp/templates`, static files are stored in `myapp/public`.\n\nBoth are served from the server root, **if there is a name conflict the static files will be served in preference**\n\nMaking a template hierarchy\n===========================\n\nCreate a base template\n----------------------\n\nIn `myapp/templates` create a file named `base.mako` and edit it to appear as follows:\n\n.. code-block:: html+mako\n\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n    <html>\n      <head>\n        ${self.head_tags()}\n      </head>\n      <body>\n        ${self.body()}\n      </body>\n    </html>\n\nA base template such as the very basic one above can be used for all pages rendered by Mako. This is useful for giving a consistent look to the application. \n\n* Expressions wrapped in `${...}` are evaluated by Mako and returned as text \n* `${` and `}` may span several lines but the closing brace should not be on a line by itself (or Mako throws an error)\n* Functions that are part of the `self` namespace are defined in the Mako templates\n\nCreate child templates\n----------------------\n\nCreate another file in `myapp/templates` called `my_action.mako` and edit it to appear as follows:\n\n.. code-block:: html+mako\n\n    <%inherit file=\"/base.mako\" />\n\n    <%def name=\"head_tags()\">\n      <!-- add some head tags here -->\n    </%def>\n\n    <h1>My Controller</h1>\n\n    <p>Lorem ipsum dolor ...</p>\n\nThis file  define the functions called by `base.mako`. \n\n* The `inherit` tag specifies a parent file to pass program flow to\n* Mako defines functions with `<%def name=\"function_name()\">...</%def>`, the contents of the tag are returned\n* Anything left after the Mako tags are parsed out is automatically put into the `body()` function\n\nA consistent feel to an application can be more readily achieved if all application pages refer back to single file (in this case `base.mako`)..\n\nCheck that it works\n-------------------\n\nIn the controller action, use the following as a `return()` value,\n\n.. code-block:: python\n\n    return render('/my_action.mako')\n\n\nNow run the action, usually by visiting something like ``http://localhost:5000/my_controller/my_action`` in a browser. Selecting 'View Source' in the browser should reveal the following output:\n\n.. code-block:: html\n\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n    <html>\n      <head>\n      <!-- add some head tags here -->\n      </head>\n      <body>\n\n    <h1>My Controller</h1>\n\n    <p>Lorem ipsum dolor ...</p>\n\n      </body>\n    </html>\n\n.. seealso::\n\n    The `Mako documentation <http://www.makotemplates.org/docs/>`_\n        Reasonably straightforward to follow\n\n    See the :ref:`i18n` \n        Provides more help on making your application more worldly.\n\n"
  },
  {
    "path": "pylons/docs/en/windowsnotes.rst",
    "content": ".. _windows_notes:\n\n=============\nWindows Notes\n=============\n\nPython scripts installed as part of the Pylons install process will be put in the ``Scripts`` directory of your Python installation, typically in ``C:\\Python24\\Scripts``. By default on Windows, this directory is not in your ``PATH``; this can cause the following error message when running a command such as ``paster`` from the command prompt:\n\n.. code-block:: text\n\n\tC:\\Documents and Settings\\James>paster\n\t'paster' is not recognized as an internal or external command,\n\toperable program or batch file.\n\nTo run the scripts installed with Pylons either the full path must be specified:\n\n.. code-block:: text\n\n\tC:\\Documents and Settings\\James>C:\\Python24\\Scripts\\paster\n\tUsage: C:\\Python24\\Scripts\\paster-script.py COMMAND\n\tusage: paster-script.py [paster_options] COMMAND [command_options]\n\n\toptions:\n\t  --version         show program's version number and exit\n\t  --plugin=PLUGINS  Add a plugin to the list of commands (plugins are Egg\n\t\t\t    specs; will also require() the Egg)\n\t  -h, --help        Show this help message\n\t\n\t... etc ...\n\t\nor (the preferable solution) the ``Scripts`` directory must be added to the ``PATH`` as described below.\n\nFor Win2K or WinXP\n------------------\n\n#. From the desktop or Start Menu, right click My Computer and click Properties.\n#. In the System Properties window, click on the Advanced tab.\n#. In the Advanced section, click the Environment Variables button. \n#. Finally, in the Environment Variables window, highlight the path variable in the Systems Variable section and click edit. Add or modify the path lines with the paths you wish the computer to access. Each different directory is separated with a semicolon as shown below:\n\n.. code-block:: text\n\n\tC:\\Program Files;C:\\WINDOWS;C:\\WINDOWS\\System32\n      \n#. Add the path to your scripts directory:\n\n.. code-block:: text\n\n\tC:\\Program Files;C:\\WINDOWS;C:\\WINDOWS\\System32;C:\\Python24\\Scripts\n\t\nSee `Finally`_ below.\n\t\nFor Windows 95, 98 and ME\n-------------------------\n\nEdit ``autoexec.bat``, and add the following line to the end of the file:\n\n.. code-block:: bash\n\n\tset PATH=%PATH%;C:\\Python24\\Scripts\n\nSee `Finally`_ below.\n\nFinally\n-------\n\nRestarting your computer may be required to enable the change to the ``PATH``. Then commands may be entered from any location:\n\n.. code-block:: text\n\n\tC:\\Documents and Settings\\James>paster\n\tUsage: C:\\Python24\\Scripts\\paster-script.py COMMAND\n\tusage: paster-script.py [paster_options] COMMAND [command_options]\n\n\toptions:\n\t  --version         show program's version number and exit\n\t  --plugin=PLUGINS  Add a plugin to the list of commands (plugins are Egg\n\t\t\t    specs; will also require() the Egg)\n\t  -h, --help        Show this help message\n\t\n\t... etc ...\n\nAll documentation assumes the ``PATH`` is setup correctly as described above.\n"
  },
  {
    "path": "pylons/docs/en/wsgi_support.rst",
    "content": ".. _wsgi_support:\n\n============\nWSGI support\n============\n\nThe Web Server Gateway Interface `defined in PEP 333 <http://www.python.org/dev/peps/pep-0333/>`_ is a standard interface between web servers and Python web applications or frameworks, to promote web application portability across a variety of web servers. \n\nPylons supports the Web Server Gateway Interface (or WSGI for short, pronounced \"wizgy\") throughout its stack. This is important for developers because it means that as well coming with all the features you would expect of a modern web framework, Pylons is also extremely flexible. With the WSGI it is possible to change any part of the Pylons stack to add new functionality or modify a request or a response without having to take apart the whole framework. \n\nPaste and WSGI \n-------------- \n\nMost of Pylons' WSGI capability comes from its close integration with Paste. Paste provides all the tools and middleware necessary to deploy WSGI applications. It can be thought of as a low-level WSGI framework designed for other web frameworks to build upon. Pylons is an example of a framework which makes full use of the possibilities of Paste. \n\nIf you want to, you can get the WSGI application object from your Pylons configuration file like this: \n\n.. code-block:: python \n\n    from paste.deploy import loadapp \n    wsgi_app = loadapp('config:/path/to/config.ini') \n\nYou can then serve the file using a WSGI server. Here is an example using the WSGI Reference Implementation included with Python 2.5: \n\n.. code-block:: python \n\n    from paste.deploy import loadapp \n    wsgi_app = loadapp('config:/path/to/config.ini') \n\n    from wsgiref import simple_server \n    httpd = simple_server.WSGIServer(('',8000), simple_server.WSGIRequestHandler) \n    httpd.set_app(wsgi_app) \n    httpd.serve_forever() \n\nThe ``paster serve`` command you will be used to using during the development of Pylons projects combines these two steps of creating a WSGI app from the config file and serving the resulting file to give the illusion that it is serving the config file directly. \n\nBecause the resulting Pylons application is a WSGI application it means you can do the same things with it that you can do with any WSGI application. For example add a middleware chain to it or serve it via FastCGI/SCGI/CGI/mod_python/AJP or standalone. \n\nYou can also configure extra WSGI middleware, applications and more directly using the configuration file. The various options are described in the `Paste Deploy Documentation <http://pythonpaste.org/deploy/>`_ so we won't repeat them here. \n\nUsing a WSGI Application as a Pylons 0.9 Controller \n--------------------------------------------------- \n\nIn Pylons 0.9 controllers are derived from ``pylons.controllers.WSGIController`` and are also valid WSGI applications. Unless your controller is derived from the legacy ``pylons.controllers.Controller`` class it is also assumed to be a WSGI application. This means that you don't actually need to use a Pylons controller class in your controller, any WSGI application will work as long as you give it the same name. \n\nFor example, if you added a ``hello`` controller by executing ``paster controller hello``, you could modify it to look like this: \n\n.. code-block:: python \n\n    def HelloController(environ, start_response): \n        start_response('200 OK', [('Content-Type','text/html')]) \n        return ['Hello World!'] \n\nor use ``yield`` statements like this: \n\n.. code-block:: python \n\n    def HelloController(environ, start_response): \n        start_response('200 OK', [('Content-Type','text/html')]) \n        yield 'Hello ' \n        yield 'World!' \n\nor use the standard Pylons ``Response`` object which is a valid WSGI response which takes care of calling ``start_response()`` for you: \n\n.. code-block:: python \n\n    def HelloController(environ, start_response): \n        return Response('Hello World!') \n\nand you could use the ``render()`` and ``render_response()`` objects exactly like you would in a normal controller action. \n\nAs well as writing your WSGI application as a function you could write it as a class: \n\n.. code-block:: python \n\n    class HelloController: \n\n        def __call__(self, environ, start_response): \n            start_response('200 OK', [('Content-Type','text/html')]) \n            return ['Hello World!'] \n\nAll the standard Pylons middleware defined in ``config/middleware.py`` is still available. \n\nRunning a WSGI Application From Within a Controller \n--------------------------------------------------- \n\nThere may be occasions where you don't want to replace your entire controller with a WSGI application but simply want to run a WSGI application from with a controller action. If your project was called ``test`` and you had a WSGI application called ``wsgi_app`` you could even do this: \n\n.. code-block:: python \n\n    from test.lib.base import * \n\n    def wsgi_app(environ, start_response): \n        start_response('200 OK',[('Content-type','text/html')]) \n        return ['<html>\\n<body>\\nHello World!\\n</body>\\n</html>'] \n\n    class HelloController(BaseController): \n        def index(self): \n            return wsgi_app(request.environ, self.start_response) \n\nConfiguring Middleware Within a Pylons Application \n-------------------------------------------------- \n\nA Pylons application middleware stack is directly exposed in the project's ``config/middleware.py`` file. This means that you can add and remove pieces from the stack as you choose. \n\n.. Warning:: If you remove any of the default middleware you are likely to find that various parts of Pylons stop working! \n\nAs an example, if you wanted to add middleware that added a new key to the environ dictionary you might do this: \n\n.. code-block:: python \n\n    # YOUR MIDDLEWARE \n    # Put your own middleware here, so that any problems are caught by the error \n    # handling middleware underneath \n\n    class KeyAdder: \n    def __init__(self, app, key, value): \n        self.app = app \n        if '.' not in key: \n            raise Exception(\"WSGI environ keys must contain a '.' character\") \n        self.key = key \n        self.value = value \n\n    def __call__(self, environ, start_response): \n        environ[self.key] = self.value \n        return self.app(environ, start_response) \n\n    app = KeyAdder(app, 'test.hello', 'Hello World') \n\nThen in your controller you could write: \n\n.. code-block:: python \n\n    return Response(request.environ['test.hello']) \n\nand you would see your ``Hello World!`` message. \n\nOf course, this isn't a particularly useful thing to do. Middleware classes can do one of four things or a combination of them: \n\n* Change the environ dictionary \n* Change the status \n* Change the HTTP headers \n* Change the response body of the application \n\nWith the ability to do these things as a middleware you can create authentication code, error handling middleware and more but the great thing about WSGI is that someone probably already has so you can consult the `wsgi.org middleware list <http://wsgi.org/wsgi/Middleware_and_Utilities>`_ or have a look at the `Paste project <http://pythonpaste.org>`_ and reuse an exisiting piece of middleware. \n\nThe Cascade \n----------- \n\nTowards the end of the middleware stack in your project's ``config/middleware.py`` file you will find a special piece of middleware called the cascade: \n\n.. code-block:: python \n\n    app = Cascade([static_app, javascripts_app, app]) \n\nPassed a list of applications, ``Cascade`` will try each of them in turn. If one returns a 404 status code then the next application is tried until one of the applications returns a code other than ``404`` in which case its response is returned. If all applications fail, then the last application's failure response is used. \n\nThe three WSGI applications in the cascade serve files from your project's ``public`` directory first then if nothing matches, the WebHelpers module JavaScripts are searched and finally if no JavaScripts are found your Pylons app is tried. This is why the ``public/index.html`` file is served before your controller is executed and why you can put ``/javascripts/`` into your HTML and the files will be found. \n\nYou are free to change the order of the cascade or add extra WSGI applications to it before ``app`` so that other locations are checked before your Pylons application is executed. \n\nUseful Resources \n---------------- \n\nWhilst other frameworks have put WSGI adapters at the end of their stacks so that their applications can be served by WSGI servers, we hope you can see how fully Pylons embraces WSGI throughout its design to be the most flexible and extensible of the main Python web frameworks. \n\nTo find out more about the Web Server Gateway Interface you might find the following resources useful: \n\n* `PEP 333 <http://www.python.org/dev/peps/pep-0333/>`_ \n* `The WSGI website at wsgi.org <http://wsgi.org>`_ \n* XML.com articles: Introducing WSGI - Pythons Secret Web Weapon.html `Part 1 <http://www.xml.com/pub/a/2006/09/27/introducing-wsgi-pythons-secret-web-weapon.html>`_ `Part 2 <http://www.xml.com/pub/a/2006/10/04/introducing-wsgi-pythons-secret-web-weapon-part-two.html>`_ \n\n"
  },
  {
    "path": "pylons/docs/uploader.py",
    "content": "import cPickle\nimport mimetypes\nimport os\nimport sys\nimport socket\nfrom os import path\n\nimport httplib2\nimport simplejson\n\nsocket.setdefaulttimeout(60)\n\nHERE_DIR = os.getcwd()\nBUILD_DIR = path.join(HERE_DIR, '_build')\n\n#host = 'http://localhost:25050'\nhost = 'http://pylonshq.com'\n\npost_uri = '%s/docs/upload' % host\nimage_uri = '%s/docs/upload_image' % host\ndelete_uri = '%s/docs/delete_revision' % host\n\n\ndef scan_dir(parent, directory):\n    files = []\n    for name in os.listdir(directory):\n        full_name = path.join(directory, name)\n        if name in ['_sources', '_static']:\n            continue\n        if path.isdir(full_name):\n            new_parent = parent + '/' + name\n            files.extend(scan_dir(new_parent, full_name))\n        else:\n            if name.endswith('.fpickle') or name.endswith('.pickle'):\n                fp = open(full_name, 'r')\n                data = cPickle.load(fp)\n                fp.close()\n                files.append(\n                    ('/'.join([parent, name]), data)\n                )\n            elif name == 'objects.inv':\n                fp = open(full_name, 'r')\n                data = {}\n                data['current_page_name'] = 'objects.inv'\n                data['content'] = fp.read()\n                fp.close()\n                files.append(\n                    ('/'.join([parent, name]), data)\n                )\n    return files\n\ndef scan_images(directory):\n    files = []\n    for name in os.listdir(directory):\n        if name[-4:] in ['.png', '.jpg', 'gif']:\n            files.append(name)\n    return files\n\nfiles = scan_dir('', path.join(BUILD_DIR, 'web'))\nimages = scan_images(path.join(BUILD_DIR, 'web', '_images'))\nhttp = httplib2.Http(timeout=60)\n\nbasedata = {}\n# Find the metadata about versions and such\nfor filename, filedoc in files:\n    if 'globalcontext.pickle' in filename:\n        basedata['version'] = filedoc['version']\n        basedata['project'] = filedoc['project']\n        basedata['shorttitle'] = filedoc['shorttitle']\n\nif len(sys.argv) < 2:\n    raise Exception('Failed to specify doc-key')\n\ndockey = sys.argv[1]\nheaders = {}\nheaders.setdefault('Accept', 'application/json')\nheaders.setdefault('User-Agent', 'Doc Uploader')\nheaders.setdefault('Content-Type', 'application/json')\nheaders.setdefault('Authkey', dockey)\n\nlanguage = os.path.split(HERE_DIR)[-1]\n\n# Delete this revision, just in case\n# del_uri = '%s/%s/%s' % (delete_uri, basedata['project'], basedata['version'])\n# resp, data = http.request(del_uri, 'GET', headers=headers)\n\nfor filename, filedoc in files:\n    if not isinstance(filedoc, dict):\n        continue\n    filedoc['filename'] = filename\n    filedoc['language'] = language\n    filedoc.update(basedata)\n    content = simplejson.dumps(filedoc, ensure_ascii=False).encode('utf-8')\n    headers['Content-Length'] = str(len(content))\n    resp, data = http.request(post_uri, 'POST', body=content, headers=headers)\n    status_code = int(resp.status)\n    if status_code == 200:\n        print \"Uploaded %s\" % filename\n    else:\n        print \"FAILED: %s\" % filename\n\nfor filename in images:\n    headers['Content-Type'] = mimetypes.guess_type(filename)\n    fp = open(path.join(BUILD_DIR, 'web', '_images', filename), 'r')\n    file_content = fp.read()\n    fp.close()\n    headers['Content-Length'] = str(len(file_content))\n    resp, data = http.request(image_uri + '?version=%s&project=%s&name=%s' %\n                              (basedata['version'], basedata['project'], filename),\n                              'POST', body=file_content, headers=headers)\n    status_code = int(resp.status)\n    if status_code == 200:\n        print \"Uploaded %s\" % filename\n    else:\n        print \"FAILED: %s\" % filename\n"
  },
  {
    "path": "pylons/error.py",
    "content": "\"\"\"Custom EvalException support\n\nProvides template engine HTML error formatters for the Template tab of\nEvalException.\n\n\"\"\"\nimport sys\n\ntry:\n    import mako.exceptions\nexcept ImportError:\n    mako = None\n\n__all__ = ['handle_mako_error']\n\n\ndef handle_mako_error(context, exc):\n    try:\n        exc.is_mako_exception = True\n    except:\n        pass\n    raise exc, None, sys.exc_info()[2]\n\n\ndef myghty_html_data(exc_value):\n    \"\"\"Format a Myghty exception as HTML\"\"\"\n    if hasattr(exc_value, 'htmlformat'):\n        return exc_value.htmlformat()[333:-14]\n    if hasattr(exc_value, 'mtrace'):\n        return exc_value.mtrace.htmlformat()[333:-14]\n\ntemplate_error_formatters = [myghty_html_data]\n\n\nif mako:\n    def mako_html_data(exc_value):\n        \"\"\"Format a Mako exception as HTML\"\"\"\n        if getattr(exc_value, 'is_mako_exception', False) or \\\n           isinstance(exc_value, (mako.exceptions.CompileException,\n                                  mako.exceptions.SyntaxException)):\n            return mako.exceptions.html_error_template().render(full=False,\n                                                                css=False)\n    template_error_formatters.insert(0, mako_html_data)\n"
  },
  {
    "path": "pylons/i18n/__init__.py",
    "content": "\"\"\"Internationalization and Localization functionality\"\"\"\nfrom pylons.i18n.translation import *\n"
  },
  {
    "path": "pylons/i18n/translation.py",
    "content": "\"\"\"Translation/Localization functions.\n\nProvides :mod:`gettext` translation functions via an app's\n``pylons.translator`` and get/set_lang for changing the language\ntranslated to.\n\n\"\"\"\nimport os\nfrom gettext import NullTranslations, translation\n\nimport pylons\n\n__all__ = ['_', 'add_fallback', 'get_lang', 'gettext', 'gettext_noop',\n           'lazy_gettext', 'lazy_ngettext', 'lazy_ugettext', 'lazy_ungettext',\n           'ngettext', 'set_lang', 'ugettext', 'ungettext', 'LanguageError',\n           'N_']\n\n\nclass LanguageError(Exception):\n    \"\"\"Exception raised when a problem occurs with changing languages\"\"\"\n    pass\n\n\nclass LazyString(object):\n    \"\"\"Has a number of lazily evaluated functions replicating a\n    string. Just override the eval() method to produce the actual value.\n\n    This method copied from TurboGears.\n\n    \"\"\"\n    def __init__(self, func, *args, **kwargs):\n        self.func = func\n        self.args = args\n        self.kwargs = kwargs\n\n    def eval(self):\n        return self.func(*self.args, **self.kwargs)\n\n    def __unicode__(self):\n        return unicode(self.eval())\n\n    def __str__(self):\n        return str(self.eval())\n\n    def __mod__(self, other):\n        return self.eval() % other\n\n    def format(self, *args):\n        return self.eval().format(*args)\n\n\ndef lazify(func):\n    \"\"\"Decorator to return a lazy-evaluated version of the original\"\"\"\n    def newfunc(*args, **kwargs):\n        return LazyString(func, *args, **kwargs)\n    newfunc.__name__ = 'lazy_%s' % func.__name__\n    newfunc.__doc__ = 'Lazy-evaluated version of the %s function\\n\\n%s' % \\\n        (func.__name__, func.__doc__)\n    return newfunc\n\n\ndef gettext_noop(value):\n    \"\"\"Mark a string for translation without translating it. Returns\n    value.\n\n    Used for global strings, e.g.::\n\n        foo = N_('Hello')\n\n        class Bar:\n            def __init__(self):\n                self.local_foo = _(foo)\n\n        h.set_lang('fr')\n        assert Bar().local_foo == 'Bonjour'\n        h.set_lang('es')\n        assert Bar().local_foo == 'Hola'\n        assert foo == 'Hello'\n\n    \"\"\"\n    return value\nN_ = gettext_noop\n\n\ndef gettext(value):\n    \"\"\"Mark a string for translation. Returns the localized string of\n    value.\n\n    Mark a string to be localized as follows::\n\n        gettext('This should be in lots of languages')\n\n    \"\"\"\n    return pylons.translator.gettext(value)\nlazy_gettext = lazify(gettext)\n\n\ndef ugettext(value):\n    \"\"\"Mark a string for translation. Returns the localized unicode\n    string of value.\n\n    Mark a string to be localized as follows::\n\n        _('This should be in lots of languages')\n\n    \"\"\"\n    return pylons.translator.ugettext(value)\n_ = ugettext\nlazy_ugettext = lazify(ugettext)\n\n\ndef ngettext(singular, plural, n):\n    \"\"\"Mark a string for translation. Returns the localized string of\n    the pluralized value.\n\n    This does a plural-forms lookup of a message id. ``singular`` is\n    used as the message id for purposes of lookup in the catalog, while\n    ``n`` is used to determine which plural form to use. The returned\n    message is a string.\n\n    Mark a string to be localized as follows::\n\n        ngettext('There is %(num)d file here', 'There are %(num)d files here',\n                 n) % {'num': n}\n\n    \"\"\"\n    return pylons.translator.ngettext(singular, plural, n)\nlazy_ngettext = lazify(ngettext)\n\n\ndef ungettext(singular, plural, n):\n    \"\"\"Mark a string for translation. Returns the localized unicode\n    string of the pluralized value.\n\n    This does a plural-forms lookup of a message id. ``singular`` is\n    used as the message id for purposes of lookup in the catalog, while\n    ``n`` is used to determine which plural form to use. The returned\n    message is a Unicode string.\n\n    Mark a string to be localized as follows::\n\n        ungettext('There is %(num)d file here', 'There are %(num)d files here',\n                  n) % {'num': n}\n\n    \"\"\"\n    return pylons.translator.ungettext(singular, plural, n)\nlazy_ungettext = lazify(ungettext)\n\n\ndef _get_translator(lang, **kwargs):\n    \"\"\"Utility method to get a valid translator object from a language\n    name\"\"\"\n    if not lang:\n        return NullTranslations()\n    if 'pylons_config' in kwargs:\n        conf = kwargs.pop('pylons_config')\n    else:\n        conf = pylons.config.current_conf()\n    localedir = os.path.join(conf['pylons.paths']['root'], 'i18n')\n    if not isinstance(lang, list):\n        lang = [lang]\n    try:\n        translator = translation(conf['pylons.package'], localedir,\n                                 languages=lang, **kwargs)\n    except IOError, ioe:\n        raise LanguageError('IOError: %s' % ioe)\n    translator.pylons_lang = lang\n    return translator\n\n\ndef set_lang(lang, set_environ=True, **kwargs):\n    \"\"\"Set the current language used for translations.\n\n    ``lang`` should be a string or a list of strings. If a list of\n    strings, the first language is set as the main and the subsequent\n    languages are added as fallbacks.\n    \"\"\"\n    translator = _get_translator(lang, **kwargs)\n    if not set_environ:\n        return translator\n    environ = pylons.request.environ\n    environ['pylons.pylons'].translator = translator\n    if 'paste.registry' in environ:\n        environ['paste.registry'].replace(pylons.translator, translator)\n\n\ndef get_lang():\n    \"\"\"Return the current i18n language used\"\"\"\n    return getattr(pylons.translator, 'pylons_lang', None)\n\n\ndef add_fallback(lang, **kwargs):\n    \"\"\"Add a fallback language from which words not matched in other\n    languages will be translated to.\n\n    This fallback will be associated with the currently selected\n    language -- that is, resetting the language via set_lang() resets\n    the current fallbacks.\n\n    This function can be called multiple times to add multiple\n    fallbacks.\n    \"\"\"\n    return pylons.translator.add_fallback(_get_translator(lang, **kwargs))\n"
  },
  {
    "path": "pylons/log.py",
    "content": "\"\"\"Logging related functionality\n\nThis logging Handler logs to ``environ['wsgi.errors']`` as designated\nin :pep:`333`.\n\n\"\"\"\nimport logging\nimport types\n\nimport pylons\n\n__all__ = ['WSGIErrorsHandler']\n\n\nclass WSGIErrorsHandler(logging.Handler):\n\n    \"\"\"A handler class that writes logging records to\n    `environ['wsgi.errors']`.\n\n    This code is derived from CherryPy's\n    :class:`cherrypy._cplogging.WSGIErrorHandler`.\n\n    ``cache``\n        Whether the `wsgi.errors` stream is cached (instead of looked up\n        via `pylons.request.environ` per every logged message). Enabling\n        this option is not recommended (particularly for the use case of\n        logging to `wsgi.errors` outside of a request) as the behavior\n        of a cached `wsgi.errors` stream is not strictly defined. In\n        particular, `mod_wsgi <http://www.modwsgi.org>`_'s `wsgi.errors`\n        will raise an exception when used outside of a request.\n\n    \"\"\"\n\n    def __init__(self, cache=False, *args, **kwargs):\n        logging.Handler.__init__(self, *args, **kwargs)\n        self.cache = cache\n        self.cached_stream = None\n\n    def get_wsgierrors(self):\n        \"\"\"Return the wsgi.errors stream\n\n        Raises a TypeError when outside of a web request\n        (pylons.request is not setup)\n\n        \"\"\"\n        if not self.cache:\n            return pylons.request.environ.get('wsgi.errors')\n        elif not self.cached_stream:\n            self.cached_stream = pylons.request.environ.get('wsgi.errors')\n            return self.cached_stream\n        return self.cached_stream\n\n    def flush(self):\n        \"\"\"Flushes the stream\"\"\"\n        try:\n            stream = self.get_wsgierrors()\n        except TypeError:\n            pass\n        else:\n            if stream:\n                stream.flush()\n\n    def emit(self, record):\n        \"\"\"Emit a record\"\"\"\n        try:\n            stream = self.get_wsgierrors()\n        except TypeError:\n            pass\n        else:\n            if not stream:\n                return\n            try:\n                msg = self.format(record)\n                fs = \"%s\\n\"\n                if not hasattr(types, \"UnicodeType\"):  # if no unicode support\n                    stream.write(fs % msg)\n                else:\n                    try:\n                        stream.write(fs % msg)\n                    except UnicodeError:\n                        stream.write(fs % msg.encode(\"UTF-8\"))\n                self.flush()\n            except (KeyboardInterrupt, SystemExit):\n                raise\n            except:\n                self.handleError(record)\n"
  },
  {
    "path": "pylons/media/javascripts/traceback.js",
    "content": "$(document).ready(function() {\n    var getProxyJSON = function(host, path, data, callback) {\n        data['host'] = host;\n        data['path'] = path;\n        var uri = TRACEBACK.uri+'/relay';\n        $.getJSON(uri, data, callback);\n    };\n\n    // Manipulate DOM to add the iframe, and move things around\n    var newholder = $(document.createElement(\"div\")).addClass('widget_layout');\n    $('div.feature-highlight').wrapAll(newholder[0])[0].appendChild(\n        $('button:last').remove()[0]);\n    $('div.widget_layout')[0].appendChild(document.getElementById('service_widget'));\n\n    // Hide the tabs we shouldn't see\n    $('.searchtab').hide();\n\n    // Bind the click functions for each tab\n    $('a.overview').click(function () {\n        $('#supportnav li').removeClass('active');\n        $(this).parent().addClass('active');\n        $('.overviewtab').show();\n        $('.posttracebacktab, .searchtab').hide();\n        return false;\n    });\n\n    $('a.search').click(function () {\n        $('#supportnav li').removeClass('active');\n        $(this).parent().addClass('active');\n        $('.searchtab').show();\n        $('.posttracebacktab, .overviewtab').hide();\n        return false;\n    });\n\n    // Set the search field to the exception as the default search\n    $('.searchtab input[@type=\"text\"]')[0].value = $('code.main-exception').text();\n\n    // Bind the search button to hit the mail lists\n    $('.searchtab input[@type=\"submit\"]').click(function () {\n\n        // Populate the lists array with the strings for the lists to include\n        // in the search\n        var lists = [];\n        var options = $('.searchtab input[@type=\"checkbox\"]').serializeArray();\n        $.each(options, function(i, val) {\n            lists.push('list:' + val.value);\n        });\n\n        // Setup the search data\n        var data = {mode:'json', page:1};\n        data.q = lists.join(' ') + \" \" + $('.searchtab input[@type=\"text\"]')[0].value;\n\n        var sr = $('.searchresults');\n        sr.html('Loading...');\n        var searchResults = getProxyJSON('markmail.org', '/results.xqy', data,\n            function(data, textStatus) {\n                stuff = data;\n                var numresults = $(document.createElement('p'));\n                numresults.addClass('results');\n                numresults.html(data.search.start + ' to ' + data.search.end\n                    + ' of ' + data.search.estimation);\n                var searchlink = document.createElement('a');\n                searchlink.href = 'http://markmail.org' + data.search.permalink;\n                searchlink.target = '_blank';\n                $(searchlink).html('View all results');\n                numresults.prepend(searchlink);\n                sr.html('').append(numresults);\n\n                // If there's no search results, stop here\n                if (!data.search.results) {\n                    return false;\n                }\n\n                // Iterate through the search results adding them dynamically\n                // to the element\n                $.each(data.search.results.result, function(i, val) {\n                    var result = $(document.createElement('div')).addClass('result');\n                    var link = document.createElement('a');\n                    link.href = 'http://markmail.org' + val.url;\n                    link.target = '_blank';\n                    $(link).html(val.subject);\n                    result.append(link);\n                    var blurb = $(document.createElement('div')).addClass('blurb');\n                    blurb.html(val.blurb);\n                    result.append(blurb);\n                    var meta = $(document.createElement('div')).addClass('meta');\n                    meta.html(val.date + ' - ' + val.from + ' - ' + val.list);\n                    result.append(meta);\n                    sr.append(result);\n                });\n\n                // Scroll the window down to the top of the service widget with some space\n                window.scrollTo(0, $('#service_widget').offset().top-20);\n            });\n        return false;\n    });\n});\n"
  },
  {
    "path": "pylons/media/style/black.css",
    "content": "body {\n    font-family: arial, helvetica, sans-serif;\n    background-color: #ffc900;\n    background-image: url(../img/bg.png);\n    background-repeat: repeat-x;\n    width:100%;\n    height:100%;\n    margin:0;\n    max-height: 100%;\n    padding:0;\n    border:none;\n    line-height:1.4;\n}\n#container {\n    color:white;\n    background-color:#111;\n    position: absolute;\n    left: 50%;\n    width: 500px;\n    margin-left: -300px;\n    padding:50px;\n    height:100%;\n}\n#footer {\n    margin: 120px 0 0 0;\n    padding: 3px;\n    text-align:center;\n    font-size:small;\n    background-color:#222;\n    letter-spacing: 1px;\n}\nh1 {\n    text-align:center;\n    font-size:xx-large;\n    font-weight:normal;\n    margin: 0 0 20px 0;\n    border:none;\n    padding:0;\n    letter-spacing: 5px;\n}\nh2 {\n    font-size:xx-large;\n    font-weight:normal;\n    margin: 0 0 20px 0;\n    border:none;\n    padding:0;\n}\nhr {\n    margin-bottom:30px;\n    border: 1px solid #222;\n    background-color: #222;\n    padding: 2px;\n}\n#logo {\n    background-image: url(../img/pylons-logo.gif);\n    background-repeat: no-repeat;\n    height: 0;\n    overflow: hidden;\n    padding-top: 99px;\n    width: 239px;\n}\n#left {\n    float:left;\n    width:250px;\n    margin:0 50px 0 0;\n    border:none;\n    padding:0 0 0 10px;\n}\n#right {\n    margin:0 0 0 330px;\n    border:none;\n    padding:0;\n}\nul {\n    list-style:none;\n    margin:0;\n    border:none;\n    padding:0;\n}\na:visited {\n    color:white;\n    text-decoration:none;\n}\na:link {\n    color:white;\n    text-decoration:none;\n}\n"
  },
  {
    "path": "pylons/media/style/itraceback.css",
    "content": "/* @override http://localhost:5000/_debug/media/pylons/style/itraceback.css */\n\ndiv.credits {\n    padding: 5px 0 0 0;\n    color: #777;\n    font-size: 11px;\n}\n\n#footer {\n    border-top: 1px solid #666666;\n    padding: 0;\n    margin: 20px 0 0 0;\n}\n\n#pylons_logo {\n    float: right;\n    margin: 5px 0 0 0;\n}\n\ndiv.widget_layout {\n    margin: 30px 0 0 0;\n}\ndiv.feature-highlight {\n    float: right;\n    width: 400px;\n}\n\ndiv.feature-highlight button {\n    margin: 15px 0 0 20px;\n}\n\ndiv#service_widget {\n    width: 500px;\n    padding: 0;\n    margin: 0;\n    margin-right: 10px;\n    line-height: 1.4;\n}\n\ndiv#service_widget h4, div.overviewtab h3 {\n    margin: 0;\n    padding: 0;\n    font-weight: bold;\n    font-size: 100%;\n}\n\ndiv#service_widget h2 {\n    color: #000;\n    border-bottom: 1px solid #0a0;\n    font-variant: small-caps;\n    font-size: 20px;\n    line-height: 1.3;\n    font-weight: bold;\n}\n\ndiv.overviewtab, div.posttracebacktab, div.searchtab {\n    padding: 13px 10px 10px 10px;\n    background-color: #f8f8f8;\n    border-bottom: 1px solid #ccc;\n    border-right: 1px solid #ccc;\n    border-left: 1px solid #ccc;\n}\n\ndiv.clearfix {\n    clear: left;\n    margin: 0;\n    padding: 0;\n    height: 0;\n}\n\n.hide {\n    display: none;\n}\n\ninput.query {\n    width: 350px;\n}\n\np.query {\n\tmargin: 0 0 0 20px;\n\tpadding: 0;\n}\n\n/* Nav Bar */\n\n#nv li {\n    display:block; \n    float:left; \n    list-style-type:none; \n    margin:0; \n    padding:0;\n}\n#nv a { \n    display:block; \n    float:left; \n    border: 0px;\n}\n\n\n\n\n/*** Tabs ***/\n#supportnav { float: left; width: 500px; border-bottom: 1px solid #CCC; margin: 0px; padding: 0px; }\n    #supportnav li { float: left; padding-left: 10px; margin-right: 3px; background: url(\"../img/tab-traceback.png\") no-repeat left top; }\n    #supportnav li.first-child { margin: 0; }\n    #supportnav li a { display: block; padding: 3px 10px 3px 0; border: none; outline: none; background: url(\"../img/tab-traceback.png\") no-repeat right top; color: #666; }\n    #supportnav li a:hover { color: #333; }\n    #supportnav li.active { position: relative; margin-bottom: -1px; background-position: 0 -40px; }\n    #supportnav li.active a { display: block; padding: 3px 10px 4px 0; background: url(\"../img/tab-traceback.png\") no-repeat right -40px; font-weight: bold; color: #333; }\n    #supportnav li.active a { background-position: right -40px; }\n* html #supportnav { margin-bottom: 0; }\n    \ndiv.searchresults div.result {\n\tmargin-bottom: 5px;\n\tpadding: 2px 0px 2px 4px;\n\tcursor: pointer;\n\tbackground-color: rgb(247, 247, 247);\n\tborder: 1px solid rgb(235, 235, 235);\n}\n\ndiv.searchresults div.result div.meta {\n\tfont-size: 0.8em;\n\tcolor: rgb(1, 116, 22);\n}\n\np.results a {\n    float: right;\n}\n\ndiv.searchresults div.blurb {\n\tfont-size: 0.8em;\n}\n\ndiv.searchresults div.result a {\n\ttext-decoration: underline;\n\tfont-size: 0.9em;\n\tcursor: pointer;\n}\n"
  },
  {
    "path": "pylons/media/style/orange.css",
    "content": "body{\n    margin: 0px;\n    padding: 0px;/* 4% 0 0;*/\n    background: #494943 url(../img/bg.jpg) top repeat-x; \n    font-family: Verdana, Arial, sans-serif;\n    font-size: 75%;\n    line-height: 160%;\n    color: #333;\n    /*min-width:770px;\n    max-width: 1100px;*/\n}\n\n\n/* Layout Styles */\n/*.top-bar{background: #fff url(../img/bar.png) right top no-repeat;} */\n\ndiv.main-content-bg{\n    \n}\ndiv.main-content-bar{\n    \n}\ndiv#nav-bar{\n    border-top: 1px solid #fff;\n    float: left; \n    width: 100%;\n    margin-top: 16px;\n    background: #fff url(../img/bar-bg.png) right top repeat-x;\n}\ndiv#main-content{\n    float: left; \n    width: 100%;\n    background: #fff;\n}\ndiv#side-content{\n\n    /*background: #FFf url(../img/bar.png) top right no-repeat;*/\n    padding-top: 42px;\n    float: left; margin-top: 0px; width: 30%; clear: right;\n    height: 550px;\n}\ndiv.three, div.two, div.one{\n    width: 746px;\n    padding: 0 12px 0px 12px;\n    clear: both;\n}\n\ndiv.three div.a, div.two div.a{\n    float: left;\n    clear: left;\n    width: 204px;\n    /*background-color: #ddd;*/\n}\ndiv.a div.padding, div.b div.padding, div.c div.padding, div.one div.padding{\n    padding: 0px 12px 20px 12px;\n}\n\ndiv.three div.b{\n    float: left;\n    width: 271px;\n    /*background-color: #ccc;*/\n}\ndiv.three div.c{\n    float: left;\n    clear: right;\n    width: 271px;\n    /*background-color: #bbb;*/\n}\n\ndiv.two div.b{\n    float: left;\n    clear: right;\n    width: 542px;\n   /* background-color: #333;*/\n}\n\n/* Logo */\n\n\nh1#logo{\n    margin: 20px 5% 0 5%;\n    padding: 0;\n    float: left;\n    width: 155px;\n    height: 52px;\n\n    \n    /*padding: 25px 5% 0 5%;\n    margin: 0 0 0 -2px;\n    float: left;*/\n}\n/* Nav Bar */\n\n#nav-global { \n    margin:0; \n    white-space:nowrap; \n    float: right;\n    /*position: absolute; margin:0; left:380px; top: 0px;*/\n    padding-right: 5%;\n    clear: right;\n    padding-bottom: 20px;\n}\n#nav-global li {\n    display:block; \n    float:left; \n    list-style-type:none; \n    margin:0; \n    padding:0;\n}\n#nav-global a { \n    display:block; \n    float:left; \n    /*font-family:\"Trebuchet MS\"; \n    font-size: 110%; */\n    padding:42px 18px 7px 18px; \n    background:#000000; \n    color: #ccc; \n    border: 0px;\n    text-decoration: underline;\n}\n#nav-global a:hover {\n    color:white; \n    background: url(../img/main-nav-bg-on.png) bottom repeat-x; \n    border: 0px;\n}\n#homepage #nav-homepage a, #overview #nav-overview a, #download #nav-download a, #documentation #nav-documentation a, #weblog #nav-weblog a, #community #nav-community a, #code #nav-code a { \n    color:white; \n    background:#000 url(../img/main-nav-bg.png) bottom repeat-x; \n}\n\nul#navlist\n{\n    /*background: url(../img/bar.png) left top no-repeat;*/\n    margin: 0;\n    padding:0;\n    padding-left: 5%;\n    padding-top: 8px;\n    color: #eee;\n    line-height: 34px;\n}\n\nul#navlist  li {\n    display: inline; \n}\n\nul#navlist li a\n{\n    /*font-family: Tahoma, sans-serif;\n    font-size: 11px;font-weight: bold;*/\n    border: 0px;\n    border-left: 1px solid #49A200;\n    /*padding: 0em 1em;*/\n    padding: 0 18px 0 18px;\n    color: #fff;\n    margin-right: 9px;\n    text-decoration: none;\n    float: left;\n    \n    background:  url('../img/tab-brown.png') no-repeat top right;\n}\nul#navlist  li a#highlight , ul#navlist li a#highlight:hover\n{\n    background: url('../img/tab-yellow-highlight.png') no-repeat top right;\n    color: #fff;\n    padding-right: 33px;\n}\n\nul#navlist li a:hover\n{\n    background: url('../img/tab-yellow.png') no-repeat top right;\n    color: #fff;\n}\n\nul#navlist li.active a.active,  ul#main-nav li.active a.active:hover\n{\n    background:  url('../img/tab-white.png') no-repeat top left;\n    color: #333;\n}\n\n\n\n\n\n/* Font Styles */\n\na, a:link, a:visited, a:active {\n    color: #0040BB;\n    text-decoration: none;\n    border-bottom:  1px dotted #ccc;\n}\na:hover{\n    color: #000;\n    border-bottom: 1px dotted #000;\n}\n\na.no-underline, a.no-underline:link, a.no-underline:visited, a.no-underline:active {\n    border: 0px;\n}\n\nimg.no-border{\n    border: 0px;\n}\n/* Paragraph Styles */\n\n.last{\n    padding-bottom: 0px;\n    margin-bottom: 0px;\n}\n\n.first{\n    margin-top: 0px;\n}\n\nblockquote {\n\tpadding-left: 10px;\n\tpadding-right: 10px;\n\tmargin-left: 5px;\n\tmargin-right: 0;\n\tborder-left: #ddd;\n\tborder-width: 0 0 0 1px;\n\tborder-style: none none none solid;\n}\np.first, form{\n    padding: 0px;\n    margin: 0px;\n}\n\n.medium{\n    font-family: Verdana, Geneva, Arial, sans-serif;\n    font-size: 11px;\n    line-height: 19px;\n}\n\n.large{\n    font-size: 110%;\n}\n\n.small{\n    font-size: 90%;\n    line-height: 150%;\n    font-family: Verdana, sans-serif;\n    color: #000;\n}\n\np.indent{\n    padding-left: 15px;\n    padding-bottom: 15px;\n}\n\ntt, code{\n    font-size: 130%;\n    color: #800000;\n}\n\npre{\n   /* border-top: 1px dotted #000;\n    border-left: 1px dotted #000;\n    border-right: 1px solid #999;\n    border-bottom: 1px solid #999;\n    background: #eee;*/\n    font-size: 120%;\n    \n    padding: 3px 5px 3px 10px;\n    margin-right: 10px;\n}\n\n.go{\n    /*background: url(../img/go.png) no-repeat right bottom;*/\n    padding-right: 20px;\n}\n\n.help, a.help{\n    cursor: help;\n    font-weight: normal;\n}\n\n.highlight{\n    background: #ffffcc url(../img/highlight.png) repeat;\n}\n\n/* Horizontal Rule */\n\ndiv.hr {\n    clear: both; line-height: 0px; font-size: 0px;     margin: 0px;\n    padding: 0px;\n    /*height: 4px;\n    url(../img/horizontal-rule.png) no-repeat;background: #000; \n    margin-bottom: 20px;\n    width: 770px;*/\n}\nhr {\n    height: 1em;\n    visibility: hidden;\n    margin: 0px;\n    padding: 0px;\n}\n\n/* Form Styles */\n\n.form-style input[type=submit]{\n    background: #87CD15;\n    color: #fff;\n    border-top: 1px solid #999;\n    border-left: 1px solid #999;\n    border-bottom: 1px solid #333;\n    border-right: 1px solid #333;\n}\n\n.form-style input[type=text], textarea,  input[type=file]{\n    font-family: Tahoma, sans-serif;\n    font-size: 11px;\n    color: #444;\n    background: #EAFEC2;\n    border: solid 1px #aaa;\n    padding: 3px;\n}\n\n.form-style select{\n    font-family: Tahoma, sans-serif;\n    font-size: 11px;\n    color: #444;\n    background: #EAFEC2;\n    border: solid 1px #aaa;\n}\n\n/* Lists */\n\nul.large{\n    padding: 0 0 0 15px;\n    margin: 0 0 15px 0px;\n}    \nul.large li a {\n    font-weight: normal;\n}    \n\n\n/* Header Styles */\n\nh1.first{\n    margin-top: 0px;\n    border-bottom: 1px solid #666;\n    background: #fFF;\n    padding: 3px;\n}\n\nh1, h2, h3 {\n\tfont-size: 170%;\n\tline-height: normal;\n\tfont-weight: normal;\n        font-family: Arial, sans-serif;\n\tcolor: #000000;\n\ttext-decoration: none;\n\t/*margin: 0 0 12px 0;\n\tpadding: 0;*/\n\ttext-align: left;\n}\n\nh2{\n    font-size: 140%;\n}\n\nh3 {\n    font-size: 120%;\n}\n\nh4{\n    font-size: 100%;\n}\n\nh4.asterix{\n    /*background: url(../img/box-small.png) no-repeat left center;*/\n    padding: 0px 0px 0px 15px;\n    margin: 0px;\n    /*font-size: 110%; */\n    color: #000000;\n}\n\n/* Boxes */\n\ndiv.faq-box{\n    /*border-style: solid;\n    border-color: #C6F27A;\n    border-width: 1px;*/\n    /*background:url('../img/hatch-green.png');*/\n    padding: 10px; \n    /*font-family: Verdana, Geneva, Arial, sans-serif;\n    font-size: 11px;\n    line-height: 17px;*/\n    \n}\ndiv.highlight-box{\n    border-style: solid;\n    border-color: #cccccc;\n    border-width: 1px;\n    background:url('../img/hatch-yellow.png'); \n    padding: 10px;\n    color: #555;\n    /*font-family: Verdana, Geneva, Arial, sans-serif;\n    font-size: 11px;\n    line-height: 17px;*/\n} \n\n.box-top{\n    width: 518px;\n    /*background: url(../img/box-top.png) no-repeat left top;*/\n    padding-top: 7px;\n    margin-bottom: 15px;\n}\n.box-middle{\n    /*background: url(../img/box-middle.png) repeat-y left top;*/\n}\n.box-bottom{\n    /*background: url(../img/box-bottom.png) no-repeat left bottom;*/\n    padding: 0 10px 11px 12px;\n}\n\n\n/* Utility Styles */\n\n.content-padding{\n    padding: 20px 6.5% 40px 6.5%;\n}\n.sidebar-padding{\n    padding: 15px 15px 40px 25px;\n}\n.invisible{\n    visibility: hidden;\n    font-size: 1px;\n    padding: 0px;\n    line-height: 0px;\n    margin: 0px;\n}\n\na.no-underline{\n    border: 0px;\n}\n\nimg.no-border{\n    border: 0px;\n}\n\nbr.clear{\n    clear: both;\n    width: 100%;\n}\n\n\n/* Quotes */\n.quote-top p{\n    padding: 0px;\n    margin: 0px;\n \n}\n.quote-top{\n    font-family: tahoma;\n    \n    /*background: url(../img/quote-top.png) no-repeat left top;*/\n    padding-left: 25px;\n    padding-top: 4px;\n}\n.quote-bottom{\n    /*background: url(../img/quote-bottom.png) no-repeat right bottom;*/\n    padding-right: 17px;\n    padding-bottom: 7px;\n}\n.quote-author{\n    \n    /*background: url(../img/quote-author.png) no-repeat left top;*/\n    padding-left: 20px;\n    padding-bottom: 20px;\n}\n/* Footer Styles */\n\n#footer{padding: 5px 5% 40px 5%;}\n#footer p{\n    color: #333;\n}\n#footer a{\n    font-weight: normal;\n}\n#footer a:visited{\n    color: #666;\n    text-decoration: none;\n    border-bottom: 1px dotted;\n}\n#footer a{\n    color: #888;\n    font-weight: normal;\n}\n#footer a:hover{\n    color: #000;\n    text-decoration: none;\n    border-bottom: 1px dotted;\n}\n\n"
  },
  {
    "path": "pylons/middleware.py",
    "content": "\"\"\"Pylons' WSGI middlewares\"\"\"\nimport logging\nimport os.path\n\nfrom paste.deploy.converters import asbool\nfrom paste.urlparser import StaticURLParser\nfrom weberror.evalexception import EvalException\nfrom weberror.errormiddleware import ErrorMiddleware\nfrom webhelpers.html import literal\n\nimport pylons\nfrom pylons.controllers.util import Request, Response\nfrom pylons.error import template_error_formatters\nfrom pylons.util import call_wsgi_application\n\n__all__ = ['ErrorHandler', 'error_document_template',\n           'footer_html', 'head_html', 'media_path']\n\nlog = logging.getLogger(__name__)\n\nmedia_path = os.path.join(os.path.dirname(__file__), 'media')\n\nhead_html = \"\"\"\\\n<link rel=\"stylesheet\" href=\"{{prefix}}/media/pylons/style/itraceback.css\" \\\ntype=\"text/css\" media=\"screen\" />\"\"\"\n\nfooter_html = \"\"\"\\\n<script src=\"{{prefix}}/media/pylons/javascripts/traceback.js\"></script>\n<script>\nvar TRACEBACK = {\n    uri: \"{{prefix}}\",\n    host: \"%s\",\n    traceback: \"/tracebacks\"\n}\n</script>\n<div id=\"service_widget\">\n<h2 class=\"assistance\">Online Assistance</h2>\n<div id=\"nv\">\n<ul id=\"supportnav\">\n    <li class=\"nav active\"><a class=\"overview\" href=\"#\">Overview</a></li>\n    <li class=\"nav\"><a class=\"search\" href=\"#\">Search Mail Lists</a></li>\n</ul>\n</div>\n<div class=\"clearfix\">&nbsp;</div>\n<div class=\"overviewtab\">\n<b>Looking for help?</b>\n\n<p>Here are a few tips for troubleshooting if the above traceback isn't\nhelping out.</p>\n\n<ol>\n<li>Search the mail list</li>\n<li>Post a message to the mail list</li>\n\n</div>\n\n<div class=\"searchtab\">\n<p>The following mail lists will be searched:<br />\n<input type=\"checkbox\" name=\"lists\" value=\"pylons\" checked=\"checked\" /> Pylons<br />\n<input type=\"checkbox\" name=\"lists\" value=\"python\" /> Python<br />\n<input type=\"checkbox\" name=\"lists\" value=\"mako\" /> Mako<br />\n<input type=\"checkbox\" name=\"lists\" value=\"sqlalchemy\" /> SQLAlchemy</p>\n<p class=\"query\">for: <input type=\"text\" name=\"query\" class=\"query\" /></p>\n\n<p><input type=\"submit\" value=\"Search\" /></p>\n<div class=\"searchresults\">\n\n</div>\n</div>\n\n</div>\n<div id=\"pylons_logo\">\\\n<img src=\"{{prefix}}/media/pylons/img/pylons-powered-02.png\" /></div>\n<div class=\"credits\">Pylons version %s</div>\"\"\"\n\nreport_libs = ['pylons', 'genshi', 'sqlalchemy']\n\n\ndef DebugHandler(app, global_conf, **kwargs):\n    footer = footer_html % (kwargs.get('traceback_host',\n                                       'pylonshq.com'),\n                            pylons.__version__)\n    py_media = dict(pylons=media_path)\n    app = EvalException(app, global_conf,\n                        templating_formatters=template_error_formatters,\n                        media_paths=py_media, head_html=head_html,\n                        footer_html=footer,\n                        libraries=report_libs)\n    return app\n\n\ndef ErrorHandler(app, global_conf, **errorware):\n    \"\"\"ErrorHandler Toggle\n\n    If debug is enabled, this function will return the app wrapped in\n    the WebError ``EvalException`` middleware which displays\n    interactive debugging sessions when a traceback occurs.\n\n    Otherwise, the app will be wrapped in the WebError\n    ``ErrorMiddleware``, and the ``errorware`` dict will be passed into\n    it. The ``ErrorMiddleware`` handles sending an email to the address\n    listed in the .ini file, under ``email_to``.\n\n    \"\"\"\n    if asbool(global_conf.get('debug')):\n        footer = footer_html % (pylons.config.get('traceback_host',\n                                                  'pylonshq.com'),\n                                pylons.__version__)\n        py_media = dict(pylons=media_path)\n        app = EvalException(app, global_conf,\n                            templating_formatters=template_error_formatters,\n                            media_paths=py_media, head_html=head_html,\n                            footer_html=footer,\n                            libraries=report_libs)\n    else:\n        app = ErrorMiddleware(app, global_conf, **errorware)\n    return app\n\n\nclass StatusCodeRedirect(object):\n    \"\"\"Internally redirects a request based on status code\n\n    StatusCodeRedirect watches the response of the app it wraps. If the\n    response is an error code in the errors sequence passed the request\n    will be re-run with the path URL set to the path passed in.\n\n    This operation is non-recursive and the output of the second\n    request will be used no matter what it is.\n\n    Should an application wish to bypass the error response (ie, to\n    purposely return a 401), set\n    ``environ['pylons.status_code_redirect'] = True`` in the application.\n\n    \"\"\"\n    def __init__(self, app, errors=(400, 401, 403, 404),\n                 path='/error/document'):\n        \"\"\"Initialize the ErrorRedirect\n\n        ``errors``\n            A sequence (list, tuple) of error code integers that should\n            be caught.\n        ``path``\n            The path to set for the next request down to the\n            application.\n\n        \"\"\"\n        self.app = app\n        self.error_path = path\n\n        # Transform errors to str for comparison\n        self.errors = tuple([str(x) for x in errors])\n\n    def __call__(self, environ, start_response):\n        status, headers, app_iter, exc_info = call_wsgi_application(\n            self.app, environ, catch_exc_info=True)\n        if status[:3] in self.errors and \\\n            'pylons.status_code_redirect' not in environ and self.error_path:\n            # Create a response object\n            environ['pylons.original_response'] = Response(\n                status=status, headerlist=headers, app_iter=app_iter)\n            environ['pylons.original_request'] = Request(environ)\n\n            # Create a new environ to avoid touching the original request data\n            new_environ = environ.copy()\n            new_environ['PATH_INFO'] = self.error_path\n\n            newstatus, headers, app_iter, exc_info = call_wsgi_application(\n                    self.app, new_environ, catch_exc_info=True)\n        start_response(status, headers, exc_info)\n        return app_iter\n\n\nerror_document_template = literal(\"\"\"\\\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n <title>Server Error %(code)s</title>\n<!-- CSS Imports -->\n<link rel=\"stylesheet\" href=\"%(prefix)s/error/style/black.css\" type=\"text/css\" media=\"screen\" />\n\n<!-- Favorite Icons -->\n<link rel=\"icon\" href=\"%(prefix)s/error/img/favicon.ico\" type=\"image/png\" />\n\n<style type=\"text/css\">\n        .red {\n            color:#FF0000;\n        }\n        .bold {\n            font-weight: bold;\n        }\n</style>\n</head>\n\n<body>\n    <div id=\"container\">\n        %(message)s\n    </div>\n</body>\n</html>\n\"\"\")\n\n\ndef debugger_filter_factory(global_conf, **kwargs):\n    def filter(app):\n        return DebugHandler(app, global_conf, **kwargs)\n    return filter\n\n\ndef debugger_filter_app_factory(app, global_conf, **kwargs):\n    return DebugHandler(app, global_conf, **kwargs)\n"
  },
  {
    "path": "pylons/templates/__init__.py",
    "content": ""
  },
  {
    "path": "pylons/templates/controller.py_tmpl",
    "content": "import logging\n\nfrom pylons import request, response, session, tmpl_context as c, url\nfrom pylons.controllers.util import abort, redirect\n\n{{importstatement}}\n\nlog = logging.getLogger(__name__)\n\nclass {{name}}Controller(BaseController):\n\n    def index(self):\n        # Return a rendered template\n        #return render('/{{tmpl_name}}.mako')\n        # or, return a string\n        return 'Hello World'\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/config/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/config/deployment.ini_tmpl_tmpl",
    "content": "#\n# {{project}} - Pylons configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\nemail_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 0.0.0.0\nport = 5000\n\n[app:main]\nuse = egg:{{project}}\nfull_stack = true\nstatic_files = true\n\ncache_dir = %(here)s/data\nbeaker.session.key = {{package}}\nbeaker.session.secret = ${app_instance_secret}\napp_instance_uuid = ${app_instance_uuid}\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for the Cache data, or the Session saves, un-comment the desired settings\n# here:\n#beaker.cache.data_dir = %(here)s/data/cache\n#beaker.session.data_dir = %(here)s/data/sessions\n\n{{if sqlalchemy}}\n\n# SQLAlchemy database URL\nsqlalchemy.url = sqlite:///production.db\n\n{{endif}}\n\n# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*\n# Debug mode will enable the interactive debugging tool, allowing ANYONE to\n# execute malicious code after an exception is raised.\nset debug = false\n\n\n# Logging configuration\n[loggers]\nkeys = root\n\n[handlers]\nkeys = console\n\n[formatters]\nkeys = generic\n\n[logger_root]\nlevel = INFO\nhandlers = console\n\n[handler_console]\nclass = StreamHandler\nargs = (sys.stderr,)\nlevel = NOTSET\nformatter = generic\n\n[formatter_generic]\nformat = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/config/environment.py_tmpl",
    "content": "\"\"\"Pylons environment configuration\"\"\"\nimport os\n\n\n{{if template_engine == 'mako'}}\nfrom mako.lookup import TemplateLookup\n{{elif template_engine == 'genshi'}}\nfrom genshi.template import TemplateLoader\n{{elif template_engine == 'jinja2'}}\nfrom jinja2 import Environment, FileSystemLoader\n{{endif}}\nfrom pylons.configuration import PylonsConfig\n{{if template_engine == 'mako'}}\nfrom pylons.error import handle_mako_error\n{{endif}}\n{{if sqlalchemy}}\nfrom sqlalchemy import engine_from_config\n{{endif}}\n\nimport {{package}}.lib.app_globals as app_globals\nimport {{package}}.lib.helpers\nfrom {{package}}.config.routing import make_map\n{{if sqlalchemy}}\nfrom {{package}}.model import init_model\n{{endif}}\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"Configure the Pylons environment via the ``pylons.config``\n    object\n    \"\"\"\n    config = PylonsConfig()\n    \n    # Pylons paths\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, 'public'),\n                 templates=[os.path.join(root, 'templates')])\n\n    # Initialize config with the basic options\n    config.init_app(global_conf, app_conf, package='{{package}}', paths=paths)\n\n    config['routes.map'] = make_map(config)\n    config['pylons.app_globals'] = app_globals.Globals(config)\n    config['pylons.h'] = {{package}}.lib.helpers\n    \n    # Setup cache object as early as possible\n    import pylons\n    pylons.cache._push_object(config['pylons.app_globals'].cache)\n    \n    {{if template_engine == 'mako'}}\n\n    # Create the Mako TemplateLookup, with the default auto-escaping\n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from markupsafe import escape'])\n    {{elif template_engine == 'genshi'}}\n\n    # Create the Genshi TemplateLoader\n    config['pylons.app_globals'].genshi_loader = TemplateLoader(\n        paths['templates'], auto_reload=True)\n    {{elif template_engine == 'jinja2'}}\n\n    # Create the Jinja2 Environment\n    jinja2_env = Environment(loader=FileSystemLoader(paths['templates']))\n    config['pylons.app_globals'].jinja2_env = jinja2_env\n{{endif}}{{if sqlalchemy}}\n    # Setup the SQLAlchemy database engine\n    engine = engine_from_config(config, 'sqlalchemy.')\n    init_model(engine)\n    {{endif}}\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n    \n    return config\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/config/middleware.py_tmpl",
    "content": "\"\"\"Pylons middleware initialization\"\"\"\nfrom beaker.middleware import SessionMiddleware\nfrom paste.cascade import Cascade\nfrom paste.registry import RegistryManager\nfrom paste.urlparser import StaticURLParser\nfrom paste.deploy.converters import asbool\nfrom pylons.middleware import ErrorHandler, StatusCodeRedirect\nfrom pylons.wsgiapp import PylonsApp\nfrom routes.middleware import RoutesMiddleware\n\nfrom {{package}}.config.environment import load_environment\n\ndef make_app(global_conf, full_stack=True, static_files=True, **app_conf):\n    \"\"\"Create a Pylons WSGI application and return it\n\n    ``global_conf``\n        The inherited configuration for this application. Normally from\n        the [DEFAULT] section of the Paste ini file.\n\n    ``full_stack``\n        Whether this application provides a full WSGI stack (by default,\n        meaning it handles its own exceptions and errors). Disable\n        full_stack when this application is \"managed\" by another WSGI\n        middleware.\n\n    ``static_files``\n        Whether this application serves its own static files; disable\n        when another web server is responsible for serving them.\n\n    ``app_conf``\n        The application's local configuration. Normally specified in\n        the [app:<name>] section of the Paste ini file (where <name>\n        defaults to main).\n\n    \"\"\"\n    # Configure the Pylons environment\n    config = load_environment(global_conf, app_conf)\n\n    # The Pylons WSGI app\n    app = PylonsApp(config=config)\n\n    # Routing/Session Middleware\n    app = RoutesMiddleware(app, config['routes.map'], singleton=False)\n    app = SessionMiddleware(app, config)\n\n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n\n    if asbool(full_stack):\n        # Handle Python exceptions\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n        # Display error documents for 401, 403, 404 status codes (and\n        # 500 when debug is disabled)\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])\n\n    # Establish the Registry for this application\n    app = RegistryManager(app)\n\n    if asbool(static_files):\n        # Serve static files\n        static_app = StaticURLParser(config['pylons.paths']['static_files'])\n        app = Cascade([static_app, app])\n    app.config = config\n    return app\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/config/routing.py_tmpl",
    "content": "\"\"\"Routes configuration\n\nThe more specific and detailed routes should be defined first so they\nmay take precedent over the more generic routes. For more information\nrefer to the routes manual at http://routes.groovie.org/docs/\n\"\"\"\nfrom routes import Mapper\n\ndef make_map(config):\n    \"\"\"Create, configure and return the routes Mapper\"\"\"\n    map = Mapper(directory=config['pylons.paths']['controllers'],\n                 always_scan=config['debug'])\n    map.minimization = False\n    map.explicit = False\n\n    # The ErrorController route (handles 404/500 error pages); it should\n    # likely stay at the top, ensuring it can always be resolved\n    map.connect('/error/{action}', controller='error')\n    map.connect('/error/{action}/{id}', controller='error')\n\n    # CUSTOM ROUTES HERE\n\n    map.connect('/{controller}/{action}')\n    map.connect('/{controller}/{action}/{id}')\n\n    return map\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/controllers/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/controllers/error.py_tmpl",
    "content": "import cgi\n\nfrom paste.urlparser import PkgResourcesParser\nfrom pylons.middleware import error_document_template\nfrom webhelpers.html.builder import literal\n\nfrom {{package}}.lib.base import BaseController\n\nclass ErrorController(BaseController):\n    \"\"\"Generates error documents as and when they are required.\n\n    The ErrorDocuments middleware forwards to ErrorController when error\n    related status codes are returned from the application.\n\n    This behaviour can be altered by changing the parameters to the\n    ErrorDocuments middleware in your config/middleware.py file.\n\n    \"\"\"\n    def document(self):\n        \"\"\"Render the error document\"\"\"\n        request = self._py_object.request\n        resp = request.environ.get('pylons.original_response')\n        content = literal(resp.body) or cgi.escape(request.GET.get('message', ''))\n        page = error_document_template % \\\n            dict(prefix=request.environ.get('SCRIPT_NAME', ''),\n                 code=cgi.escape(request.GET.get('code', str(resp.status_int))),\n                 message=content)\n        return page\n\n    def img(self, id):\n        \"\"\"Serve Pylons' stock images\"\"\"\n        return self._serve_file('/'.join(['media/img', id]))\n\n    def style(self, id):\n        \"\"\"Serve Pylons' stock stylesheets\"\"\"\n        return self._serve_file('/'.join(['media/style', id]))\n\n    def _serve_file(self, path):\n        \"\"\"Call Paste's FileApp (a WSGI application) to serve the file\n        at the specified path\n        \"\"\"\n        request = self._py_object.request\n        request.environ['PATH_INFO'] = '/%s' % path\n        return PkgResourcesParser('pylons', 'pylons')(request.environ, self.start_response)\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/lib/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/lib/app_globals.py_tmpl",
    "content": "\"\"\"The application's Globals object\"\"\"\n\nfrom beaker.cache import CacheManager\nfrom beaker.util import parse_cache_config_options\n\nclass Globals(object):\n    \"\"\"Globals acts as a container for objects available throughout the\n    life of the application\n\n    \"\"\"\n\n    def __init__(self, config):\n        \"\"\"One instance of Globals is created during application\n        initialization and is available during requests via the\n        'app_globals' variable\n\n        \"\"\"\n        self.cache = CacheManager(**parse_cache_config_options(config))\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/lib/base.py_tmpl",
    "content": "\"\"\"The base Controller API\n\nProvides the BaseController class for subclassing.\n\"\"\"\nfrom pylons.controllers import WSGIController\n{{if template_engine in ('genshi', 'jinja2', 'mako')}}\nfrom pylons.templating import render_{{template_engine}} as render\n{{endif}}\n{{if sqlalchemy}}\n\nfrom {{package}}.model.meta import Session\n{{endif}}\n\nclass BaseController(WSGIController):\n\n    def __call__(self, environ, start_response):\n        \"\"\"Invoke the Controller\"\"\"\n        # WSGIController.__call__ dispatches to the Controller method\n        # the request is routed to. This routing information is\n        # available in environ['pylons.routes_dict']\n        {{if sqlalchemy}}\n        try:\n            return WSGIController.__call__(self, environ, start_response)\n        finally:\n            Session.remove(){{else}}        return WSGIController.__call__(self, environ, start_response){{endif}}\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/lib/helpers.py_tmpl",
    "content": "\"\"\"Helper functions\n\nConsists of functions to typically be used within templates, but also\navailable to Controllers. This module is available to templates as 'h'.\n\"\"\"\n# Import helpers as desired, or define your own, ie:\n#from webhelpers.html.tags import checkbox, password\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/model/__init__.py_tmpl",
    "content": "{{if sqlalchemy}}\n\"\"\"The application's model objects\"\"\"\nfrom {{package}}.model.meta import Session, Base\n\n\ndef init_model(engine):\n    \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n    Session.configure(bind=engine)\n\n{{endif}}\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/model/meta.py_tmpl",
    "content": "{{if sqlalchemy}}\n\"\"\"SQLAlchemy Metadata and Session object\"\"\"\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import scoped_session, sessionmaker\n\n__all__ = ['Base', 'Session']\n\n# SQLAlchemy session manager. Updated by model.init_model()\nSession = scoped_session(sessionmaker())\n\n# The declarative Base\nBase = declarative_base()\n{{else}}\n{{skip_template()}}\n{{endif}}\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/public/index.html_tmpl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n    <head>\n        <title>Welcome to Pylons!</title>\n        <style type=\"text/css\">\n            body {\n                font-family: arial, helvetica, sans-serif;\n                background-color: #ffc900;\n                background-image: url(bg.png);\n                background-repeat: repeat-x;\n                width:100%;\n                height:100%;\n                margin:0;\n                max-height: 100%;\n                padding:0;\n                border:none;\n                line-height:1.4;\n            }\n            #container {\n                color:white;\n                background-color:#111;\n                position: absolute;\n                left: 50%;\n                width: 500px;\n                margin-left: -300px;\n                padding:50px;\n                height:100%;\n            }\n            #footer {\n                margin: 120px 0 0 0;\n                padding: 3px;\n                text-align:center;\n                font-size:small;\n                background-color:#222;\n                letter-spacing: 1px;\n            }\n            h1 {\n                text-align:center;\n                font-size:xx-large;\n                font-weight:normal;\n                margin: 0 0 20px 0;\n                border:none;\n                padding:0;\n                letter-spacing: 5px;\n            }\n            h2 {\n                font-size:xx-large;\n                font-weight:normal;\n                margin: 0 0 20px 0;\n                border:none;\n                padding:0;\n            }\n            hr {\n                margin-bottom:30px;\n                border: 1px solid #222;\n                background-color: #222;\n                padding: 2px;\n            }\n            #logo {\n                background-image: url(signum8b_spk.png);\n                background-repeat: no-repeat;\n                height: 0;\n                overflow: hidden;\n                padding-top: 99px;\n                width: 239px;\n            }\n            #left {\n                float:left;\n                width:250px;\n                margin:0 50px 0 0;\n                border:none;\n                padding:0 0 0 10px;\n            }\n            #right {\n                margin:0 0 0 330px;\n                border:none;\n                padding:0;\n            }\n            ul {\n                list-style:none;\n                margin:0;\n                border:none;\n                padding:0;\n            }\n            a:visited {\n                color:white;\n                text-decoration:none;\n            }\n            a:link {\n                color:white;\n                text-decoration:none;\n            }</style>\n    </head>\n    <body>\n        <div id=\"container\">\n            <h1>Welcome to <img src=\"pylons-logo.gif\" alt=\"Logo displaying the word Pylons\"\n                    style=\"vertical-align:-15px; width: 250px;\"/>\n            </h1>\n            <hr/>\n            <div id=\"left\">\n                <h2>Let's begin!</h2>\n                <p>If you haven't used Pylons before, start with the <a href=\"http://pylonshq.com/docs/en/1.0/gettingstarted/\"\n                        style=\"text-decoration:underline;\">beginners' tutorial</a>.</p>\n            </div>\n            <div id=\"right\">\n                <h2>Help</h2>\n                <ul>\n                    <li>\n                        <a href=\"http://pylonshq.com/docs/en/1.0/\">Official documentation</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonsfaq/Home\">FAQ</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/dashboard.action\">Wiki</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonscommunity/Home#Home-JointheMailingLists\">Mailing list</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonscommunity/Home#Home-IRC\">IRC</a>\n                    </li>\n                    <li>\n                        <a href=\"http://pylonshq.com/project/pylonshq/roadmap\">Bug tracker</a>\n                    </li>\n                </ul>\n            </div>\n            <div id=\"footer\">\n                <a href=\"http://www.pylonshq.com\" style=\"color: #ccc; text-decoration:none;\"\n                    >www.pylonshq.com</a>\n            </div>\n        </div>\n    </body>\n</html>\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/templates/.distutils_placeholder",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/templates/__init__.py_tmpl",
    "content": "{{if template_engine not in ['genshi', 'kid']}}\n{{skip_template()}}\n{{endif}}\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/tests/__init__.py_tmpl",
    "content": "\"\"\"Pylons application test package\n\nThis package assumes the Pylons environment is already loaded, such as\nwhen this script is imported from the `nosetests --with-pylons=test.ini`\ncommand.\n\nThis module initializes the application via ``websetup`` (`paster\nsetup-app`) and provides the base testing objects.\n\"\"\"\nfrom unittest import TestCase\nimport os\nimport sys\n\nimport pylons\nfrom pylons.i18n.translation import _get_translator\nfrom paste.deploy import loadapp\nfrom pylons import url\nfrom paste.script.appinstall import SetupCommand\nfrom routes.util import URLGenerator\nfrom webtest import TestApp\n\nfrom {{package}}.config.environment import load_environment\n\n__all__ = ['environ', 'url', 'TestController']\n\nenviron = {}\nhere_dir = os.path.dirname(os.path.abspath(__file__))\nconf_dir = os.path.dirname(os.path.dirname(here_dir))\n\nsys.path.insert(0, conf_dir)\n\n\nclass TestController(TestCase):\n    def __init__(self, *args, **kwargs):\n        wsgiapp = loadapp('config:test.ini', relative_to=conf_dir)\n        config = wsgiapp.config\n        pylons.app_globals._push_object(config['pylons.app_globals'])\n        pylons.config._push_object(config)\n        \n        # Initialize a translator for tests that utilize i18n\n        translator = _get_translator(pylons.config.get('lang'))\n        pylons.translator._push_object(translator)\n        \n        url._push_object(URLGenerator(config['routes.map'], environ))\n        self.app = TestApp(wsgiapp)\n        TestCase.__init__(self, *args, **kwargs)\n"
  },
  {
    "path": "pylons/templates/default_project/+package+/tests/functional/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/tests/test_models.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/default_project/+package+/websetup.py_tmpl",
    "content": "\"\"\"Setup the {{project}} application\"\"\"\nimport logging\n\nfrom {{package}}.config.environment import load_environment\n{{if sqlalchemy}}\nfrom {{package}}.model.meta import Session, Base\n{{endif}}\n\nlog = logging.getLogger(__name__)\n\ndef setup_app(command, conf, vars):\n    \"\"\"Place any commands to setup {{package}} here\"\"\"\n    # Don't reload the app if it was loaded under the testing environment\n    load_environment(conf.global_conf, conf.local_conf)\n    {{if sqlalchemy}}\n\n    # Create the tables if they don't already exist\n    Base.metadata.create_all(bind=Session.bind)\n    {{endif}}\n"
  },
  {
    "path": "pylons/templates/default_project/MANIFEST.in_tmpl",
    "content": "include {{package}}/config/deployment.ini_tmpl\nrecursive-include {{package}}/public *\nrecursive-include {{package}}/templates *\n"
  },
  {
    "path": "pylons/templates/default_project/README.txt_tmpl",
    "content": "This file is for you to describe the {{project}} application. Typically\nyou would include information such as the information below:\n\nInstallation and Setup\n======================\n\nInstall ``{{project}}`` using easy_install::\n\n    easy_install {{project}}\n\nMake a config file as follows::\n\n    paster make-config {{project}} config.ini\n\nTweak the config file as appropriate and then setup the application::\n\n    paster setup-app config.ini\n\nThen you are ready to go.\n"
  },
  {
    "path": "pylons/templates/default_project/development.ini_tmpl",
    "content": "#\n# {{project}} - Pylons development environment configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\n# Uncomment and replace with the address which should receive any error reports\n#email_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = egg:{{project}}\nfull_stack = true\nstatic_files = true\n\ncache_dir = %(here)s/data\nbeaker.session.key = {{package}}\nbeaker.session.secret = somesecret\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for the Cache data, or the Session saves, un-comment the desired settings\n# here:\n#beaker.cache.data_dir = %(here)s/data/cache\n#beaker.session.data_dir = %(here)s/data/sessions\n\n{{if sqlalchemy}}\n\n# SQLAlchemy database URL\nsqlalchemy.url = sqlite:///%(here)s/development.db\n\n{{endif}}\n\n# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*\n# Debug mode will enable the interactive debugging tool, allowing ANYONE to\n# execute malicious code after an exception is raised.\n#set debug = false\n\n\n# Logging configuration\n[loggers]\nkeys = root, routes, {{package_logger}}{{if sqlalchemy}}, sqlalchemy{{endif}}\n\n[handlers]\nkeys = console\n\n[formatters]\nkeys = generic\n\n[logger_root]\nlevel = INFO\nhandlers = console\n\n[logger_routes]\nlevel = INFO\nhandlers =\nqualname = routes.middleware\n# \"level = DEBUG\" logs the route matched and routing variables.\n\n[logger_{{package_logger}}]\nlevel = DEBUG\nhandlers =\nqualname = {{package}}\n\n{{if sqlalchemy}}\n\n[logger_sqlalchemy]\nlevel = INFO\nhandlers =\nqualname = sqlalchemy.engine\n# \"level = INFO\" logs SQL queries.\n# \"level = DEBUG\" logs SQL queries and results.\n# \"level = WARN\" logs neither.  (Recommended for production systems.)\n{{endif}}\n\n[handler_console]\nclass = StreamHandler\nargs = (sys.stderr,)\nlevel = NOTSET\nformatter = generic\n\n[formatter_generic]\nformat = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s\ndatefmt = %H:%M:%S\n"
  },
  {
    "path": "pylons/templates/default_project/ez_setup.py",
    "content": "#!python\n\"\"\"Bootstrap setuptools installation\n\nIf you want to use setuptools in your package's setup.py, just include this\nfile in the same directory with it, and add this to the top of your setup.py::\n\n    from ez_setup import use_setuptools\n    use_setuptools()\n\nIf you want to require a specific version of setuptools, set a download\nmirror, or use an alternate download directory, you can do so by supplying\nthe appropriate options to ``use_setuptools()``.\n\nThis file can also be run as a script to install or upgrade setuptools.\n\"\"\"\nimport sys\nDEFAULT_VERSION = \"0.6c9\"\nDEFAULT_URL     = \"http://pypi.python.org/packages/%s/s/setuptools/\" % sys.version[:3]\n\nmd5_data = {\n    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',\n    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',\n    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',\n    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',\n    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',\n    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',\n    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',\n    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',\n    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',\n    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',\n    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',\n    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',\n    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',\n    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',\n    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',\n    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',\n    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',\n    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',\n    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',\n    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',\n    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',\n    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',\n    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',\n    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',\n    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',\n    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',\n    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',\n    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',\n    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',\n    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',\n    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',\n    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',\n    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',\n    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',\n}\n\nimport sys, os\ntry: from hashlib import md5\nexcept ImportError: from md5 import md5\n\ndef _validate_md5(egg_name, data):\n    if egg_name in md5_data:\n        digest = md5(data).hexdigest()\n        if digest != md5_data[egg_name]:\n            print >>sys.stderr, (\n                \"md5 validation of %s failed!  (Possible download problem?)\"\n                % egg_name\n            )\n            sys.exit(2)\n    return data\n\ndef use_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    download_delay=15\n):\n    \"\"\"Automatically find/download setuptools and make it available on sys.path\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end with\n    a '/').  `to_dir` is the directory where setuptools will be downloaded, if\n    it is not already available.  If `download_delay` is specified, it should\n    be the number of seconds that will be paused before initiating a download,\n    should one be required.  If an older version of setuptools is installed,\n    this routine will print a message to ``sys.stderr`` and raise SystemExit in\n    an attempt to abort the calling script.\n    \"\"\"\n    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules\n    def do_download():\n        egg = download_setuptools(version, download_base, to_dir, download_delay)\n        sys.path.insert(0, egg)\n        import setuptools; setuptools.bootstrap_install_from = egg\n    try:\n        import pkg_resources\n    except ImportError:\n        return do_download()       \n    try:\n        pkg_resources.require(\"setuptools>=\"+version); return\n    except pkg_resources.VersionConflict, e:\n        if was_imported:\n            print >>sys.stderr, (\n            \"The required version of setuptools (>=%s) is not available, and\\n\"\n            \"can't be installed while this script is running. Please install\\n\"\n            \" a more recent version first, using 'easy_install -U setuptools'.\"\n            \"\\n\\n(Currently using %r)\"\n            ) % (version, e.args[0])\n            sys.exit(2)\n        else:\n            del pkg_resources, sys.modules['pkg_resources']    # reload ok\n            return do_download()\n    except pkg_resources.DistributionNotFound:\n        return do_download()\n\ndef download_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    delay = 15\n):\n    \"\"\"Download setuptools from a specified location and return its filename\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end\n    with a '/'). `to_dir` is the directory where the egg will be downloaded.\n    `delay` is the number of seconds to pause before an actual download attempt.\n    \"\"\"\n    import urllib2, shutil\n    egg_name = \"setuptools-%s-py%s.egg\" % (version,sys.version[:3])\n    url = download_base + egg_name\n    saveto = os.path.join(to_dir, egg_name)\n    src = dst = None\n    if not os.path.exists(saveto):  # Avoid repeated downloads\n        try:\n            from distutils import log\n            if delay:\n                log.warn(\"\"\"\n---------------------------------------------------------------------------\nThis script requires setuptools version %s to run (even to display\nhelp).  I will attempt to download it for you (from\n%s), but\nyou may need to enable firewall access for this script first.\nI will start the download in %d seconds.\n\n(Note: if this machine does not have network access, please obtain the file\n\n   %s\n\nand place it in this directory before rerunning this script.)\n---------------------------------------------------------------------------\"\"\",\n                    version, download_base, delay, url\n                ); from time import sleep; sleep(delay)\n            log.warn(\"Downloading %s\", url)\n            src = urllib2.urlopen(url)\n            # Read/write all in one block, so we don't create a corrupt file\n            # if the download is interrupted.\n            data = _validate_md5(egg_name, src.read())\n            dst = open(saveto,\"wb\"); dst.write(data)\n        finally:\n            if src: src.close()\n            if dst: dst.close()\n    return os.path.realpath(saveto)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndef main(argv, version=DEFAULT_VERSION):\n    \"\"\"Install or upgrade setuptools and EasyInstall\"\"\"\n    try:\n        import setuptools\n    except ImportError:\n        egg = None\n        try:\n            egg = download_setuptools(version, delay=0)\n            sys.path.insert(0,egg)\n            from setuptools.command.easy_install import main\n            return main(list(argv)+[egg])   # we're done here\n        finally:\n            if egg and os.path.exists(egg):\n                os.unlink(egg)\n    else:\n        if setuptools.__version__ == '0.0.1':\n            print >>sys.stderr, (\n            \"You have an obsolete version of setuptools installed.  Please\\n\"\n            \"remove it from your system entirely before rerunning this script.\"\n            )\n            sys.exit(2)\n\n    req = \"setuptools>=\"+version\n    import pkg_resources\n    try:\n        pkg_resources.require(req)\n    except pkg_resources.VersionConflict:\n        try:\n            from setuptools.command.easy_install import main\n        except ImportError:\n            from easy_install import main\n        main(list(argv)+[download_setuptools(delay=0)])\n        sys.exit(0) # try to force an exit\n    else:\n        if argv:\n            from setuptools.command.easy_install import main\n            main(argv)\n        else:\n            print \"Setuptools version\",version,\"or greater has been installed.\"\n            print '(Run \"ez_setup.py -U setuptools\" to reinstall or upgrade.)'\n\ndef update_md5(filenames):\n    \"\"\"Update our built-in md5 registry\"\"\"\n\n    import re\n\n    for name in filenames:\n        base = os.path.basename(name)\n        f = open(name,'rb')\n        md5_data[base] = md5(f.read()).hexdigest()\n        f.close()\n\n    data = [\"    %r: %r,\\n\" % it for it in md5_data.items()]\n    data.sort()\n    repl = \"\".join(data)\n\n    import inspect\n    srcfile = inspect.getsourcefile(sys.modules[__name__])\n    f = open(srcfile, 'rb'); src = f.read(); f.close()\n\n    match = re.search(\"\\nmd5_data = {\\n([^}]+)}\", src)\n    if not match:\n        print >>sys.stderr, \"Internal error!\"\n        sys.exit(2)\n\n    src = src[:match.start(1)] + repl + src[match.end(1):]\n    f = open(srcfile,'w')\n    f.write(src)\n    f.close()\n\n\nif __name__=='__main__':\n    if len(sys.argv)>2 and sys.argv[1]=='--md5update':\n        update_md5(sys.argv[2:])\n    else:\n        main(sys.argv[1:])\n\n\n\n\n\n\n"
  },
  {
    "path": "pylons/templates/default_project/setup.cfg_tmpl",
    "content": "[egg_info]\ntag_build = dev\ntag_svn_revision = true\n\n[easy_install]\nfind_links = http://www.pylonshq.com/download/\n\n# Babel configuration\n[compile_catalog]\ndomain = {{package}}\ndirectory = {{package}}/i18n\nstatistics = true\n\n[extract_messages]\nadd_comments = TRANSLATORS:\noutput_file = {{package}}/i18n/{{package}}.pot\nwidth = 80\n\n[init_catalog]\ndomain = {{package}}\ninput_file = {{package}}/i18n/{{package}}.pot\noutput_dir = {{package}}/i18n\n\n[update_catalog]\ndomain = {{package}}\ninput_file = {{package}}/i18n/{{package}}.pot\noutput_dir = {{package}}/i18n\nprevious = true\n"
  },
  {
    "path": "pylons/templates/default_project/setup.py_tmpl",
    "content": "try:\n    from setuptools import setup, find_packages\nexcept ImportError:\n    from ez_setup import use_setuptools\n    use_setuptools()\n    from setuptools import setup, find_packages\n\nsetup(\n    name='{{project}}',\n    version='{{version}}',\n    description={{repr(description)}},\n    author={{repr(author)}},\n    author_email={{repr(author_email)}},\n    url={{repr(url)}},\n    install_requires=[\n        \"Pylons>=1.0.1rc1\",\n{{if sqlalchemy}}\n        \"SQLAlchemy>=0.5\",\n{{endif}}\n{{if template_engine == 'genshi'}}\n        \"Genshi>=0.4\",\n{{elif template_engine == 'jinja2'}}\n        \"Jinja2\",\n{{endif}}\n    ],\n    setup_requires=[\"PasteScript>=1.6.3\"],\n    packages=find_packages(exclude=['ez_setup']),\n    include_package_data=True,\n    test_suite='nose.collector',\n    package_data={'{{package}}': ['i18n/*/LC_MESSAGES/*.mo']},\n    #message_extractors={'{{package}}': [\n    #        ('**.py', 'python', None),\n    #        {{babel_templates_extractor}}('public/**', 'ignore', None)]},\n    zip_safe={{zip_safe}},\n    paster_plugins={{egg_plugins}},\n    entry_points=\"\"\"\n    [paste.app_factory]\n    main = {{package}}.config.middleware:make_app\n\n    [paste.app_install]\n    main = pylons.util:PylonsInstaller\n    \"\"\",\n)\n"
  },
  {
    "path": "pylons/templates/default_project/test.ini_tmpl",
    "content": "#\n# {{project}} - Pylons testing environment configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\n# Uncomment and replace with the address which should receive any error reports\n#email_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = config:development.ini\n\n# Add additional test specific configuration options as necessary.\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/__init__.py_tmpl",
    "content": ""
  },
  {
    "path": "pylons/templates/minimal_project/+package+/config/deployment.ini_tmpl_tmpl",
    "content": "#\n# {{project}} - Pylons configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\nemail_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 0.0.0.0\nport = 5000\n\n[app:main]\nuse = egg:{{project}}\nfull_stack = true\nstatic_files = true\n\ncache_dir = %(here)s/data\nbeaker.session.key = {{package}}\nbeaker.session.secret = ${app_instance_secret}\napp_instance_uuid = ${app_instance_uuid}\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for the Cache data, or the Session saves, un-comment the desired settings\n# here:\n#beaker.cache.data_dir = %(here)s/data/cache\n#beaker.session.data_dir = %(here)s/data/sessions\n\n# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*\n# Debug mode will enable the interactive debugging tool, allowing ANYONE to\n# execute malicious code after an exception is raised.\nset debug = false\n\n\n# Logging configuration\n[loggers]\nkeys = root\n\n[handlers]\nkeys = console\n\n[formatters]\nkeys = generic\n\n[logger_root]\nlevel = INFO\nhandlers = console\n\n[handler_console]\nclass = StreamHandler\nargs = (sys.stderr,)\nlevel = NOTSET\nformatter = generic\n\n[formatter_generic]\nformat = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/controllers/__init__.py_tmpl",
    "content": "\"\"\"The base Controller API\n\nProvides the BaseController class for subclassing.\n\"\"\"\nfrom pylons.controllers import WSGIController\n{{if template_engine in ('genshi', 'jinja2', 'mako')}}\nfrom pylons.templating import render_{{template_engine}} as render\n{{endif}}\n\nclass BaseController(WSGIController):\n\n    def __call__(self, environ, start_response):\n        \"\"\"Invoke the Controller\"\"\"\n        # WSGIController.__call__ dispatches to the Controller method\n        # the request is routed to. This routing information is\n        # available in environ['pylons.routes_dict']\n        return WSGIController.__call__(self, environ, start_response)\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/helpers.py_tmpl",
    "content": "\"\"\"Helper functions\n\nConsists of functions to typically be used within templates, but also\navailable to Controllers. This module is available to templates as 'h'.\n\"\"\"\n# Import helpers as desired, or define your own, ie:\n#from webhelpers.html.tags import checkbox, password\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/public/index.html_tmpl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n    \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n    <head>\n        <title>Welcome to Pylons!</title>\n        <style type=\"text/css\">\n            body {\n                font-family: arial, helvetica, sans-serif;\n                background-color: #ffc900;\n                background-image: url(bg.png);\n                background-repeat: repeat-x;\n                width:100%;\n                height:100%;\n                margin:0;\n                max-height: 100%;\n                padding:0;\n                border:none;\n                line-height:1.4;\n            }\n            #container {\n                color:white;\n                background-color:#111;\n                position: absolute;\n                left: 50%;\n                width: 500px;\n                margin-left: -300px;\n                padding:50px;\n                height:100%;\n            }\n            #footer {\n                margin: 120px 0 0 0;\n                padding: 3px;\n                text-align:center;\n                font-size:small;\n                background-color:#222;\n                letter-spacing: 1px;\n            }\n            h1 {\n                text-align:center;\n                font-size:xx-large;\n                font-weight:normal;\n                margin: 0 0 20px 0;\n                border:none;\n                padding:0;\n                letter-spacing: 5px;\n            }\n            h2 {\n                font-size:xx-large;\n                font-weight:normal;\n                margin: 0 0 20px 0;\n                border:none;\n                padding:0;\n            }\n            hr {\n                margin-bottom:30px;\n                border: 1px solid #222;\n                background-color: #222;\n                padding: 2px;\n            }\n            #logo {\n                background-image: url(signum8b_spk.png);\n                background-repeat: no-repeat;\n                height: 0;\n                overflow: hidden;\n                padding-top: 99px;\n                width: 239px;\n            }\n            #left {\n                float:left;\n                width:250px;\n                margin:0 50px 0 0;\n                border:none;\n                padding:0 0 0 10px;\n            }\n            #right {\n                margin:0 0 0 330px;\n                border:none;\n                padding:0;\n            }\n            ul {\n                list-style:none;\n                margin:0;\n                border:none;\n                padding:0;\n            }\n            a:visited {\n                color:white;\n                text-decoration:none;\n            }\n            a:link {\n                color:white;\n                text-decoration:none;\n            }</style>\n    </head>\n    <body>\n        <div id=\"container\">\n            <h1>Welcome to <img src=\"pylons-logo.gif\" alt=\"Logo displaying the word Pylons\"\n                    style=\"vertical-align:-15px; width: 250px;\"/>\n            </h1>\n            <hr/>\n            <div id=\"left\">\n                <h2>Let's begin!</h2>\n                <p>If you haven't used Pylons before, start with the <a href=\"http://pylonshq.com/docs/en/1.0/gettingstarted/\"\n                        style=\"text-decoration:underline;\">beginners' tutorial</a>.</p>\n            </div>\n            <div id=\"right\">\n                <h2>Help</h2>\n                <ul>\n                    <li>\n                        <a href=\"http://pylonshq.com/docs/en/1.0/\">Official documentation</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonsfaq/Home\">FAQ</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/dashboard.action\">Wiki</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonscommunity/Home#Home-JointheMailingLists\">Mailing list</a>\n                    </li>\n                    <li>\n                        <a href=\"http://wiki.pylonshq.com/display/pylonscommunity/Home#Home-IRC\">IRC</a>\n                    </li>\n                    <li>\n                        <a href=\"http://pylonshq.com/project/pylonshq/roadmap\">Bug tracker</a>\n                    </li>\n                </ul>\n            </div>\n            <div id=\"footer\">\n                <a href=\"http://www.pylonshq.com\" style=\"color: #ccc; text-decoration:none;\"\n                    >www.pylonshq.com</a>\n            </div>\n        </div>\n    </body>\n</html>\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/routing.py_tmpl",
    "content": "\"\"\"Routes configuration\n\nThe more specific and detailed routes should be defined first so they\nmay take precedent over the more generic routes. For more information\nrefer to the routes manual at http://routes.groovie.org/docs/\n\"\"\"\nfrom routes import Mapper\n\ndef make_map(config):\n    \"\"\"Create, configure and return the routes Mapper\"\"\"\n    map = Mapper(directory=config['pylons.paths']['controllers'],\n                 always_scan=config['debug'])\n    map.minimization = False\n    map.explicit = False\n\n    # The ErrorController route (handles 404/500 error pages); it should\n    # likely stay at the top, ensuring it can always be resolved\n    map.connect('/error/{action}', controller='error')\n    map.connect('/error/{action}/{id}', controller='error')\n\n    # CUSTOM ROUTES HERE\n\n    map.connect('/{controller}/{action}')\n    map.connect('/{controller}/{action}/{id}')\n\n    return map\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/templates/.distutils_placeholder",
    "content": ""
  },
  {
    "path": "pylons/templates/minimal_project/+package+/templates/__init__.py_tmpl",
    "content": "{{if template_engine not in ['genshi', 'kid']}}\n{{skip_template()}}\n{{endif}}\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/tests/__init__.py_tmpl",
    "content": "\"\"\"Pylons application test package\n\nThis package assumes the Pylons environment is already loaded, such as\nwhen this script is imported from the `nosetests --with-pylons=test.ini`\ncommand.\n\nThis module initializes the application via ``websetup`` (`paster\nsetup-app`) and provides the base testing objects.\n\"\"\"\nfrom unittest import TestCase\n\nfrom paste.deploy import loadapp\nfrom paste.script.appinstall import SetupCommand\nfrom pylons import url\nfrom routes.util import URLGenerator\nfrom webtest import TestApp\n\nimport pylons.test\n\n__all__ = ['environ', 'url', 'TestController']\n\n# Invoke websetup with the current config file\nSetupCommand('setup-app').run([pylons.test.pylonsapp.config['__file__']])\n\nenviron = {}\n\nclass TestController(TestCase):\n\n    def __init__(self, *args, **kwargs):\n        wsgiapp = pylons.test.pylonsapp\n        config = wsgiapp.config\n        self.app = TestApp(wsgiapp)\n        url._push_object(URLGenerator(config['routes.map'], environ))\n        TestCase.__init__(self, *args, **kwargs)\n"
  },
  {
    "path": "pylons/templates/minimal_project/+package+/wsgiapp.py_tmpl",
    "content": "\"\"\"The {{project}} WSGI application\"\"\"\nimport os\n\nfrom beaker.cache import CacheManager\nfrom beaker.middleware import SessionMiddleware\nfrom beaker.util import parse_cache_config_options\n{{if template_engine == 'mako'}}\nfrom mako.lookup import TemplateLookup\n{{elif template_engine == 'genshi'}}\nfrom genshi.template import TemplateLoader\n{{elif template_engine == 'jinja2'}}\nfrom jinja2 import ChoiceLoader, Environment, FileSystemLoader\n{{endif}}\nfrom paste.cascade import Cascade\nfrom paste.registry import RegistryManager\nfrom paste.urlparser import StaticURLParser\nfrom paste.deploy.converters import asbool\nfrom pylons.configuration import PylonsConfig\n{{if template_engine == 'mako'}}\nfrom pylons.error import handle_mako_error\n{{endif}}\nfrom pylons.middleware import ErrorHandler, StatusCodeRedirect\nfrom pylons.wsgiapp import PylonsApp\nfrom routes.middleware import RoutesMiddleware\n\nimport {{package}}.helpers\nfrom {{package}}.routing import make_map\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"Configure the Pylons environment via the ``pylons.config``\n    object\n    \"\"\"\n    # Pylons paths\n    config = PylonsConfig()\n    root = os.path.dirname(os.path.abspath(__file__))\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, 'public'),\n                 templates=[os.path.join(root, 'templates')])\n\n    # Initialize config with the basic options\n    config.init_app(global_conf, app_conf, package='{{package}}', paths=paths)\n\n    config['routes.map'] = make_map(config)\n    config['pylons.app_globals'] = Globals(config)\n    config['pylons.h'] = {{package}}.helpers\n    {{if template_engine == 'mako'}}\n\n    # Create the Mako TemplateLookup, with the default auto-escaping\n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from markupsafe import escape'])\n    {{elif template_engine == 'genshi'}}\n\n    # Create the Genshi TemplateLoader\n    config['pylons.app_globals'].genshi_loader = TemplateLoader(\n        paths['templates'], auto_reload=True)\n    {{elif template_engine == 'jinja2'}}\n\n    # Create the Jinja2 Environment\n    config['pylons.app_globals'].jinja2_env = Environment(loader=ChoiceLoader(\n            [FileSystemLoader(path) for path in paths['templates']]))\n    # Jinja2's unable to request c's attributes without strict_c\n    config['pylons.strict_c'] = True\n    {{endif}}\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n    \n    return config\n\n\ndef make_app(global_conf, full_stack=True, static_files=True, **app_conf):\n    \"\"\"Create a Pylons WSGI application and return it\n\n    ``global_conf``\n        The inherited configuration for this application. Normally from\n        the [DEFAULT] section of the Paste ini file.\n\n    ``full_stack``\n        Whether or not this application provides a full WSGI stack (by\n        default, meaning it handles its own exceptions and errors).\n        Disable full_stack when this application is \"managed\" by another\n        WSGI middleware.\n\n    ``static_files``\n        Whether this application serves its own static files; disable\n        when another web server is responsible for serving them.\n\n    ``app_conf``\n        The application's local configuration. Normally specified in the\n        [app:<name>] section of the Paste ini file (where <name>\n        defaults to main).\n    \"\"\"\n    # Configure the Pylons environment\n    config = load_environment(global_conf, app_conf)\n\n    # The Pylons WSGI app\n    app = PylonsApp(config=config)\n\n    # Routing/Session/Cache Middleware\n    app = RoutesMiddleware(app, config['routes.map'], singleton=False)\n    app = SessionMiddleware(app, config)\n\n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n\n    if asbool(full_stack):\n        # Handle Python exceptions\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n        # Display error documents for 401, 403, 404 status codes (and\n        # 500 when debug is disabled)\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [401, 403, 404, 500])\n\n    # Establish the Registry for this application\n    app = RegistryManager(app)\n\n    if asbool(static_files):\n        # Serve static files\n        static_app = StaticURLParser(config['pylons.paths']['static_files'])\n        app = Cascade([static_app, app])\n    \n    app.config = config\n    return app\n\n\nclass Globals(object):\n\n    \"\"\"Globals acts as a container for objects available throughout the\n    life of the application\n\n    \"\"\"\n\n    def __init__(self, config):\n        \"\"\"One instance of Globals is created during application\n        initialization and is available during requests via the\n        'app_globals' variable\n\n        \"\"\"\n        self.cache = CacheManager(**parse_cache_config_options(config))\n"
  },
  {
    "path": "pylons/templates/minimal_project/MANIFEST.in_tmpl",
    "content": "include {{package}}/config/deployment.ini_tmpl\nrecursive-include {{package}}/public *\nrecursive-include {{package}}/templates *\n"
  },
  {
    "path": "pylons/templates/minimal_project/README.txt_tmpl",
    "content": "This file is for you to describe the {{project}} application. Typically\nyou would include information such as the information below:\n\nInstallation and Setup\n======================\n\nInstall ``{{project}}`` using easy_install::\n\n    easy_install {{project}}\n\nMake a config file as follows::\n\n    paster make-config {{project}} config.ini\n\nTweak the config file as appropriate and then setup the application::\n\n    paster setup-app config.ini\n\nThen you are ready to go.\n"
  },
  {
    "path": "pylons/templates/minimal_project/development.ini_tmpl",
    "content": "#\n# {{project}} - Pylons development environment configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\n# Uncomment and replace with the address which should receive any error reports\n#email_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = egg:{{project}}\nfull_stack = true\nstatic_files = true\ncache_dir = %(here)s/data\nbeaker.session.key = {{package}}\nbeaker.session.secret = somesecret\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for the Cache data, or the Session saves, un-comment the desired settings\n# here:\n#beaker.cache.data_dir = %(here)s/data/cache\n#beaker.session.data_dir = %(here)s/data/sessions\n\n# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*\n# Debug mode will enable the interactive debugging tool, allowing ANYONE to\n# execute malicious code after an exception is raised.\n#set debug = false\n\n\n# Logging configuration\n[loggers]\nkeys = root, routes, {{package_logger}}\n\n[handlers]\nkeys = console\n\n[formatters]\nkeys = generic\n\n[logger_root]\nlevel = INFO\nhandlers = console\n\n[logger_routes]\nlevel = INFO\nhandlers =\nqualname = routes.middleware\n# \"level = DEBUG\" logs the route matched and routing variables.\n\n[logger_{{package_logger}}]\nlevel = DEBUG\nhandlers =\nqualname = {{package}}\n\n{{if sqlalchemy}}\n\n[logger_sqlalchemy]\nlevel = INFO\nhandlers =\nqualname = sqlalchemy.engine\n# \"level = INFO\" logs SQL queries.\n# \"level = DEBUG\" logs SQL queries and results.\n# \"level = WARN\" logs neither.  (Recommended for production systems.)\n{{endif}}\n\n[handler_console]\nclass = StreamHandler\nargs = (sys.stderr,)\nlevel = NOTSET\nformatter = generic\n\n[formatter_generic]\nformat = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s\ndatefmt = %H:%M:%S\n"
  },
  {
    "path": "pylons/templates/minimal_project/ez_setup.py",
    "content": "#!python\n\"\"\"Bootstrap setuptools installation\n\nIf you want to use setuptools in your package's setup.py, just include this\nfile in the same directory with it, and add this to the top of your setup.py::\n\n    from ez_setup import use_setuptools\n    use_setuptools()\n\nIf you want to require a specific version of setuptools, set a download\nmirror, or use an alternate download directory, you can do so by supplying\nthe appropriate options to ``use_setuptools()``.\n\nThis file can also be run as a script to install or upgrade setuptools.\n\"\"\"\nimport sys\nDEFAULT_VERSION = \"0.6c9\"\nDEFAULT_URL     = \"http://pypi.python.org/packages/%s/s/setuptools/\" % sys.version[:3]\n\nmd5_data = {\n    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',\n    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',\n    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',\n    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',\n    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',\n    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',\n    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',\n    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',\n    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',\n    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',\n    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',\n    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',\n    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',\n    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',\n    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',\n    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',\n    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',\n    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',\n    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',\n    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',\n    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',\n    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',\n    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',\n    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',\n    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',\n    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',\n    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',\n    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',\n    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',\n    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',\n    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',\n    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',\n    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',\n    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',\n}\n\nimport sys, os\ntry: from hashlib import md5\nexcept ImportError: from md5 import md5\n\ndef _validate_md5(egg_name, data):\n    if egg_name in md5_data:\n        digest = md5(data).hexdigest()\n        if digest != md5_data[egg_name]:\n            print >>sys.stderr, (\n                \"md5 validation of %s failed!  (Possible download problem?)\"\n                % egg_name\n            )\n            sys.exit(2)\n    return data\n\ndef use_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    download_delay=15\n):\n    \"\"\"Automatically find/download setuptools and make it available on sys.path\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end with\n    a '/').  `to_dir` is the directory where setuptools will be downloaded, if\n    it is not already available.  If `download_delay` is specified, it should\n    be the number of seconds that will be paused before initiating a download,\n    should one be required.  If an older version of setuptools is installed,\n    this routine will print a message to ``sys.stderr`` and raise SystemExit in\n    an attempt to abort the calling script.\n    \"\"\"\n    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules\n    def do_download():\n        egg = download_setuptools(version, download_base, to_dir, download_delay)\n        sys.path.insert(0, egg)\n        import setuptools; setuptools.bootstrap_install_from = egg\n    try:\n        import pkg_resources\n    except ImportError:\n        return do_download()       \n    try:\n        pkg_resources.require(\"setuptools>=\"+version); return\n    except pkg_resources.VersionConflict, e:\n        if was_imported:\n            print >>sys.stderr, (\n            \"The required version of setuptools (>=%s) is not available, and\\n\"\n            \"can't be installed while this script is running. Please install\\n\"\n            \" a more recent version first, using 'easy_install -U setuptools'.\"\n            \"\\n\\n(Currently using %r)\"\n            ) % (version, e.args[0])\n            sys.exit(2)\n        else:\n            del pkg_resources, sys.modules['pkg_resources']    # reload ok\n            return do_download()\n    except pkg_resources.DistributionNotFound:\n        return do_download()\n\ndef download_setuptools(\n    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,\n    delay = 15\n):\n    \"\"\"Download setuptools from a specified location and return its filename\n\n    `version` should be a valid setuptools version number that is available\n    as an egg for download under the `download_base` URL (which should end\n    with a '/'). `to_dir` is the directory where the egg will be downloaded.\n    `delay` is the number of seconds to pause before an actual download attempt.\n    \"\"\"\n    import urllib2, shutil\n    egg_name = \"setuptools-%s-py%s.egg\" % (version,sys.version[:3])\n    url = download_base + egg_name\n    saveto = os.path.join(to_dir, egg_name)\n    src = dst = None\n    if not os.path.exists(saveto):  # Avoid repeated downloads\n        try:\n            from distutils import log\n            if delay:\n                log.warn(\"\"\"\n---------------------------------------------------------------------------\nThis script requires setuptools version %s to run (even to display\nhelp).  I will attempt to download it for you (from\n%s), but\nyou may need to enable firewall access for this script first.\nI will start the download in %d seconds.\n\n(Note: if this machine does not have network access, please obtain the file\n\n   %s\n\nand place it in this directory before rerunning this script.)\n---------------------------------------------------------------------------\"\"\",\n                    version, download_base, delay, url\n                ); from time import sleep; sleep(delay)\n            log.warn(\"Downloading %s\", url)\n            src = urllib2.urlopen(url)\n            # Read/write all in one block, so we don't create a corrupt file\n            # if the download is interrupted.\n            data = _validate_md5(egg_name, src.read())\n            dst = open(saveto,\"wb\"); dst.write(data)\n        finally:\n            if src: src.close()\n            if dst: dst.close()\n    return os.path.realpath(saveto)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndef main(argv, version=DEFAULT_VERSION):\n    \"\"\"Install or upgrade setuptools and EasyInstall\"\"\"\n    try:\n        import setuptools\n    except ImportError:\n        egg = None\n        try:\n            egg = download_setuptools(version, delay=0)\n            sys.path.insert(0,egg)\n            from setuptools.command.easy_install import main\n            return main(list(argv)+[egg])   # we're done here\n        finally:\n            if egg and os.path.exists(egg):\n                os.unlink(egg)\n    else:\n        if setuptools.__version__ == '0.0.1':\n            print >>sys.stderr, (\n            \"You have an obsolete version of setuptools installed.  Please\\n\"\n            \"remove it from your system entirely before rerunning this script.\"\n            )\n            sys.exit(2)\n\n    req = \"setuptools>=\"+version\n    import pkg_resources\n    try:\n        pkg_resources.require(req)\n    except pkg_resources.VersionConflict:\n        try:\n            from setuptools.command.easy_install import main\n        except ImportError:\n            from easy_install import main\n        main(list(argv)+[download_setuptools(delay=0)])\n        sys.exit(0) # try to force an exit\n    else:\n        if argv:\n            from setuptools.command.easy_install import main\n            main(argv)\n        else:\n            print \"Setuptools version\",version,\"or greater has been installed.\"\n            print '(Run \"ez_setup.py -U setuptools\" to reinstall or upgrade.)'\n\ndef update_md5(filenames):\n    \"\"\"Update our built-in md5 registry\"\"\"\n\n    import re\n\n    for name in filenames:\n        base = os.path.basename(name)\n        f = open(name,'rb')\n        md5_data[base] = md5(f.read()).hexdigest()\n        f.close()\n\n    data = [\"    %r: %r,\\n\" % it for it in md5_data.items()]\n    data.sort()\n    repl = \"\".join(data)\n\n    import inspect\n    srcfile = inspect.getsourcefile(sys.modules[__name__])\n    f = open(srcfile, 'rb'); src = f.read(); f.close()\n\n    match = re.search(\"\\nmd5_data = {\\n([^}]+)}\", src)\n    if not match:\n        print >>sys.stderr, \"Internal error!\"\n        sys.exit(2)\n\n    src = src[:match.start(1)] + repl + src[match.end(1):]\n    f = open(srcfile,'w')\n    f.write(src)\n    f.close()\n\n\nif __name__=='__main__':\n    if len(sys.argv)>2 and sys.argv[1]=='--md5update':\n        update_md5(sys.argv[2:])\n    else:\n        main(sys.argv[1:])\n\n\n\n\n\n\n"
  },
  {
    "path": "pylons/templates/minimal_project/setup.cfg_tmpl",
    "content": "[egg_info]\ntag_build = dev\ntag_svn_revision = true\n\n[easy_install]\nfind_links = http://www.pylonshq.com/download/\n\n[nosetests]\nwith-pylons = test.ini\n"
  },
  {
    "path": "pylons/templates/minimal_project/setup.py_tmpl",
    "content": "try:\n    from setuptools import setup, find_packages\nexcept ImportError:\n    from ez_setup import use_setuptools\n    use_setuptools()\n    from setuptools import setup, find_packages\n\nsetup(\n    name='{{project}}',\n    version='{{version}}',\n    description={{repr(description)}},\n    author={{repr(author)}},\n    author_email={{repr(author_email)}},\n    url={{repr(url)}},\n    install_requires=[\n        \"Pylons>=1.0.1rc1\",\n{{if sqlalchemy}}\n        \"SQLAlchemy>=0.5\",\n{{endif}}\n{{if template_engine == 'genshi'}}\n        \"Genshi>=0.4\",\n{{elif template_engine == 'jinja2'}}\n        \"Jinja2\",\n{{endif}}\n    ],\n    setup_requires=[\"PasteScript>=1.6.3\"],\n    packages=find_packages(exclude=['ez_setup']),\n    include_package_data=True,\n    test_suite='nose.collector',\n    package_data={'{{package}}': ['i18n/*/LC_MESSAGES/*.mo']},\n    #message_extractors={'{{package}}': [\n    #        ('**.py', 'python', None),\n    #        {{babel_templates_extractor}}('public/**', 'ignore', None)]},\n    zip_safe={{zip_safe}},\n    paster_plugins={{egg_plugins}},\n    entry_points=\"\"\"\n    [paste.app_factory]\n    main = {{package}}.wsgiapp:make_app\n\n    [paste.app_install]\n    main = pylons.util:PylonsInstaller\n    \"\"\",\n)\n"
  },
  {
    "path": "pylons/templates/minimal_project/test.ini_tmpl",
    "content": "#\n# {{project}} - Pylons testing environment configuration\n#\n# The %(here)s variable will be replaced with the parent directory of this file\n#\n[DEFAULT]\ndebug = true\n# Uncomment and replace with the address which should receive any error reports\n#email_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@localhost\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = config:development.ini\n\n# Add additional test specific configuration options as necessary.\n"
  },
  {
    "path": "pylons/templates/restcontroller.py_tmpl",
    "content": "import logging\n\nfrom pylons import request, response, session, tmpl_context as c, url\nfrom pylons.controllers.util import abort, redirect\n\n{{importstatement}}\n\nlog = logging.getLogger(__name__)\n\nclass {{classname}}Controller(BaseController):\n    \"\"\"REST Controller styled on the Atom Publishing Protocol\"\"\"\n    # To properly map this controller, ensure your config/routing.py\n    # file has a resource setup:\n    #     {{resource_command}}\n    def index(self, format='html'):\n        \"\"\"GET /{{path}}{{pluralname}}: All items in the collection\"\"\"\n        # url('{{nameprefix}}{{pluralname}}')\n\n    def create(self):\n        \"\"\"POST /{{path}}{{pluralname}}: Create a new item\"\"\"\n        # url('{{nameprefix}}{{pluralname}}')\n\n    def new(self, format='html'):\n        \"\"\"GET /{{path}}{{pluralname}}/new: Form to create a new item\"\"\"\n        # url('{{nameprefix}}new_{{singularname}}')\n\n    def update(self, id):\n        \"\"\"PUT /{{path}}{{pluralname}}/id: Update an existing item\"\"\"\n        # Forms posted to this method should contain a hidden field:\n        #    <input type=\"hidden\" name=\"_method\" value=\"PUT\" />\n        # Or using helpers:\n        #    h.form(url('{{nameprefix}}{{singularname}}', id=ID),\n        #           method='put')\n        # url('{{nameprefix}}{{singularname}}', id=ID)\n\n    def delete(self, id):\n        \"\"\"DELETE /{{path}}{{pluralname}}/id: Delete an existing item\"\"\"\n        # Forms posted to this method should contain a hidden field:\n        #    <input type=\"hidden\" name=\"_method\" value=\"DELETE\" />\n        # Or using helpers:\n        #    h.form(url('{{nameprefix}}{{singularname}}', id=ID),\n        #           method='delete')\n        # url('{{nameprefix}}{{singularname}}', id=ID)\n\n    def show(self, id, format='html'):\n        \"\"\"GET /{{path}}{{pluralname}}/id: Show a specific item\"\"\"\n        # url('{{nameprefix}}{{singularname}}', id=ID)\n\n    def edit(self, id, format='html'):\n        \"\"\"GET /{{path}}{{pluralname}}/id/edit: Form to edit an existing item\"\"\"\n        # url('{{nameprefix}}edit_{{singularname}}', id=ID)\n"
  },
  {
    "path": "pylons/templates/test_controller.py_tmpl",
    "content": "from {{base_package}}.tests import *\n\nclass Test{{name}}Controller(TestController):\n\n    def test_index(self):\n        response = self.app.get(url(controller='{{fname}}', action='index'))\n        # Test response...\n"
  },
  {
    "path": "pylons/templates/test_restcontroller.py_tmpl",
    "content": "from {{base_package}}.tests import *\n\nclass Test{{name}}Controller(TestController):\n\n    def test_index(self):\n        response = self.app.get(url('{{nameprefix}}{{pluralname}}'))\n        # Test response...\n\n    def test_index_as_xml(self):\n        response = self.app.get(url('formatted_{{nameprefix}}{{pluralname}}', format='xml'))\n\n    def test_create(self):\n        response = self.app.post(url('{{nameprefix}}{{pluralname}}'))\n\n    def test_new(self):\n        response = self.app.get(url('{{nameprefix}}new_{{singularname}}'))\n\n    def test_new_as_xml(self):\n        response = self.app.get(url('formatted_{{nameprefix}}new_{{singularname}}', format='xml'))\n\n    def test_update(self):\n        response = self.app.put(url('{{nameprefix}}{{singularname}}', id=1))\n\n    def test_update_browser_fakeout(self):\n        response = self.app.post(url('{{nameprefix}}{{singularname}}', id=1), params=dict(_method='put'))\n\n    def test_delete(self):\n        response = self.app.delete(url('{{nameprefix}}{{singularname}}', id=1))\n\n    def test_delete_browser_fakeout(self):\n        response = self.app.post(url('{{nameprefix}}{{singularname}}', id=1), params=dict(_method='delete'))\n\n    def test_show(self):\n        response = self.app.get(url('{{nameprefix}}{{singularname}}', id=1))\n\n    def test_show_as_xml(self):\n        response = self.app.get(url('formatted_{{nameprefix}}{{singularname}}', id=1, format='xml'))\n\n    def test_edit(self):\n        response = self.app.get(url('{{nameprefix}}edit_{{singularname}}', id=1))\n\n    def test_edit_as_xml(self):\n        response = self.app.get(url('formatted_{{nameprefix}}edit_{{singularname}}', id=1, format='xml'))\n"
  },
  {
    "path": "pylons/templating.py",
    "content": "\"\"\"Render functions and helpers\n\nRender functions and helpers\n============================\n\n:mod:`pylons.templating` includes several basic render functions,\n:func:`render_mako`, :func:`render_genshi` and :func:`render_jinja2`\nthat render templates from the file-system with the assumption that\nvariables intended for the will be attached to :data:`tmpl_context`\n(hereafter referred to by its short name of :data:`c` which it is\ncommonly imported as).\n\nThe default render functions work with the template language loader\nobject that is setup on the :data:`app_globals` object in the project's\n:file:`config/environment.py`.\n\nUsage\n-----\n\nGenerally, one of the render functions will be imported in the\ncontroller. Variables intended for the template are attached to the\n:data:`c` object. The render functions return unicode (they actually\nreturn :class:`~webhelpers.html.literal` objects, a subclass of\nunicode).\n\n.. admonition :: Tip\n\n    :data:`tmpl_context` (template context) is abbreviated to :data:`c`\n    instead of its full name since it will likely be used extensively\n    and it's much faster to use :data:`c`. Of course, for users that\n    can't tolerate one-letter variables, feel free to not import\n    :data:`tmpl_context` as :data:`c` since both names are available in\n    templates as well.\n\nExample of rendering a template with some variables::\n\n    from pylons import tmpl_context as c\n    from pylons.templating import render_mako as render\n\n    from sampleproject.lib.base import BaseController\n\n    class SampleController(BaseController):\n\n        def index(self):\n            c.first_name = \"Joe\"\n            c.last_name = \"Smith\"\n            return render('/some/template.mako')\n\nAnd the accompanying Mako template:\n\n.. code-block:: mako\n\n    Hello ${c.first name}, I see your lastname is ${c.last_name}!\n\nYour controller will have additional default imports for commonly used\nfunctions.\n\nTemplate Globals\n----------------\n\nTemplates rendered in Pylons should include the default Pylons globals\nas the :func:`render_mako`, :func:`render_genshi` and\n:func:`render_jinja2` functions. The full list of Pylons globals that\nare included in the template's namespace are:\n\n- :term:`c` -- Template context object\n- :term:`tmpl_context` -- Template context object\n- :data:`config` -- Pylons :class:`~pylons.configuration.PylonsConfig`\n  object (acts as a dict)\n- :term:`app_globals` -- Project application globals object\n- :term:`h` -- Project helpers module reference\n- :data:`request` -- Pylons :class:`~pylons.controllers.util.Request`\n  object for this request\n- :data:`response` -- Pylons :class:`~pylons.controllers.util.Response`\n  object for this request\n- :class:`session` -- Pylons session object (unless Sessions are\n  removed)\n- :class:`url <routes.util.URLGenerator>` -- Routes url generator\n  object\n- :class:`translator` -- Gettext translator object configured for\n  current locale\n- :func:`ungettext` -- Unicode capable version of gettext's ngettext\n  function (handles plural translations)\n- :func:`_` -- Unicode capable gettext translate function\n- :func:`N_` -- gettext no-op function to mark a string for\n  translation, but doesn't actually translate\n\nConfiguring the template language\n---------------------------------\n\nThe template engine is created in the projects\n``config/environment.py`` and attached to the ``app_globals`` (g)\ninstance. Configuration options can be directly passed into the\ntemplate engine, and are used by the render functions.\n\n.. warning::\n\n    Don't change the variable name on :data:`app_globals` that the\n    template loader is attached to if you want to use the render_*\n    functions that :mod:`pylons.templating` comes with. The render_*\n    functions look for the template loader to render the template.\n\n\"\"\"\nimport logging\n\nfrom webhelpers.html import literal\n\nimport pylons\n\n__all__ = ['render_genshi', 'render_jinja2', 'render_mako']\n\nPYLONS_VARS = ['c', 'app_globals', 'config', 'h', 'render', 'request',\n               'session', 'translator', 'ungettext', '_', 'N_']\n\nlog = logging.getLogger(__name__)\n\n\ndef pylons_globals():\n    \"\"\"Create and return a dictionary of global Pylons variables\n\n    Render functions should call this to retrieve a list of global\n    Pylons variables that should be included in the global template\n    namespace if possible.\n\n    Pylons variables that are returned in the dictionary:\n        ``c``, ``h``, ``_``, ``N_``, config, request, response,\n        translator, ungettext, ``url``\n\n    If SessionMiddleware is being used, ``session`` will also be\n    available in the template namespace.\n\n    \"\"\"\n    conf = pylons.config._current_obj()\n    c = pylons.tmpl_context._current_obj()\n    app_globals = conf.get('pylons.app_globals')\n    pylons_vars = dict(\n        c=c,\n        tmpl_context=c,\n        config=conf,\n        app_globals=app_globals,\n        h=conf.get('pylons.h'),\n        request=pylons.request._current_obj(),\n        response=pylons.response._current_obj(),\n        url=pylons.url._current_obj(),\n        translator=pylons.translator._current_obj(),\n        ungettext=pylons.i18n.ungettext,\n        _=pylons.i18n._,\n        N_=pylons.i18n.N_\n    )\n\n    # If the session was overriden to be None, don't populate the session\n    # var\n    econf = pylons.config['pylons.environ_config']\n    if 'beaker.session' in pylons.request.environ or \\\n        ('session' in econf and econf['session'] in pylons.request.environ):\n        pylons_vars['session'] = pylons.session._current_obj()\n    log.debug(\"Created render namespace with pylons vars: %s\", pylons_vars)\n    return pylons_vars\n\n\ndef cached_template(template_name, render_func, ns_options=(),\n                    cache_key=None, cache_type=None, cache_expire=None,\n                    **kwargs):\n    \"\"\"Cache and render a template\n\n    Cache a template to the namespace ``template_name``, along with a\n    specific key if provided.\n\n    Basic Options\n\n    ``template_name``\n        Name of the template, which is used as the template namespace.\n    ``render_func``\n        Function used to generate the template should it no longer be\n        valid or doesn't exist in the cache.\n    ``ns_options``\n        Tuple of strings, that should correspond to keys likely to be\n        in the ``kwargs`` that should be used to construct the\n        namespace used for the cache. For example, if the template\n        language supports the 'fragment' option, the namespace should\n        include it so that the cached copy for a template is not the\n        same as the fragment version of it.\n\n    Caching options (uses Beaker caching middleware)\n\n    ``cache_key``\n        Key to cache this copy of the template under.\n    ``cache_type``\n        Valid options are ``dbm``, ``file``, ``memory``, ``database``,\n        or ``memcached``.\n    ``cache_expire``\n        Time in seconds to cache this template with this ``cache_key``\n        for. Or use 'never' to designate that the cache should never\n        expire.\n\n    The minimum key required to trigger caching is\n    ``cache_expire='never'`` which will cache the template forever\n    seconds with no key.\n\n    \"\"\"\n    # If one of them is not None then the user did set something\n    if cache_key is not None or cache_expire is not None or cache_type \\\n        is not None:\n\n        if not cache_type:\n            cache_type = 'dbm'\n        if not cache_key:\n            cache_key = 'default'\n        if cache_expire == 'never':\n            cache_expire = None\n        namespace = template_name\n        for name in ns_options:\n            namespace += str(kwargs.get(name))\n        cache = pylons.cache.get_cache(namespace, type=cache_type)\n        content = cache.get_value(cache_key, createfunc=render_func,\n            expiretime=cache_expire)\n        return content\n    else:\n        return render_func()\n\n\ndef render_mako(template_name, extra_vars=None, cache_key=None,\n                cache_type=None, cache_expire=None):\n    \"\"\"Render a template with Mako\n\n    Accepts the cache options ``cache_key``, ``cache_type``, and\n    ``cache_expire``.\n\n    \"\"\"\n    # Create a render callable for the cache function\n    def render_template():\n        # Pull in extra vars if needed\n        globs = extra_vars or {}\n\n        # Second, get the globals\n        globs.update(pylons_globals())\n\n        # Grab a template reference\n        template = globs['app_globals'].mako_lookup.get_template(template_name)\n\n        return literal(template.render_unicode(**globs))\n\n    return cached_template(template_name, render_template, cache_key=cache_key,\n                           cache_type=cache_type, cache_expire=cache_expire)\n\n\ndef render_mako_def(template_name, def_name, cache_key=None,\n                    cache_type=None, cache_expire=None, **kwargs):\n    \"\"\"Render a def block within a Mako template\n\n    Takes the template name, and the name of the def within it to call.\n    If the def takes arguments, they should be passed in as keyword\n    arguments.\n\n    Example::\n\n        # To call the def 'header' within the 'layout.mako' template\n        # with a title argument\n        render_mako_def('layout.mako', 'header', title='Testing')\n\n    Also accepts the cache options ``cache_key``, ``cache_type``, and\n    ``cache_expire``.\n\n    \"\"\"\n    # Create a render callable for the cache function\n    def render_template():\n        # Pull in extra vars if needed\n        globs = kwargs or {}\n\n        # Second, get the globals\n        globs.update(pylons_globals())\n\n        # Grab a template reference\n        template = globs['app_globals'].mako_lookup.get_template(\n            template_name).get_def(def_name)\n\n        return literal(template.render_unicode(**globs))\n\n    return cached_template(template_name, render_template, cache_key=cache_key,\n                           cache_type=cache_type, cache_expire=cache_expire)\n\n\ndef render_genshi(template_name, extra_vars=None, cache_key=None,\n                  cache_type=None, cache_expire=None, method='xhtml'):\n    \"\"\"Render a template with Genshi\n\n    Accepts the cache options ``cache_key``, ``cache_type``, and\n    ``cache_expire`` in addition to method which are passed to Genshi's\n    render function.\n\n    \"\"\"\n    # Create a render callable for the cache function\n    def render_template():\n        # Pull in extra vars if needed\n        globs = extra_vars or {}\n\n        # Second, get the globals\n        globs.update(pylons_globals())\n\n        # Grab a template reference\n        template = globs['app_globals'].genshi_loader.load(template_name)\n\n        return literal(template.generate(**globs).render(method=method,\n                                                         encoding=None))\n\n    return cached_template(template_name, render_template, cache_key=cache_key,\n                           cache_type=cache_type, cache_expire=cache_expire,\n                           ns_options=('method'), method=method)\n\n\ndef render_jinja2(template_name, extra_vars=None, cache_key=None,\n                 cache_type=None, cache_expire=None):\n    \"\"\"Render a template with Jinja2\n\n    Accepts the cache options ``cache_key``, ``cache_type``, and\n    ``cache_expire``.\n\n    \"\"\"\n    # Create a render callable for the cache function\n    def render_template():\n        # Pull in extra vars if needed\n        globs = extra_vars or {}\n\n        # Second, get the globals\n        globs.update(pylons_globals())\n\n        # Grab a template reference\n        template = \\\n            globs['app_globals'].jinja2_env.get_template(template_name)\n\n        return literal(template.render(**globs))\n\n    return cached_template(template_name, render_template, cache_key=cache_key,\n                           cache_type=cache_type, cache_expire=cache_expire)\n"
  },
  {
    "path": "pylons/test.py",
    "content": "\"\"\"Test related functionality\n\nAdds a Pylons plugin to `nose\n<http://www.somethingaboutorange.com/mrl/projects/nose/>`_ that loads\nthe Pylons app *before* scanning for doc tests.\n\nThis can be configured in the projects :file:`setup.cfg` under a\n``[nosetests]`` block:\n\n.. code-block:: ini\n\n    [nosetests]\n    with-pylons=development.ini\n\nAlternate ini files may be specified if the app should be loaded using\na different configuration.\n\n\"\"\"\nimport os\nimport sys\n\nimport nose.plugins\nimport pkg_resources\nfrom paste.deploy import loadapp\n\nimport pylons\nfrom pylons.i18n.translation import _get_translator\n\npylonsapp = None\n\n\nclass PylonsPlugin(nose.plugins.Plugin):\n    \"\"\"Nose plugin extension\n\n    For use with nose to allow a project to be configured before nose\n    proceeds to scan the project for doc tests and unit tests. This\n    prevents modules from being loaded without a configured Pylons\n    environment.\n\n    \"\"\"\n    enabled = False\n    enableOpt = 'pylons_config'\n    name = 'pylons'\n\n    def options(self, parser, env=os.environ):\n        \"\"\"Add command-line options for this plugin\"\"\"\n        env_opt = 'NOSE_WITH_%s' % self.name.upper()\n        env_opt.replace('-', '_')\n\n        parser.add_option(\"--with-%s\" % self.name,\n                          dest=self.enableOpt, type=\"string\",\n                          default=\"\",\n                          help=\"Setup Pylons environment with the config file\"\n                          \" specified by ATTR [NOSE_ATTR]\")\n\n    def configure(self, options, conf):\n        \"\"\"Configure the plugin\"\"\"\n        self.config_file = None\n        self.conf = conf\n        if hasattr(options, self.enableOpt):\n            self.enabled = bool(getattr(options, self.enableOpt))\n            self.config_file = getattr(options, self.enableOpt)\n\n    def begin(self):\n        \"\"\"Called before any tests are collected or run\n\n        Loads the application, and in turn its configuration.\n\n        \"\"\"\n        global pylonsapp\n        path = os.getcwd()\n        sys.path.insert(0, path)\n        pkg_resources.working_set.add_entry(path)\n        self.app = pylonsapp = loadapp('config:' + self.config_file,\n                                       relative_to=path)\n\n        # Setup the config and app_globals, only works if we can get\n        # to the config object\n        conf = getattr(pylonsapp, 'config')\n        if conf:\n            pylons.config._push_object(conf)\n\n            if 'pylons.app_globals' in conf:\n                pylons.app_globals._push_object(conf['pylons.app_globals'])\n\n        # Initialize a translator for tests that utilize i18n\n        translator = _get_translator(pylons.config.get('lang'))\n        pylons.translator._push_object(translator)\n"
  },
  {
    "path": "pylons/testutil.py",
    "content": "\"\"\"Utility classes for creating workable pylons controllers for unit\ntesting.\n\nThese classes are used solely by Pylons for unit testing controller\nfunctionality.\n\n\"\"\"\nimport gettext\n\nimport pylons\nfrom pylons.configuration import request_defaults, response_defaults\nfrom pylons.controllers.util import Request, Response\nfrom pylons.util import ContextObj, PylonsContext\n\n\nclass ControllerWrap(object):\n    def __init__(self, controller):\n        self.controller = controller\n\n    def __call__(self, environ, start_response):\n        app = self.controller()\n        app.start_response = None\n        return app(environ, start_response)\n\n\nclass SetupCacheGlobal(object):\n    def __init__(self, app, environ, setup_g=True, setup_cache=False,\n                 setup_session=False):\n        if setup_g:\n            g = type('G object', (object,), {})\n            g.message = 'Hello'\n            g.counter = 0\n            g.pylons_config = type('App conf', (object,), {})\n            g.pylons_config.app_conf = dict(cache_enabled='True')\n            self.g = g\n        self.app = app\n        self.environ = environ\n        self.setup_cache = setup_cache\n        self.setup_session = setup_session\n        self.setup_g = setup_g\n\n    def __call__(self, environ, start_response):\n        registry = environ['paste.registry']\n        py_obj = PylonsContext()\n        environ_config = environ.setdefault('pylons.environ_config', {})\n        if self.setup_cache:\n            py_obj.cache = environ['beaker.cache']\n            registry.register(pylons.cache, environ['beaker.cache'])\n            environ_config['cache'] = 'beaker.cache'\n        if self.setup_session:\n            py_obj.session = environ['beaker.session']\n            registry.register(pylons.session, environ['beaker.session'])\n            environ_config['session'] = 'beaker.session'\n        if self.setup_g:\n            py_obj.app_globals = self.g\n            registry.register(pylons.app_globals, self.g)\n        translator = gettext.NullTranslations()\n        py_obj.translator = translator\n        registry.register(pylons.translator, translator)\n\n        # Update the environ\n        req = Request(environ, charset=request_defaults['charset'],\n                      unicode_errors=request_defaults['errors'],\n                      decode_param_names=request_defaults['decode_param_names']\n        )\n        req.language = request_defaults['language']\n\n        response = Response(\n            content_type=response_defaults['content_type'],\n            charset=response_defaults['charset'])\n        response.headers.update(response_defaults['headers'])\n\n        environ.update(self.environ)\n        py_obj.config = pylons.config._current_obj()\n        py_obj.request = req\n        py_obj.response = response\n        py_obj.tmpl_context = ContextObj()\n        environ['pylons.pylons'] = py_obj\n        registry.register(pylons.request, req)\n        registry.register(pylons.response, response)\n        if 'routes.url' in environ:\n            registry.register(pylons.url, environ['routes.url'])\n        return self.app(environ, start_response)\n"
  },
  {
    "path": "pylons/url.py",
    "content": "from repoze.bfg.encode import urlencode\nfrom repoze.bfg.threadlocal import get_current_registry\nfrom repoze.bfg.url import _join_elements\n\nfrom pylons.interfaces import IRoutesMapper\n\n\ndef route_url(route_name, request, *elements, **kw):\n    try:\n        reg = request.registry\n    except AttributeError:\n        reg = get_current_registry()  # b/c\n    mapper = reg.getUtility(IRoutesMapper)\n\n    route = mapper.routes.get(route_name)\n    if route and 'custom_url_generator' in route.__dict__:\n        route_name, request, elements, kw = route.custom_url_generator(\n            route_name, request, *elements, **kw)\n    anchor = ''\n    qs = ''\n    app_url = None\n\n    if '_query' in kw:\n        qs = '?' + urlencode(kw.pop('_query'), doseq=True)\n\n    if '_anchor' in kw:\n        anchor = kw.pop('_anchor')\n        if isinstance(anchor, unicode):\n            anchor = anchor.encode('utf-8')\n        anchor = '#' + anchor\n\n    if '_app_url' in kw:\n        app_url = kw.pop('_app_url')\n\n    path = mapper.generate(route_name, kw)  # raises KeyError if generate fails\n\n    if elements:\n        suffix = _join_elements(elements)\n        if not path.endswith('/'):\n            suffix = '/' + suffix\n    else:\n        suffix = ''\n\n    if app_url is None:\n        # we only defer lookup of application_url until here because\n        # it's somewhat expensive; we won't need to do it if we've\n        # been passed _app_url\n        app_url = request.application_url\n\n    return app_url + path + suffix + qs + anchor\n"
  },
  {
    "path": "pylons/util.py",
    "content": "\"\"\"Paste Template and Pylons utility functions\n\nPylonsTemplate is a Paste Template sub-class that configures the source\ndirectory and default plug-ins for a new Pylons project. The minimal\ntemplate a more minimal template with less additional directories and\nlayout.\n\n\"\"\"\nimport logging\nimport sys\n\nimport pkg_resources\nfrom paste.deploy.converters import asbool\nfrom paste.script.appinstall import Installer\nfrom paste.script.templates import Template, var\nfrom tempita import paste_script_template_renderer\n\nimport pylons\nimport pylons.configuration\nimport pylons.i18n\n\n__all__ = ['AttribSafeContextObj', 'ContextObj', 'PylonsContext',\n           'class_name_from_module_name', 'call_wsgi_application']\n\nlog = logging.getLogger(__name__)\n\n\ndef call_wsgi_application(application, environ, catch_exc_info=False):\n    \"\"\"\n    Call the given WSGI application, returning ``(status_string,\n    headerlist, app_iter)``\n\n    Be sure to call ``app_iter.close()`` if it's there.\n\n    If catch_exc_info is true, then returns ``(status_string,\n    headerlist, app_iter, exc_info)``, where the fourth item may\n    be None, but won't be if there was an exception.  If you don't\n    do this and there was an exception, the exception will be\n    raised directly.\n\n    \"\"\"\n    captured = []\n    output = []\n\n    def start_response(status, headers, exc_info=None):\n        if exc_info is not None and not catch_exc_info:\n            raise exc_info[0], exc_info[1], exc_info[2]\n        captured[:] = [status, headers, exc_info]\n        return output.append\n    app_iter = application(environ, start_response)\n    if not captured or output:\n        try:\n            output.extend(app_iter)\n        finally:\n            if hasattr(app_iter, 'close'):\n                app_iter.close()\n        app_iter = output\n    if catch_exc_info:\n        return (captured[0], captured[1], app_iter, captured[2])\n    else:\n        return (captured[0], captured[1], app_iter)\n\n\ndef class_name_from_module_name(module_name):\n    \"\"\"Takes a module name and returns the name of the class it\n    defines.\n\n    If the module name contains dashes, they are replaced with\n    underscores.\n\n    Example::\n\n        >>> class_name_from_module_name('with-dashes')\n        'WithDashes'\n        >>> class_name_from_module_name('with_underscores')\n        'WithUnderscores'\n        >>> class_name_from_module_name('oneword')\n        'Oneword'\n\n    \"\"\"\n    words = module_name.replace('-', '_').split('_')\n    return ''.join(w.title() for w in words)\n\n\nclass PylonsContext(object):\n    \"\"\"Pylons context object\n\n    All the Pylons Stacked Object Proxies are also stored here, for use\n    in generators and async based operation where the globals can't be\n    used.\n\n    This object is attached in\n    :class:`~pylons.controllers.core.WSGIController` instances as\n    :attr:`~WSGIController._py_object`. For example::\n\n        class MyController(WSGIController):\n            def index(self):\n                pyobj = self._py_object\n                return \"Environ is %s\" % pyobj.request.environ\n\n    \"\"\"\n    pass\n\n\nclass ContextObj(object):\n    \"\"\"The :term:`tmpl_context` object, with strict attribute access\n    (raises an Exception when the attribute does not exist)\"\"\"\n    def __repr__(self):\n        attrs = sorted((name, value)\n                       for name, value in self.__dict__.iteritems()\n                       if not name.startswith('_'))\n        parts = []\n        for name, value in attrs:\n            value_repr = repr(value)\n            if len(value_repr) > 70:\n                value_repr = value_repr[:60] + '...' + value_repr[-5:]\n            parts.append(' %s=%s' % (name, value_repr))\n        return '<%s.%s at %s%s>' % (\n            self.__class__.__module__,\n            self.__class__.__name__,\n            hex(id(self)),\n            ','.join(parts))\n\n\nclass AttribSafeContextObj(ContextObj):\n    \"\"\"The :term:`tmpl_context` object, with lax attribute access (\n    returns '' when the attribute does not exist)\"\"\"\n    def __getattr__(self, name):\n        try:\n            return object.__getattribute__(self, name)\n        except AttributeError:\n            log.debug(\"No attribute called %s found on c object, returning \"\n                      \"empty string\", name)\n            return ''\n\n\nclass PylonsTemplate(Template):\n    _template_dir = ('pylons', 'templates/default_project')\n    template_renderer = staticmethod(paste_script_template_renderer)\n    summary = 'Pylons application template'\n    egg_plugins = ['PasteScript', 'Pylons']\n    vars = [\n        var('template_engine', 'mako/genshi/jinja2/etc: Template language',\n            default='mako'),\n        var('sqlalchemy', 'True/False: Include SQLAlchemy configuration',\n            default=False),\n    ]\n    ensure_names = ['description', 'author', 'author_email', 'url']\n\n    def pre(self, command, output_dir, vars):\n        \"\"\"Called before template is applied.\"\"\"\n        package_logger = vars['package']\n        if package_logger == 'root':\n            # Rename the app logger in the rare case a project is named 'root'\n            package_logger = 'app'\n        vars['package_logger'] = package_logger\n        vars['template_engine'] = 'mako'\n\n        template_engine = 'mako'\n\n        if template_engine == 'mako':\n            # Support a Babel extractor default for Mako\n            vars['babel_templates_extractor'] = \\\n                (\"('templates/**.mako', 'mako', {'input_encoding': 'utf-8'})\"\n                 \",\\n%s#%s\" % (' ' * 4, ' ' * 8))\n        else:\n            vars['babel_templates_extractor'] = ''\n\n        # Ensure these exist in the namespace\n        for name in self.ensure_names:\n            vars.setdefault(name, '')\n\n        vars['version'] = vars.get('version', '0.1')\n        vars['zip_safe'] = asbool(vars.get('zip_safe', 'false'))\n        vars['sqlalchemy'] = asbool(vars.get('sqlalchemy', 'false'))\n\n\nclass MinimalPylonsTemplate(PylonsTemplate):\n    _template_dir = ('pylons', 'templates/minimal_project')\n    summary = 'Pylons minimal application template'\n    vars = [\n        var('template_engine', 'mako/genshi/jinja2/etc: Template language',\n            default='mako'),\n    ]\n\n\nclass LegacyPylonsTemplate(PylonsTemplate):\n    _template_dir = ('pylons', 'templates/legacy_project')\n    summary = 'Pylons legacy application template'\n    vars = [\n        var('template_engine', 'mako/genshi/jinja2/etc: Template language',\n            default='mako'),\n    ]\n\n\nclass NewPylonsTemplate(PylonsTemplate):\n    _template_dir = ('pylons', 'templates/new_project')\n    summary = 'Pylons \"newstyle\" application template'\n    vars = []\n\n\nclass NewMinimalPylonsTemplate(PylonsTemplate):\n    _template_dir = ('pylons', 'templates/newminimal_project')\n    summary = 'Pylons \"newstyle\" minimal application template'\n    vars = []\n\n\nclass NewSQLAlchemyTemplate(PylonsTemplate):\n    _template_dir = ('pylons', 'templates/newsqla_project')\n    summary = 'Pylons \"newstyle\" SQLAlchemy template'\n    vars = []\n\n\nclass PylonsInstaller(Installer):\n    use_cheetah = False\n    config_file = 'config/deployment.ini_tmpl'\n\n    def config_content(self, command, vars):\n        \"\"\"\n        Called by ``self.write_config``, this returns the text content\n        for the config file, given the provided variables.\n        \"\"\"\n        modules = [line.strip()\n                    for line in self.dist.get_metadata_lines('top_level.txt')\n                    if line.strip() and not line.strip().startswith('#')]\n        if not modules:\n            print >> sys.stderr, 'No modules are listed in top_level.txt'\n            print >> sys.stderr, \\\n                'Try running python setup.py egg_info to regenerate that file'\n        for module in modules:\n            if pkg_resources.resource_exists(module, self.config_file):\n                return self.template_renderer(\n                    pkg_resources.resource_string(module, self.config_file),\n                    vars, filename=self.config_file)\n        # Legacy support for the old location in egg-info\n        return super(PylonsInstaller, self).config_content(command, vars)\n\n\ndef resolve_dotted(name):\n    return pkg_resources.EntryPoint.parse('x=%s' % name).load(False)\n"
  },
  {
    "path": "pylons/wsgiapp.py",
    "content": "\"\"\"WSGI App Creator\n\nThis module is responsible for creating the basic Pylons WSGI\napplication (PylonsApp). It's generally assumed that it will be called\nby Paste, though any WSGI server could create and call the WSGI app as\nwell.\n\n\"\"\"\nimport logging\nimport sys\n\nimport paste.registry\nimport pkg_resources\nfrom webob.exc import HTTPNotFound\n\nimport pylons\nimport pylons.templating\nfrom pylons.controllers.util import Request, Response\nfrom pylons.i18n.translation import _get_translator\nfrom pylons.util import (AttribSafeContextObj, ContextObj, PylonsContext,\n                         class_name_from_module_name)\n\n__all__ = ['PylonsApp']\n\nlog = logging.getLogger(__name__)\n\n\nclass PylonsApp(object):\n    \"\"\"Pylons WSGI Application\n\n    This basic WSGI app is provided should a web developer want to\n    get access to the most basic Pylons web application environment\n    available. By itself, this Pylons web application does little more\n    than dispatch to a controller and setup the context object, the\n    request object, and the globals object.\n\n    Additional functionality like sessions, and caching can be setup by\n    altering the ``environ['pylons.environ_config']`` setting to\n    indicate what key the ``session`` and ``cache`` functionality\n    should come from.\n\n    Resolving the URL and dispatching can be customized by sub-classing\n    or \"monkey-patching\" this class. Subclassing is the preferred\n    approach.\n\n    \"\"\"\n    def __init__(self, config=None, **kwargs):\n        \"\"\"Initialize a base Pylons WSGI application\n\n        The base Pylons WSGI application requires several keywords, the\n        package name, and the globals object. If no helpers object is\n        provided then h will be None.\n\n        \"\"\"\n        self.config = config = config or pylons.config._current_obj()\n        package_name = config['pylons.package']\n        self.helpers = config['pylons.h']\n        self.globals = config.get('pylons.app_globals')\n        self.environ_config = config['pylons.environ_config']\n        self.package_name = package_name\n        self.request_options = config['pylons.request_options']\n        self.response_options = config['pylons.response_options']\n        self.controller_classes = {}\n        self.log_debug = False\n        self.config.setdefault('lang', None)\n\n        # Cache some options for use during requests\n        self._session_key = self.environ_config.get('session', 'beaker.session')\n        self._cache_key = self.environ_config.get('cache', 'beaker.cache')\n\n    def __call__(self, environ, start_response):\n        \"\"\"Setup and handle a web request\n\n        PylonsApp splits its functionality into several methods to\n        make it easier to subclass and customize core functionality.\n\n        The methods are called in the following order:\n\n        1. :meth:`~PylonsApp.setup_app_env`\n        2. :meth:`~PylonsApp.load_test_env` (Only if operating in\n           testing mode)\n        3. :meth:`~PylonsApp.resolve`\n        4. :meth:`~PylonsApp.dispatch`\n\n        The response from :meth:`~PylonsApp.dispatch` is expected to be\n        an iterable (valid :pep:`333` WSGI response), which is then\n        sent back as the response.\n\n        \"\"\"\n        # Cache the logging level for the request\n        log_debug = self.log_debug = logging.DEBUG >= log.getEffectiveLevel()\n        environ['pylons.log_debug'] = log_debug\n\n        self.setup_app_env(environ, start_response)\n        if 'paste.testing_variables' in environ:\n            self.load_test_env(environ)\n            if environ['PATH_INFO'] == '/_test_vars':\n                paste.registry.restorer.save_registry_state(environ)\n                start_response('200 OK', [('Content-type', 'text/plain')])\n                return ['%s' % paste.registry.restorer.get_request_id(environ)]\n\n        controller = self.resolve(environ, start_response)\n        response = self.dispatch(controller, environ, start_response)\n\n        response_obj = callable(response)\n        if 'paste.testing_variables' in environ and response_obj:\n            environ['paste.testing_variables']['response'] = response\n\n        try:\n            if response_obj:\n                return response(environ, start_response)\n            elif response is not None:\n                return response\n\n            raise Exception(\"No content returned by controller (Did you \"\n                            \"remember to 'return' it?) in: %r\" %\n                            controller.__name__)\n        finally:\n            # Help Python collect ram a bit faster by removing the reference\n            # cycle that the pylons object causes\n            if 'pylons.pylons' in environ:\n                del environ['pylons.pylons']\n\n    def register_globals(self, environ):\n        \"\"\"Registers globals in the environment, called from\n        :meth:`~PylonsApp.setup_app_env`\n\n        Override this to control how the Pylons API is setup. Note that\n        a custom render function will need to be used if the\n        ``pylons.app_globals`` global is not available.\n\n        \"\"\"\n        pylons_obj = environ['pylons.pylons']\n\n        registry = environ['paste.registry']\n        registry.register(pylons.response, pylons_obj.response)\n        registry.register(pylons.request, pylons_obj.request)\n\n        registry.register(pylons.app_globals, self.globals)\n        registry.register(pylons.config, self.config)\n        registry.register(pylons.tmpl_context, pylons_obj.tmpl_context)\n        registry.register(pylons.translator, pylons_obj.translator)\n\n        if 'session' in pylons_obj.__dict__:\n            registry.register(pylons.session, pylons_obj.session)\n        if 'cache' in pylons_obj.__dict__:\n            registry.register(pylons.cache, pylons_obj.cache)\n        elif 'cache' in pylons_obj.app_globals.__dict__:\n            registry.register(pylons.cache, pylons_obj.app_globals.cache)\n\n        if 'routes.url' in environ:\n            registry.register(pylons.url, environ['routes.url'])\n\n    def setup_app_env(self, environ, start_response):\n        \"\"\"Setup and register all the Pylons objects with the registry\n\n        After creating all the global objects for use in the request,\n        :meth:`~PylonsApp.register_globals` is called to register them\n        in the environment.\n\n        \"\"\"\n        if self.log_debug:\n            log.debug(\"Setting up Pylons stacked object globals\")\n\n        # Setup the basic pylons global objects\n        req_options = self.request_options\n        req = Request(environ, charset=req_options['charset'],\n                      unicode_errors=req_options['errors'],\n                      decode_param_names=req_options['decode_param_names'])\n        req.language = req_options['language']\n        req.config = self.config\n        req.link, req.route_dict = environ['wsgiorg.routing_args']\n\n        response = Response(\n            content_type=self.response_options['content_type'],\n            charset=self.response_options['charset'])\n        response.headers.update(self.response_options['headers'])\n\n        # Store a copy of the request/response in environ for faster access\n        pylons_obj = PylonsContext()\n        pylons_obj.config = self.config\n        pylons_obj.request = req\n        pylons_obj.response = response\n        pylons_obj.app_globals = self.globals\n        pylons_obj.h = self.helpers\n\n        if 'routes.url' in environ:\n            pylons_obj.url = environ['routes.url']\n\n        environ['pylons.pylons'] = pylons_obj\n\n        environ['pylons.environ_config'] = self.environ_config\n\n        # Setup the translator object\n        lang = self.config['lang']\n        pylons_obj.translator = _get_translator(lang, pylons_config=self.config)\n\n        if self.config['pylons.strict_tmpl_context']:\n            tmpl_context = ContextObj()\n        else:\n            tmpl_context = AttribSafeContextObj()\n        pylons_obj.tmpl_context = req.tmpl_context = tmpl_context\n\n        if self._session_key in environ:\n            pylons_obj.session = req.session = environ[self._session_key]\n        if self._cache_key in environ:\n            pylons_obj.cache = environ[self._cache_key]\n\n        # Load the globals with the registry if around\n        if 'paste.registry' in environ:\n            self.register_globals(environ)\n\n    def resolve(self, environ, start_response):\n        \"\"\"Uses dispatching information found in\n        ``environ['wsgiorg.routing_args']`` to retrieve a controller\n        name and return the controller instance from the appropriate\n        controller module.\n\n        Override this to change how the controller name is found and\n        returned.\n\n        \"\"\"\n        match = environ['wsgiorg.routing_args'][1]\n        environ['pylons.routes_dict'] = match\n        controller = match.get('controller', match.get('responder'))\n        if not controller:\n            return\n\n        if self.log_debug:\n            log.debug(\"Resolved URL to controller: %r\", controller)\n        return self.find_controller(controller)\n\n    def find_controller(self, controller):\n        \"\"\"Locates a controller by attempting to import it then grab\n        the SomeController instance from the imported module.\n\n        Controller name is assumed to be a module in the controllers\n        directory unless it contains a '.' or ':' which is then assumed\n        to be a dotted path to the module and name of the controller\n        object.\n\n        Override this to change how the controller object is found once\n        the URL has been resolved.\n\n        \"\"\"\n        # If this isn't a basestring, its an object, assume that its the\n        # proper instance to begin with\n        if not isinstance(controller, basestring):\n            return controller\n\n        # Check to see if we've cached the class instance for this name\n        if controller in self.controller_classes:\n            return self.controller_classes[controller]\n\n        # Check to see if its a dotted name\n        if '.' in controller or ':' in controller:\n            mycontroller = pkg_resources.EntryPoint.parse(\n                'x=%s' % controller).load(False)\n            self.controller_classes[controller] = mycontroller\n            return mycontroller\n\n        # Pull the controllers class name, import controller\n        full_module_name = self.package_name + '.controllers.' \\\n            + controller.replace('/', '.')\n\n        # Hide the traceback here if the import fails (bad syntax and such)\n        __traceback_hide__ = 'before_and_this'\n\n        __import__(full_module_name)\n        if hasattr(sys.modules[full_module_name], '__controller__'):\n            mycontroller = getattr(sys.modules[full_module_name],\n                sys.modules[full_module_name].__controller__)\n        else:\n            module_name = controller.split('/')[-1]\n            class_name = class_name_from_module_name(module_name) + 'Controller'\n            if self.log_debug:\n                log.debug(\"Found controller, module: '%s', class: '%s'\",\n                          full_module_name, class_name)\n            mycontroller = getattr(sys.modules[full_module_name], class_name)\n        self.controller_classes[controller] = mycontroller\n        return mycontroller\n\n    def dispatch(self, controller, environ, start_response):\n        \"\"\"Dispatches to a controller, will instantiate the controller\n        if necessary.\n\n        Override this to change how the controller dispatch is handled.\n\n        \"\"\"\n        log_debug = self.log_debug\n        if not controller:\n            if log_debug:\n                log.debug(\"No controller found, returning 404 HTTP Not Found\")\n            return HTTPNotFound()(environ, start_response)\n\n        # Is it a responder?\n        if 'responder' in environ['pylons.routes_dict']:\n            return controller(environ['pylons.pylons'].request)\n\n        # Is it a class? Then its a WSGIController\n        if hasattr(controller, '__bases__'):\n            if log_debug:\n                log.debug(\"Controller appears to be a class, instantiating\")\n            controller = controller()\n            controller._pylons_log_debug = log_debug\n\n        # Add a reference to the controller app located\n        environ['pylons.controller'] = controller\n\n        # Controller is assumed to handle a WSGI call\n        if log_debug:\n            log.debug(\"Calling controller class with WSGI interface\")\n        return controller(environ, start_response)\n\n    def load_test_env(self, environ):\n        \"\"\"Sets up our Paste testing environment\"\"\"\n        if self.log_debug:\n            log.debug(\"Setting up paste testing environment variables\")\n        testenv = environ['paste.testing_variables']\n        pylons_obj = environ['pylons.pylons']\n        testenv['req'] = pylons_obj.request\n        testenv['response'] = pylons_obj.response\n        testenv['tmpl_context'] = pylons_obj.tmpl_context\n        testenv['app_globals'] = testenv['g'] = pylons_obj.app_globals\n        testenv['h'] = self.config['pylons.h']\n        testenv['config'] = self.config\n        if hasattr(pylons_obj, 'session'):\n            testenv['session'] = pylons_obj.session\n        if hasattr(pylons_obj, 'cache'):\n            testenv['cache'] = pylons_obj.cache\n        elif hasattr(pylons_obj.app_globals, 'cache'):\n            testenv['cache'] = pylons_obj.app_globals.cache\n"
  },
  {
    "path": "rtd.txt",
    "content": "repoze.sphinx.autointerface\nbabel\n"
  },
  {
    "path": "scripts/gen-go-pylons.py",
    "content": "#!/usr/bin/env python\n\"\"\"Generate go-pylons.py\"\"\"\nimport sys\nimport textwrap\nimport virtualenv\n\nfilename = 'go-pylons.py'\n\nafter_install = \"\"\"\\\nimport os, subprocess\ndef after_install(options, home_dir):\n    etc = join(home_dir, 'etc')\n    ## TODO: this should all come from distutils\n    ## like distutils.sysconfig.get_python_inc()\n    if sys.platform == 'win32':\n        lib_dir = join(home_dir, 'Lib')\n        bin_dir = join(home_dir, 'Scripts')\n    elif is_jython:\n        lib_dir = join(home_dir, 'Lib')\n        bin_dir = join(home_dir, 'bin')\n    else:\n        lib_dir = join(home_dir, 'lib', py_version)\n        bin_dir = join(home_dir, 'bin')\n\n    if not os.path.exists(etc):\n        os.makedirs(etc)\n    subprocess.call([join(bin_dir, 'easy_install'),\n        '-f', 'http://pylonshq.com/download/%s', 'Pylons==%s'])\n\"\"\"\n\n\ndef generate(filename, version):\n    path = version\n    if '==' in version:\n        path = version[:version.find('==')]\n    output = virtualenv.create_bootstrap_script(\n        textwrap.dedent(after_install % (path, version)))\n    fp = open(filename, 'w')\n    fp.write(output)\n    fp.close()\n\n\ndef main():\n    if len(sys.argv) != 2:\n        print >> sys.stderr, 'usage: %s version' % sys.argv[0]\n        sys.exit(1)\n    generate(filename, sys.argv[1])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "scripts/go-pylons.py",
    "content": "#!/usr/bin/env python\n## WARNING: This file is generated\n#!/usr/bin/env python\n\"\"\"Create a \"virtual\" Python installation\n\"\"\"\n\n__version__ = \"12.0.5\"\nvirtualenv_version = __version__  # legacy\n\nimport base64\nimport sys\nimport os\nimport codecs\nimport optparse\nimport re\nimport shutil\nimport logging\nimport tempfile\nimport zlib\nimport errno\nimport glob\nimport distutils.sysconfig\nfrom distutils.util import strtobool\nimport struct\nimport subprocess\nimport tarfile\n\nif sys.version_info < (2, 6):\n    print('ERROR: %s' % sys.exc_info()[1])\n    print('ERROR: this script requires Python 2.6 or greater.')\n    sys.exit(101)\n\ntry:\n    basestring\nexcept NameError:\n    basestring = str\n\ntry:\n    import ConfigParser\nexcept ImportError:\n    import configparser as ConfigParser\n\njoin = os.path.join\npy_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])\n\nis_jython = sys.platform.startswith('java')\nis_pypy = hasattr(sys, 'pypy_version_info')\nis_win = (sys.platform == 'win32')\nis_cygwin = (sys.platform == 'cygwin')\nis_darwin = (sys.platform == 'darwin')\nabiflags = getattr(sys, 'abiflags', '')\n\nuser_dir = os.path.expanduser('~')\nif is_win:\n    default_storage_dir = os.path.join(user_dir, 'virtualenv')\nelse:\n    default_storage_dir = os.path.join(user_dir, '.virtualenv')\ndefault_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')\n\nif is_pypy:\n    expected_exe = 'pypy'\nelif is_jython:\n    expected_exe = 'jython'\nelse:\n    expected_exe = 'python'\n\n# Return a mapping of version -> Python executable\n# Only provided for Windows, where the information in the registry is used\nif not is_win:\n    def get_installed_pythons():\n        return {}\nelse:\n    try:\n        import winreg\n    except ImportError:\n        import _winreg as winreg\n\n    def get_installed_pythons():\n        try:\n            python_core = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE,\n                    \"Software\\\\Python\\\\PythonCore\")\n        except WindowsError:\n            # No registered Python installations\n            return {}\n        i = 0\n        versions = []\n        while True:\n            try:\n                versions.append(winreg.EnumKey(python_core, i))\n                i = i + 1\n            except WindowsError:\n                break\n        exes = dict()\n        for ver in versions:\n            try:\n                path = winreg.QueryValue(python_core, \"%s\\\\InstallPath\" % ver)\n            except WindowsError:\n                continue\n            exes[ver] = join(path, \"python.exe\")\n\n        winreg.CloseKey(python_core)\n\n        # Add the major versions\n        # Sort the keys, then repeatedly update the major version entry\n        # Last executable (i.e., highest version) wins with this approach\n        for ver in sorted(exes):\n            exes[ver[0]] = exes[ver]\n\n        return exes\n\nREQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',\n                    'fnmatch', 'locale', 'encodings', 'codecs',\n                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',\n                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',\n                    'zlib']\n\nREQUIRED_FILES = ['lib-dynload', 'config']\n\nmajver, minver = sys.version_info[:2]\nif majver == 2:\n    if minver >= 6:\n        REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])\n    if minver >= 7:\n        REQUIRED_MODULES.extend(['_weakrefset'])\nelif majver == 3:\n    # Some extra modules are needed for Python 3, but different ones\n    # for different versions.\n    REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',\n                             '_weakrefset', 'copyreg', 'tempfile', 'random',\n                             '__future__', 'collections', 'keyword', 'tarfile',\n                             'shutil', 'struct', 'copy', 'tokenize', 'token',\n                             'functools', 'heapq', 'bisect', 'weakref',\n                             'reprlib'])\n    if minver >= 2:\n        REQUIRED_FILES[-1] = 'config-%s' % majver\n    if minver >= 3:\n        import sysconfig\n        platdir = sysconfig.get_config_var('PLATDIR')\n        REQUIRED_FILES.append(platdir)\n        # The whole list of 3.3 modules is reproduced below - the current\n        # uncommented ones are required for 3.3 as of now, but more may be\n        # added as 3.3 development continues.\n        REQUIRED_MODULES.extend([\n            #\"aifc\",\n            #\"antigravity\",\n            #\"argparse\",\n            #\"ast\",\n            #\"asynchat\",\n            #\"asyncore\",\n            \"base64\",\n            #\"bdb\",\n            #\"binhex\",\n            #\"bisect\",\n            #\"calendar\",\n            #\"cgi\",\n            #\"cgitb\",\n            #\"chunk\",\n            #\"cmd\",\n            #\"codeop\",\n            #\"code\",\n            #\"colorsys\",\n            #\"_compat_pickle\",\n            #\"compileall\",\n            #\"concurrent\",\n            #\"configparser\",\n            #\"contextlib\",\n            #\"cProfile\",\n            #\"crypt\",\n            #\"csv\",\n            #\"ctypes\",\n            #\"curses\",\n            #\"datetime\",\n            #\"dbm\",\n            #\"decimal\",\n            #\"difflib\",\n            #\"dis\",\n            #\"doctest\",\n            #\"dummy_threading\",\n            \"_dummy_thread\",\n            #\"email\",\n            #\"filecmp\",\n            #\"fileinput\",\n            #\"formatter\",\n            #\"fractions\",\n            #\"ftplib\",\n            #\"functools\",\n            #\"getopt\",\n            #\"getpass\",\n            #\"gettext\",\n            #\"glob\",\n            #\"gzip\",\n            \"hashlib\",\n            #\"heapq\",\n            \"hmac\",\n            #\"html\",\n            #\"http\",\n            #\"idlelib\",\n            #\"imaplib\",\n            #\"imghdr\",\n            \"imp\",\n            \"importlib\",\n            #\"inspect\",\n            #\"json\",\n            #\"lib2to3\",\n            #\"logging\",\n            #\"macpath\",\n            #\"macurl2path\",\n            #\"mailbox\",\n            #\"mailcap\",\n            #\"_markupbase\",\n            #\"mimetypes\",\n            #\"modulefinder\",\n            #\"multiprocessing\",\n            #\"netrc\",\n            #\"nntplib\",\n            #\"nturl2path\",\n            #\"numbers\",\n            #\"opcode\",\n            #\"optparse\",\n            #\"os2emxpath\",\n            #\"pdb\",\n            #\"pickle\",\n            #\"pickletools\",\n            #\"pipes\",\n            #\"pkgutil\",\n            #\"platform\",\n            #\"plat-linux2\",\n            #\"plistlib\",\n            #\"poplib\",\n            #\"pprint\",\n            #\"profile\",\n            #\"pstats\",\n            #\"pty\",\n            #\"pyclbr\",\n            #\"py_compile\",\n            #\"pydoc_data\",\n            #\"pydoc\",\n            #\"_pyio\",\n            #\"queue\",\n            #\"quopri\",\n            #\"reprlib\",\n            \"rlcompleter\",\n            #\"runpy\",\n            #\"sched\",\n            #\"shelve\",\n            #\"shlex\",\n            #\"smtpd\",\n            #\"smtplib\",\n            #\"sndhdr\",\n            #\"socket\",\n            #\"socketserver\",\n            #\"sqlite3\",\n            #\"ssl\",\n            #\"stringprep\",\n            #\"string\",\n            #\"_strptime\",\n            #\"subprocess\",\n            #\"sunau\",\n            #\"symbol\",\n            #\"symtable\",\n            #\"sysconfig\",\n            #\"tabnanny\",\n            #\"telnetlib\",\n            #\"test\",\n            #\"textwrap\",\n            #\"this\",\n            #\"_threading_local\",\n            #\"threading\",\n            #\"timeit\",\n            #\"tkinter\",\n            #\"tokenize\",\n            #\"token\",\n            #\"traceback\",\n            #\"trace\",\n            #\"tty\",\n            #\"turtledemo\",\n            #\"turtle\",\n            #\"unittest\",\n            #\"urllib\",\n            #\"uuid\",\n            #\"uu\",\n            #\"wave\",\n            #\"weakref\",\n            #\"webbrowser\",\n            #\"wsgiref\",\n            #\"xdrlib\",\n            #\"xml\",\n            #\"xmlrpc\",\n            #\"zipfile\",\n        ])\n    if minver >= 4:\n        REQUIRED_MODULES.extend([\n            'operator',\n            '_collections_abc',\n            '_bootlocale',\n        ])\n\nif is_pypy:\n    # these are needed to correctly display the exceptions that may happen\n    # during the bootstrap\n    REQUIRED_MODULES.extend(['traceback', 'linecache'])\n\nclass Logger(object):\n\n    \"\"\"\n    Logging object for use in command-line script.  Allows ranges of\n    levels, to avoid some redundancy of displayed information.\n    \"\"\"\n\n    DEBUG = logging.DEBUG\n    INFO = logging.INFO\n    NOTIFY = (logging.INFO+logging.WARN)/2\n    WARN = WARNING = logging.WARN\n    ERROR = logging.ERROR\n    FATAL = logging.FATAL\n\n    LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]\n\n    def __init__(self, consumers):\n        self.consumers = consumers\n        self.indent = 0\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def debug(self, msg, *args, **kw):\n        self.log(self.DEBUG, msg, *args, **kw)\n    def info(self, msg, *args, **kw):\n        self.log(self.INFO, msg, *args, **kw)\n    def notify(self, msg, *args, **kw):\n        self.log(self.NOTIFY, msg, *args, **kw)\n    def warn(self, msg, *args, **kw):\n        self.log(self.WARN, msg, *args, **kw)\n    def error(self, msg, *args, **kw):\n        self.log(self.ERROR, msg, *args, **kw)\n    def fatal(self, msg, *args, **kw):\n        self.log(self.FATAL, msg, *args, **kw)\n    def log(self, level, msg, *args, **kw):\n        if args:\n            if kw:\n                raise TypeError(\n                    \"You may give positional or keyword arguments, not both\")\n        args = args or kw\n        rendered = None\n        for consumer_level, consumer in self.consumers:\n            if self.level_matches(level, consumer_level):\n                if (self.in_progress_hanging\n                    and consumer in (sys.stdout, sys.stderr)):\n                    self.in_progress_hanging = False\n                    sys.stdout.write('\\n')\n                    sys.stdout.flush()\n                if rendered is None:\n                    if args:\n                        rendered = msg % args\n                    else:\n                        rendered = msg\n                    rendered = ' '*self.indent + rendered\n                if hasattr(consumer, 'write'):\n                    consumer.write(rendered+'\\n')\n                else:\n                    consumer(rendered)\n\n    def start_progress(self, msg):\n        assert not self.in_progress, (\n            \"Tried to start_progress(%r) while in_progress %r\"\n            % (msg, self.in_progress))\n        if self.level_matches(self.NOTIFY, self._stdout_level()):\n            sys.stdout.write(msg)\n            sys.stdout.flush()\n            self.in_progress_hanging = True\n        else:\n            self.in_progress_hanging = False\n        self.in_progress = msg\n\n    def end_progress(self, msg='done.'):\n        assert self.in_progress, (\n            \"Tried to end_progress without start_progress\")\n        if self.stdout_level_matches(self.NOTIFY):\n            if not self.in_progress_hanging:\n                # Some message has been printed out since start_progress\n                sys.stdout.write('...' + self.in_progress + msg + '\\n')\n                sys.stdout.flush()\n            else:\n                sys.stdout.write(msg + '\\n')\n                sys.stdout.flush()\n        self.in_progress = None\n        self.in_progress_hanging = False\n\n    def show_progress(self):\n        \"\"\"If we are in a progress scope, and no log messages have been\n        shown, write out another '.'\"\"\"\n        if self.in_progress_hanging:\n            sys.stdout.write('.')\n            sys.stdout.flush()\n\n    def stdout_level_matches(self, level):\n        \"\"\"Returns true if a message at this level will go to stdout\"\"\"\n        return self.level_matches(level, self._stdout_level())\n\n    def _stdout_level(self):\n        \"\"\"Returns the level that stdout runs at\"\"\"\n        for level, consumer in self.consumers:\n            if consumer is sys.stdout:\n                return level\n        return self.FATAL\n\n    def level_matches(self, level, consumer_level):\n        \"\"\"\n        >>> l = Logger([])\n        >>> l.level_matches(3, 4)\n        False\n        >>> l.level_matches(3, 2)\n        True\n        >>> l.level_matches(slice(None, 3), 3)\n        False\n        >>> l.level_matches(slice(None, 3), 2)\n        True\n        >>> l.level_matches(slice(1, 3), 1)\n        True\n        >>> l.level_matches(slice(2, 3), 1)\n        False\n        \"\"\"\n        if isinstance(level, slice):\n            start, stop = level.start, level.stop\n            if start is not None and start > consumer_level:\n                return False\n            if stop is not None and stop <= consumer_level:\n                return False\n            return True\n        else:\n            return level >= consumer_level\n\n    #@classmethod\n    def level_for_integer(cls, level):\n        levels = cls.LEVELS\n        if level < 0:\n            return levels[0]\n        if level >= len(levels):\n            return levels[-1]\n        return levels[level]\n\n    level_for_integer = classmethod(level_for_integer)\n\n# create a silent logger just to prevent this from being undefined\n# will be overridden with requested verbosity main() is called.\nlogger = Logger([(Logger.LEVELS[-1], sys.stdout)])\n\ndef mkdir(path):\n    if not os.path.exists(path):\n        logger.info('Creating %s', path)\n        os.makedirs(path)\n    else:\n        logger.info('Directory %s already exists', path)\n\ndef copyfileordir(src, dest, symlink=True):\n    if os.path.isdir(src):\n        shutil.copytree(src, dest, symlink)\n    else:\n        shutil.copy2(src, dest)\n\ndef copyfile(src, dest, symlink=True):\n    if not os.path.exists(src):\n        # Some bad symlink in the src\n        logger.warn('Cannot find file %s (bad symlink)', src)\n        return\n    if os.path.exists(dest):\n        logger.debug('File %s already exists', dest)\n        return\n    if not os.path.exists(os.path.dirname(dest)):\n        logger.info('Creating parent directories for %s', os.path.dirname(dest))\n        os.makedirs(os.path.dirname(dest))\n    if not os.path.islink(src):\n        srcpath = os.path.abspath(src)\n    else:\n        srcpath = os.readlink(src)\n    if symlink and hasattr(os, 'symlink') and not is_win:\n        logger.info('Symlinking %s', dest)\n        try:\n            os.symlink(srcpath, dest)\n        except (OSError, NotImplementedError):\n            logger.info('Symlinking failed, copying to %s', dest)\n            copyfileordir(src, dest, symlink)\n    else:\n        logger.info('Copying to %s', dest)\n        copyfileordir(src, dest, symlink)\n\ndef writefile(dest, content, overwrite=True):\n    if not os.path.exists(dest):\n        logger.info('Writing %s', dest)\n        f = open(dest, 'wb')\n        f.write(content.encode('utf-8'))\n        f.close()\n        return\n    else:\n        f = open(dest, 'rb')\n        c = f.read()\n        f.close()\n        if c != content.encode(\"utf-8\"):\n            if not overwrite:\n                logger.notify('File %s exists with different content; not overwriting', dest)\n                return\n            logger.notify('Overwriting %s with new content', dest)\n            f = open(dest, 'wb')\n            f.write(content.encode('utf-8'))\n            f.close()\n        else:\n            logger.info('Content %s already in place', dest)\n\ndef rmtree(dir):\n    if os.path.exists(dir):\n        logger.notify('Deleting tree %s', dir)\n        shutil.rmtree(dir)\n    else:\n        logger.info('Do not need to delete %s; already gone', dir)\n\ndef make_exe(fn):\n    if hasattr(os, 'chmod'):\n        oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777\n        newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777\n        os.chmod(fn, newmode)\n        logger.info('Changed mode of %s to %s', fn, oct(newmode))\n\ndef _find_file(filename, dirs):\n    for dir in reversed(dirs):\n        files = glob.glob(os.path.join(dir, filename))\n        if files and os.path.isfile(files[0]):\n            return True, files[0]\n    return False, filename\n\ndef file_search_dirs():\n    here = os.path.dirname(os.path.abspath(__file__))\n    dirs = ['.', here,\n            join(here, 'virtualenv_support')]\n    if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':\n        # Probably some boot script; just in case virtualenv is installed...\n        try:\n            import virtualenv\n        except ImportError:\n            pass\n        else:\n            dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))\n    return [d for d in dirs if os.path.isdir(d)]\n\n\nclass UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):\n    \"\"\"\n    Custom help formatter for use in ConfigOptionParser that updates\n    the defaults before expanding them, allowing them to show up correctly\n    in the help listing\n    \"\"\"\n    def expand_default(self, option):\n        if self.parser is not None:\n            self.parser.update_defaults(self.parser.defaults)\n        return optparse.IndentedHelpFormatter.expand_default(self, option)\n\n\nclass ConfigOptionParser(optparse.OptionParser):\n    \"\"\"\n    Custom option parser which updates its defaults by checking the\n    configuration files and environmental variables\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self.config = ConfigParser.RawConfigParser()\n        self.files = self.get_config_files()\n        self.config.read(self.files)\n        optparse.OptionParser.__init__(self, *args, **kwargs)\n\n    def get_config_files(self):\n        config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)\n        if config_file and os.path.exists(config_file):\n            return [config_file]\n        return [default_config_file]\n\n    def update_defaults(self, defaults):\n        \"\"\"\n        Updates the given defaults with values from the config files and\n        the environ. Does a little special handling for certain types of\n        options (lists).\n        \"\"\"\n        # Then go and look for the other sources of configuration:\n        config = {}\n        # 1. config files\n        config.update(dict(self.get_config_section('virtualenv')))\n        # 2. environmental variables\n        config.update(dict(self.get_environ_vars()))\n        # Then set the options with those values\n        for key, val in config.items():\n            key = key.replace('_', '-')\n            if not key.startswith('--'):\n                key = '--%s' % key  # only prefer long opts\n            option = self.get_option(key)\n            if option is not None:\n                # ignore empty values\n                if not val:\n                    continue\n                # handle multiline configs\n                if option.action == 'append':\n                    val = val.split()\n                else:\n                    option.nargs = 1\n                if option.action == 'store_false':\n                    val = not strtobool(val)\n                elif option.action in ('store_true', 'count'):\n                    val = strtobool(val)\n                try:\n                    val = option.convert_value(key, val)\n                except optparse.OptionValueError:\n                    e = sys.exc_info()[1]\n                    print(\"An error occurred during configuration: %s\" % e)\n                    sys.exit(3)\n                defaults[option.dest] = val\n        return defaults\n\n    def get_config_section(self, name):\n        \"\"\"\n        Get a section of a configuration\n        \"\"\"\n        if self.config.has_section(name):\n            return self.config.items(name)\n        return []\n\n    def get_environ_vars(self, prefix='VIRTUALENV_'):\n        \"\"\"\n        Returns a generator with all environmental vars with prefix VIRTUALENV\n        \"\"\"\n        for key, val in os.environ.items():\n            if key.startswith(prefix):\n                yield (key.replace(prefix, '').lower(), val)\n\n    def get_default_values(self):\n        \"\"\"\n        Overridding to make updating the defaults after instantiation of\n        the option parser possible, update_defaults() does the dirty work.\n        \"\"\"\n        if not self.process_default_values:\n            # Old, pre-Optik 1.5 behaviour.\n            return optparse.Values(self.defaults)\n\n        defaults = self.update_defaults(self.defaults.copy())  # ours\n        for option in self._get_all_options():\n            default = defaults.get(option.dest)\n            if isinstance(default, basestring):\n                opt_str = option.get_opt_string()\n                defaults[option.dest] = option.check_value(opt_str, default)\n        return optparse.Values(defaults)\n\n\ndef main():\n    parser = ConfigOptionParser(\n        version=virtualenv_version,\n        usage=\"%prog [OPTIONS] DEST_DIR\",\n        formatter=UpdatingDefaultsHelpFormatter())\n\n    parser.add_option(\n        '-v', '--verbose',\n        action='count',\n        dest='verbose',\n        default=0,\n        help=\"Increase verbosity.\")\n\n    parser.add_option(\n        '-q', '--quiet',\n        action='count',\n        dest='quiet',\n        default=0,\n        help='Decrease verbosity.')\n\n    parser.add_option(\n        '-p', '--python',\n        dest='python',\n        metavar='PYTHON_EXE',\n        help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '\n        'interpreter to create the new environment.  The default is the interpreter that '\n        'virtualenv was installed with (%s)' % sys.executable)\n\n    parser.add_option(\n        '--clear',\n        dest='clear',\n        action='store_true',\n        help=\"Clear out the non-root install and start from scratch.\")\n\n    parser.set_defaults(system_site_packages=False)\n    parser.add_option(\n        '--no-site-packages',\n        dest='system_site_packages',\n        action='store_false',\n        help=\"DEPRECATED. Retained only for backward compatibility. \"\n             \"Not having access to global site-packages is now the default behavior.\")\n\n    parser.add_option(\n        '--system-site-packages',\n        dest='system_site_packages',\n        action='store_true',\n        help=\"Give the virtual environment access to the global site-packages.\")\n\n    parser.add_option(\n        '--always-copy',\n        dest='symlink',\n        action='store_false',\n        default=True,\n        help=\"Always copy files rather than symlinking.\")\n\n    parser.add_option(\n        '--unzip-setuptools',\n        dest='unzip_setuptools',\n        action='store_true',\n        help=\"Unzip Setuptools when installing it.\")\n\n    parser.add_option(\n        '--relocatable',\n        dest='relocatable',\n        action='store_true',\n        help='Make an EXISTING virtualenv environment relocatable. '\n             'This fixes up scripts and makes all .pth files relative.')\n\n    parser.add_option(\n        '--no-setuptools',\n        dest='no_setuptools',\n        action='store_true',\n        help='Do not install setuptools (or pip) in the new virtualenv.')\n\n    parser.add_option(\n        '--no-pip',\n        dest='no_pip',\n        action='store_true',\n        help='Do not install pip in the new virtualenv.')\n\n    default_search_dirs = file_search_dirs()\n    parser.add_option(\n        '--extra-search-dir',\n        dest=\"search_dirs\",\n        action=\"append\",\n        metavar='DIR',\n        default=default_search_dirs,\n        help=\"Directory to look for setuptools/pip distributions in. \"\n              \"This option can be used multiple times.\")\n\n    parser.add_option(\n        '--never-download',\n        dest=\"never_download\",\n        action=\"store_true\",\n        default=True,\n        help=\"DEPRECATED. Retained only for backward compatibility. This option has no effect. \"\n              \"Virtualenv never downloads pip or setuptools.\")\n\n    parser.add_option(\n        '--prompt',\n        dest='prompt',\n        help='Provides an alternative prompt prefix for this environment.')\n\n    parser.add_option(\n        '--setuptools',\n        dest='setuptools',\n        action='store_true',\n        help=\"DEPRECATED. Retained only for backward compatibility. This option has no effect.\")\n\n    parser.add_option(\n        '--distribute',\n        dest='distribute',\n        action='store_true',\n        help=\"DEPRECATED. Retained only for backward compatibility. This option has no effect.\")\n\n    if 'extend_parser' in globals():\n        extend_parser(parser)\n\n    options, args = parser.parse_args()\n\n    global logger\n\n    if 'adjust_options' in globals():\n        adjust_options(options, args)\n\n    verbosity = options.verbose - options.quiet\n    logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])\n\n    if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):\n        env = os.environ.copy()\n        interpreter = resolve_interpreter(options.python)\n        if interpreter == sys.executable:\n            logger.warn('Already using interpreter %s' % interpreter)\n        else:\n            logger.notify('Running virtualenv with interpreter %s' % interpreter)\n            env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'\n            file = __file__\n            if file.endswith('.pyc'):\n                file = file[:-1]\n            popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)\n            raise SystemExit(popen.wait())\n\n    if not args:\n        print('You must provide a DEST_DIR')\n        parser.print_help()\n        sys.exit(2)\n    if len(args) > 1:\n        print('There must be only one argument: DEST_DIR (you gave %s)' % (\n            ' '.join(args)))\n        parser.print_help()\n        sys.exit(2)\n\n    home_dir = args[0]\n\n    if os.environ.get('WORKING_ENV'):\n        logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')\n        logger.fatal('Please deactivate your workingenv, then re-run this script')\n        sys.exit(3)\n\n    if 'PYTHONHOME' in os.environ:\n        logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')\n        del os.environ['PYTHONHOME']\n\n    if options.relocatable:\n        make_environment_relocatable(home_dir)\n        return\n\n    if not options.never_download:\n        logger.warn('The --never-download option is for backward compatibility only.')\n        logger.warn('Setting it to false is no longer supported, and will be ignored.')\n\n    create_environment(home_dir,\n                       site_packages=options.system_site_packages,\n                       clear=options.clear,\n                       unzip_setuptools=options.unzip_setuptools,\n                       prompt=options.prompt,\n                       search_dirs=options.search_dirs,\n                       never_download=True,\n                       no_setuptools=options.no_setuptools,\n                       no_pip=options.no_pip,\n                       symlink=options.symlink)\n    if 'after_install' in globals():\n        after_install(options, home_dir)\n\ndef call_subprocess(cmd, show_stdout=True,\n                    filter_stdout=None, cwd=None,\n                    raise_on_returncode=True, extra_env=None,\n                    remove_from_env=None):\n    cmd_parts = []\n    for part in cmd:\n        if len(part) > 45:\n            part = part[:20]+\"...\"+part[-20:]\n        if ' ' in part or '\\n' in part or '\"' in part or \"'\" in part:\n            part = '\"%s\"' % part.replace('\"', '\\\\\"')\n        if hasattr(part, 'decode'):\n            try:\n                part = part.decode(sys.getdefaultencoding())\n            except UnicodeDecodeError:\n                part = part.decode(sys.getfilesystemencoding())\n        cmd_parts.append(part)\n    cmd_desc = ' '.join(cmd_parts)\n    if show_stdout:\n        stdout = None\n    else:\n        stdout = subprocess.PIPE\n    logger.debug(\"Running command %s\" % cmd_desc)\n    if extra_env or remove_from_env:\n        env = os.environ.copy()\n        if extra_env:\n            env.update(extra_env)\n        if remove_from_env:\n            for varname in remove_from_env:\n                env.pop(varname, None)\n    else:\n        env = None\n    try:\n        proc = subprocess.Popen(\n            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,\n            cwd=cwd, env=env)\n    except Exception:\n        e = sys.exc_info()[1]\n        logger.fatal(\n            \"Error %s while executing command %s\" % (e, cmd_desc))\n        raise\n    all_output = []\n    if stdout is not None:\n        stdout = proc.stdout\n        encoding = sys.getdefaultencoding()\n        fs_encoding = sys.getfilesystemencoding()\n        while 1:\n            line = stdout.readline()\n            try:\n                line = line.decode(encoding)\n            except UnicodeDecodeError:\n                line = line.decode(fs_encoding)\n            if not line:\n                break\n            line = line.rstrip()\n            all_output.append(line)\n            if filter_stdout:\n                level = filter_stdout(line)\n                if isinstance(level, tuple):\n                    level, line = level\n                logger.log(level, line)\n                if not logger.stdout_level_matches(level):\n                    logger.show_progress()\n            else:\n                logger.info(line)\n    else:\n        proc.communicate()\n    proc.wait()\n    if proc.returncode:\n        if raise_on_returncode:\n            if all_output:\n                logger.notify('Complete output from command %s:' % cmd_desc)\n                logger.notify('\\n'.join(all_output) + '\\n----------------------------------------')\n            raise OSError(\n                \"Command %s failed with error code %s\"\n                % (cmd_desc, proc.returncode))\n        else:\n            logger.warn(\n                \"Command %s had error code %s\"\n                % (cmd_desc, proc.returncode))\n\ndef filter_install_output(line):\n    if line.strip().startswith('running'):\n        return Logger.INFO\n    return Logger.DEBUG\n\ndef find_wheels(projects, search_dirs):\n    \"\"\"Find wheels from which we can import PROJECTS.\n\n    Scan through SEARCH_DIRS for a wheel for each PROJECT in turn. Return\n    a list of the first wheel found for each PROJECT\n    \"\"\"\n\n    wheels = []\n\n    # Look through SEARCH_DIRS for the first suitable wheel. Don't bother\n    # about version checking here, as this is simply to get something we can\n    # then use to install the correct version.\n    for project in projects:\n        for dirname in search_dirs:\n            # This relies on only having \"universal\" wheels available.\n            # The pattern could be tightened to require -py2.py3-none-any.whl.\n            files = glob.glob(os.path.join(dirname, project + '-*.whl'))\n            if files:\n                wheels.append(os.path.abspath(files[0]))\n                break\n        else:\n            # We're out of luck, so quit with a suitable error\n            logger.fatal('Cannot find a wheel for %s' % (project,))\n\n    return wheels\n\ndef install_wheel(project_names, py_executable, search_dirs=None):\n    if search_dirs is None:\n        search_dirs = file_search_dirs()\n\n    wheels = find_wheels(['setuptools', 'pip'], search_dirs)\n    pythonpath = os.pathsep.join(wheels)\n    findlinks = ' '.join(search_dirs)\n\n    cmd = [\n        py_executable, '-c',\n        'import sys, pip; sys.exit(pip.main([\"install\", \"--ignore-installed\"] + sys.argv[1:]))',\n    ] + project_names\n    logger.start_progress('Installing %s...' % (', '.join(project_names)))\n    logger.indent += 2\n    try:\n        call_subprocess(cmd, show_stdout=False,\n            extra_env = {\n                'PYTHONPATH': pythonpath,\n                'PIP_FIND_LINKS': findlinks,\n                'PIP_USE_WHEEL': '1',\n                'PIP_PRE': '1',\n                'PIP_NO_INDEX': '1'\n            }\n        )\n    finally:\n        logger.indent -= 2\n        logger.end_progress()\n\ndef create_environment(home_dir, site_packages=False, clear=False,\n                       unzip_setuptools=False,\n                       prompt=None, search_dirs=None, never_download=False,\n                       no_setuptools=False, no_pip=False, symlink=True):\n    \"\"\"\n    Creates a new environment in ``home_dir``.\n\n    If ``site_packages`` is true, then the global ``site-packages/``\n    directory will be on the path.\n\n    If ``clear`` is true (default False) then the environment will\n    first be cleared.\n    \"\"\"\n    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)\n\n    py_executable = os.path.abspath(install_python(\n        home_dir, lib_dir, inc_dir, bin_dir,\n        site_packages=site_packages, clear=clear, symlink=symlink))\n\n    install_distutils(home_dir)\n\n    if not no_setuptools:\n        to_install = ['setuptools']\n        if not no_pip:\n            to_install.append('pip')\n        install_wheel(to_install, py_executable, search_dirs)\n\n    install_activate(home_dir, bin_dir, prompt)\n\ndef is_executable_file(fpath):\n    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)\n\ndef path_locations(home_dir):\n    \"\"\"Return the path locations for the environment (where libraries are,\n    where scripts go, etc)\"\"\"\n    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its\n    # prefix arg is broken: http://bugs.python.org/issue3386\n    if is_win:\n        # Windows has lots of problems with executables with spaces in\n        # the name; this function will remove them (using the ~1\n        # format):\n        mkdir(home_dir)\n        if ' ' in home_dir:\n            import ctypes\n            GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW\n            size = max(len(home_dir)+1, 256)\n            buf = ctypes.create_unicode_buffer(size)\n            try:\n                u = unicode\n            except NameError:\n                u = str\n            ret = GetShortPathName(u(home_dir), buf, size)\n            if not ret:\n                print('Error: the path \"%s\" has a space in it' % home_dir)\n                print('We could not determine the short pathname for it.')\n                print('Exiting.')\n                sys.exit(3)\n            home_dir = str(buf.value)\n        lib_dir = join(home_dir, 'Lib')\n        inc_dir = join(home_dir, 'Include')\n        bin_dir = join(home_dir, 'Scripts')\n    if is_jython:\n        lib_dir = join(home_dir, 'Lib')\n        inc_dir = join(home_dir, 'Include')\n        bin_dir = join(home_dir, 'bin')\n    elif is_pypy:\n        lib_dir = home_dir\n        inc_dir = join(home_dir, 'include')\n        bin_dir = join(home_dir, 'bin')\n    elif not is_win:\n        lib_dir = join(home_dir, 'lib', py_version)\n        multiarch_exec = '/usr/bin/multiarch-platform'\n        if is_executable_file(multiarch_exec):\n            # In Mageia (2) and Mandriva distros the include dir must be like:\n            # virtualenv/include/multiarch-x86_64-linux/python2.7\n            # instead of being virtualenv/include/python2.7\n            p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n            stdout, stderr = p.communicate()\n            # stdout.strip is needed to remove newline character\n            inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abiflags)\n        else:\n            inc_dir = join(home_dir, 'include', py_version + abiflags)\n        bin_dir = join(home_dir, 'bin')\n    return home_dir, lib_dir, inc_dir, bin_dir\n\n\ndef change_prefix(filename, dst_prefix):\n    prefixes = [sys.prefix]\n\n    if is_darwin:\n        prefixes.extend((\n            os.path.join(\"/Library/Python\", sys.version[:3], \"site-packages\"),\n            os.path.join(sys.prefix, \"Extras\", \"lib\", \"python\"),\n            os.path.join(\"~\", \"Library\", \"Python\", sys.version[:3], \"site-packages\"),\n            # Python 2.6 no-frameworks\n            os.path.join(\"~\", \".local\", \"lib\",\"python\", sys.version[:3], \"site-packages\"),\n            # System Python 2.7 on OSX Mountain Lion\n            os.path.join(\"~\", \"Library\", \"Python\", sys.version[:3], \"lib\", \"python\", \"site-packages\")))\n\n    if hasattr(sys, 'real_prefix'):\n        prefixes.append(sys.real_prefix)\n    if hasattr(sys, 'base_prefix'):\n        prefixes.append(sys.base_prefix)\n    prefixes = list(map(os.path.expanduser, prefixes))\n    prefixes = list(map(os.path.abspath, prefixes))\n    # Check longer prefixes first so we don't split in the middle of a filename\n    prefixes = sorted(prefixes, key=len, reverse=True)\n    filename = os.path.abspath(filename)\n    for src_prefix in prefixes:\n        if filename.startswith(src_prefix):\n            _, relpath = filename.split(src_prefix, 1)\n            if src_prefix != os.sep: # sys.prefix == \"/\"\n                assert relpath[0] == os.sep\n                relpath = relpath[1:]\n            return join(dst_prefix, relpath)\n    assert False, \"Filename %s does not start with any of these prefixes: %s\" % \\\n        (filename, prefixes)\n\ndef copy_required_modules(dst_prefix, symlink):\n    import imp\n    # If we are running under -p, we need to remove the current\n    # directory from sys.path temporarily here, so that we\n    # definitely get the modules from the site directory of\n    # the interpreter we are running under, not the one\n    # virtualenv.py is installed under (which might lead to py2/py3\n    # incompatibility issues)\n    _prev_sys_path = sys.path\n    if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):\n        sys.path = sys.path[1:]\n    try:\n        for modname in REQUIRED_MODULES:\n            if modname in sys.builtin_module_names:\n                logger.info(\"Ignoring built-in bootstrap module: %s\" % modname)\n                continue\n            try:\n                f, filename, _ = imp.find_module(modname)\n            except ImportError:\n                logger.info(\"Cannot import bootstrap module: %s\" % modname)\n            else:\n                if f is not None:\n                    f.close()\n                # special-case custom readline.so on OS X, but not for pypy:\n                if modname == 'readline' and sys.platform == 'darwin' and not (\n                        is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))):\n                    dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')\n                elif modname == 'readline' and sys.platform == 'win32':\n                    # special-case for Windows, where readline is not a\n                    # standard module, though it may have been installed in\n                    # site-packages by a third-party package\n                    pass\n                else:\n                    dst_filename = change_prefix(filename, dst_prefix)\n                copyfile(filename, dst_filename, symlink)\n                if filename.endswith('.pyc'):\n                    pyfile = filename[:-1]\n                    if os.path.exists(pyfile):\n                        copyfile(pyfile, dst_filename[:-1], symlink)\n    finally:\n        sys.path = _prev_sys_path\n\n\ndef subst_path(prefix_path, prefix, home_dir):\n    prefix_path = os.path.normpath(prefix_path)\n    prefix = os.path.normpath(prefix)\n    home_dir = os.path.normpath(home_dir)\n    if not prefix_path.startswith(prefix):\n        logger.warn('Path not in prefix %r %r', prefix_path, prefix)\n        return\n    return prefix_path.replace(prefix, home_dir, 1)\n\n\ndef install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True):\n    \"\"\"Install just the base environment, no distutils patches etc\"\"\"\n    if sys.executable.startswith(bin_dir):\n        print('Please use the *system* python to run this script')\n        return\n\n    if clear:\n        rmtree(lib_dir)\n        ## FIXME: why not delete it?\n        ## Maybe it should delete everything with #!/path/to/venv/python in it\n        logger.notify('Not deleting %s', bin_dir)\n\n    if hasattr(sys, 'real_prefix'):\n        logger.notify('Using real prefix %r' % sys.real_prefix)\n        prefix = sys.real_prefix\n    elif hasattr(sys, 'base_prefix'):\n        logger.notify('Using base prefix %r' % sys.base_prefix)\n        prefix = sys.base_prefix\n    else:\n        prefix = sys.prefix\n    mkdir(lib_dir)\n    fix_lib64(lib_dir, symlink)\n    stdlib_dirs = [os.path.dirname(os.__file__)]\n    if is_win:\n        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))\n    elif is_darwin:\n        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))\n    if hasattr(os, 'symlink'):\n        logger.info('Symlinking Python bootstrap modules')\n    else:\n        logger.info('Copying Python bootstrap modules')\n    logger.indent += 2\n    try:\n        # copy required files...\n        for stdlib_dir in stdlib_dirs:\n            if not os.path.isdir(stdlib_dir):\n                continue\n            for fn in os.listdir(stdlib_dir):\n                bn = os.path.splitext(fn)[0]\n                if fn != 'site-packages' and bn in REQUIRED_FILES:\n                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn), symlink)\n        # ...and modules\n        copy_required_modules(home_dir, symlink)\n    finally:\n        logger.indent -= 2\n    mkdir(join(lib_dir, 'site-packages'))\n    import site\n    site_filename = site.__file__\n    if site_filename.endswith('.pyc'):\n        site_filename = site_filename[:-1]\n    elif site_filename.endswith('$py.class'):\n        site_filename = site_filename.replace('$py.class', '.py')\n    site_filename_dst = change_prefix(site_filename, home_dir)\n    site_dir = os.path.dirname(site_filename_dst)\n    writefile(site_filename_dst, SITE_PY)\n    writefile(join(site_dir, 'orig-prefix.txt'), prefix)\n    site_packages_filename = join(site_dir, 'no-global-site-packages.txt')\n    if not site_packages:\n        writefile(site_packages_filename, '')\n\n    if is_pypy or is_win:\n        stdinc_dir = join(prefix, 'include')\n    else:\n        stdinc_dir = join(prefix, 'include', py_version + abiflags)\n    if os.path.exists(stdinc_dir):\n        copyfile(stdinc_dir, inc_dir, symlink)\n    else:\n        logger.debug('No include dir %s' % stdinc_dir)\n\n    platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1)\n    if platinc_dir != stdinc_dir:\n        platinc_dest = distutils.sysconfig.get_python_inc(\n            plat_specific=1, prefix=home_dir)\n        if platinc_dir == platinc_dest:\n            # Do platinc_dest manually due to a CPython bug;\n            # not http://bugs.python.org/issue3386 but a close cousin\n            platinc_dest = subst_path(platinc_dir, prefix, home_dir)\n        if platinc_dest:\n            # PyPy's stdinc_dir and prefix are relative to the original binary\n            # (traversing virtualenvs), whereas the platinc_dir is relative to\n            # the inner virtualenv and ignores the prefix argument.\n            # This seems more evolved than designed.\n            copyfile(platinc_dir, platinc_dest, symlink)\n\n    # pypy never uses exec_prefix, just ignore it\n    if sys.exec_prefix != prefix and not is_pypy:\n        if is_win:\n            exec_dir = join(sys.exec_prefix, 'lib')\n        elif is_jython:\n            exec_dir = join(sys.exec_prefix, 'Lib')\n        else:\n            exec_dir = join(sys.exec_prefix, 'lib', py_version)\n        for fn in os.listdir(exec_dir):\n            copyfile(join(exec_dir, fn), join(lib_dir, fn), symlink)\n\n    if is_jython:\n        # Jython has either jython-dev.jar and javalib/ dir, or just\n        # jython.jar\n        for name in 'jython-dev.jar', 'javalib', 'jython.jar':\n            src = join(prefix, name)\n            if os.path.exists(src):\n                copyfile(src, join(home_dir, name), symlink)\n        # XXX: registry should always exist after Jython 2.5rc1\n        src = join(prefix, 'registry')\n        if os.path.exists(src):\n            copyfile(src, join(home_dir, 'registry'), symlink=False)\n        copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),\n                 symlink=False)\n\n    mkdir(bin_dir)\n    py_executable = join(bin_dir, os.path.basename(sys.executable))\n    if 'Python.framework' in prefix:\n        # OS X framework builds cause validation to break\n        # https://github.com/pypa/virtualenv/issues/322\n        if os.environ.get('__PYVENV_LAUNCHER__'):\n            del os.environ[\"__PYVENV_LAUNCHER__\"]\n        if re.search(r'/Python(?:-32|-64)*$', py_executable):\n            # The name of the python executable is not quite what\n            # we want, rename it.\n            py_executable = os.path.join(\n                    os.path.dirname(py_executable), 'python')\n\n    logger.notify('New %s executable in %s', expected_exe, py_executable)\n    pcbuild_dir = os.path.dirname(sys.executable)\n    pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth')\n    if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')):\n        logger.notify('Detected python running from build directory %s', pcbuild_dir)\n        logger.notify('Writing .pth file linking to build directory for *.pyd files')\n        writefile(pyd_pth, pcbuild_dir)\n    else:\n        pcbuild_dir = None\n        if os.path.exists(pyd_pth):\n            logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)\n            os.unlink(pyd_pth)\n\n    if sys.executable != py_executable:\n        ## FIXME: could I just hard link?\n        executable = sys.executable\n        shutil.copyfile(executable, py_executable)\n        make_exe(py_executable)\n        if is_win or is_cygwin:\n            pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')\n            if os.path.exists(pythonw):\n                logger.info('Also created pythonw.exe')\n                shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))\n            python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe')\n            python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe')\n            if os.path.exists(python_d):\n                logger.info('Also created python_d.exe')\n                shutil.copyfile(python_d, python_d_dest)\n            elif os.path.exists(python_d_dest):\n                logger.info('Removed python_d.exe as it is no longer at the source')\n                os.unlink(python_d_dest)\n            # we need to copy the DLL to enforce that windows will load the correct one.\n            # may not exist if we are cygwin.\n            py_executable_dll = 'python%s%s.dll' % (\n                sys.version_info[0], sys.version_info[1])\n            py_executable_dll_d = 'python%s%s_d.dll' % (\n                sys.version_info[0], sys.version_info[1])\n            pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)\n            pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)\n            pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)\n            if os.path.exists(pythondll):\n                logger.info('Also created %s' % py_executable_dll)\n                shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))\n            if os.path.exists(pythondll_d):\n                logger.info('Also created %s' % py_executable_dll_d)\n                shutil.copyfile(pythondll_d, pythondll_d_dest)\n            elif os.path.exists(pythondll_d_dest):\n                logger.info('Removed %s as the source does not exist' % pythondll_d_dest)\n                os.unlink(pythondll_d_dest)\n        if is_pypy:\n            # make a symlink python --> pypy-c\n            python_executable = os.path.join(os.path.dirname(py_executable), 'python')\n            if sys.platform in ('win32', 'cygwin'):\n                python_executable += '.exe'\n            logger.info('Also created executable %s' % python_executable)\n            copyfile(py_executable, python_executable, symlink)\n\n            if is_win:\n                for name in ['libexpat.dll', 'libpypy.dll', 'libpypy-c.dll',\n                            'libeay32.dll', 'ssleay32.dll', 'sqlite3.dll',\n                            'tcl85.dll', 'tk85.dll']:\n                    src = join(prefix, name)\n                    if os.path.exists(src):\n                        copyfile(src, join(bin_dir, name), symlink)\n\n                for d in sys.path:\n                    if d.endswith('lib_pypy'):\n                        break\n                else:\n                    logger.fatal('Could not find lib_pypy in sys.path')\n                    raise SystemExit(3)\n                logger.info('Copying lib_pypy')\n                copyfile(d, os.path.join(home_dir, 'lib_pypy'), symlink)\n\n    if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:\n        secondary_exe = os.path.join(os.path.dirname(py_executable),\n                                     expected_exe)\n        py_executable_ext = os.path.splitext(py_executable)[1]\n        if py_executable_ext.lower() == '.exe':\n            # python2.4 gives an extension of '.4' :P\n            secondary_exe += py_executable_ext\n        if os.path.exists(secondary_exe):\n            logger.warn('Not overwriting existing %s script %s (you must use %s)'\n                        % (expected_exe, secondary_exe, py_executable))\n        else:\n            logger.notify('Also creating executable in %s' % secondary_exe)\n            shutil.copyfile(sys.executable, secondary_exe)\n            make_exe(secondary_exe)\n\n    if '.framework' in prefix:\n        if 'Python.framework' in prefix:\n            logger.debug('MacOSX Python framework detected')\n            # Make sure we use the embedded interpreter inside\n            # the framework, even if sys.executable points to\n            # the stub executable in ${sys.prefix}/bin\n            # See http://groups.google.com/group/python-virtualenv/\n            #                              browse_thread/thread/17cab2f85da75951\n            original_python = os.path.join(\n                prefix, 'Resources/Python.app/Contents/MacOS/Python')\n        if 'EPD' in prefix:\n            logger.debug('EPD framework detected')\n            original_python = os.path.join(prefix, 'bin/python')\n        shutil.copy(original_python, py_executable)\n\n        # Copy the framework's dylib into the virtual\n        # environment\n        virtual_lib = os.path.join(home_dir, '.Python')\n\n        if os.path.exists(virtual_lib):\n            os.unlink(virtual_lib)\n        copyfile(\n            os.path.join(prefix, 'Python'),\n            virtual_lib,\n            symlink)\n\n        # And then change the install_name of the copied python executable\n        try:\n            mach_o_change(py_executable,\n                          os.path.join(prefix, 'Python'),\n                          '@executable_path/../.Python')\n        except:\n            e = sys.exc_info()[1]\n            logger.warn(\"Could not call mach_o_change: %s. \"\n                        \"Trying to call install_name_tool instead.\" % e)\n            try:\n                call_subprocess(\n                    [\"install_name_tool\", \"-change\",\n                     os.path.join(prefix, 'Python'),\n                     '@executable_path/../.Python',\n                     py_executable])\n            except:\n                logger.fatal(\"Could not call install_name_tool -- you must \"\n                             \"have Apple's development tools installed\")\n                raise\n\n    if not is_win:\n        # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist\n        py_exe_version_major = 'python%s' % sys.version_info[0]\n        py_exe_version_major_minor = 'python%s.%s' % (\n            sys.version_info[0], sys.version_info[1])\n        py_exe_no_version = 'python'\n        required_symlinks = [ py_exe_no_version, py_exe_version_major,\n                         py_exe_version_major_minor ]\n\n        py_executable_base = os.path.basename(py_executable)\n\n        if py_executable_base in required_symlinks:\n            # Don't try to symlink to yourself.\n            required_symlinks.remove(py_executable_base)\n\n        for pth in required_symlinks:\n            full_pth = join(bin_dir, pth)\n            if os.path.exists(full_pth):\n                os.unlink(full_pth)\n            if symlink:\n                os.symlink(py_executable_base, full_pth)\n            else:\n                copyfile(py_executable, full_pth, symlink)\n\n    if is_win and ' ' in py_executable:\n        # There's a bug with subprocess on Windows when using a first\n        # argument that has a space in it.  Instead we have to quote\n        # the value:\n        py_executable = '\"%s\"' % py_executable\n    # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks\n    cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'\n        'getattr(out, \"buffer\", out).write(sys.prefix.encode(\"utf-8\"))']\n    logger.info('Testing executable with %s %s \"%s\"' % tuple(cmd))\n    try:\n        proc = subprocess.Popen(cmd,\n                            stdout=subprocess.PIPE)\n        proc_stdout, proc_stderr = proc.communicate()\n    except OSError:\n        e = sys.exc_info()[1]\n        if e.errno == errno.EACCES:\n            logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))\n            sys.exit(100)\n        else:\n            raise e\n\n    proc_stdout = proc_stdout.strip().decode(\"utf-8\")\n    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))\n    norm_home_dir = os.path.normcase(os.path.abspath(home_dir))\n    if hasattr(norm_home_dir, 'decode'):\n        norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())\n    if proc_stdout != norm_home_dir:\n        logger.fatal(\n            'ERROR: The executable %s is not functioning' % py_executable)\n        logger.fatal(\n            'ERROR: It thinks sys.prefix is %r (should be %r)'\n            % (proc_stdout, norm_home_dir))\n        logger.fatal(\n            'ERROR: virtualenv is not compatible with this system or executable')\n        if is_win:\n            logger.fatal(\n                'Note: some Windows users have reported this error when they '\n                'installed Python for \"Only this user\" or have multiple '\n                'versions of Python installed. Copying the appropriate '\n                'PythonXX.dll to the virtualenv Scripts/ directory may fix '\n                'this problem.')\n        sys.exit(100)\n    else:\n        logger.info('Got sys.prefix result: %r' % proc_stdout)\n\n    pydistutils = os.path.expanduser('~/.pydistutils.cfg')\n    if os.path.exists(pydistutils):\n        logger.notify('Please make sure you remove any previous custom paths from '\n                      'your %s file.' % pydistutils)\n    ## FIXME: really this should be calculated earlier\n\n    fix_local_scheme(home_dir, symlink)\n\n    if site_packages:\n        if os.path.exists(site_packages_filename):\n            logger.info('Deleting %s' % site_packages_filename)\n            os.unlink(site_packages_filename)\n\n    return py_executable\n\n\ndef install_activate(home_dir, bin_dir, prompt=None):\n    home_dir = os.path.abspath(home_dir)\n    if is_win or is_jython and os._name == 'nt':\n        files = {\n            'activate.bat': ACTIVATE_BAT,\n            'deactivate.bat': DEACTIVATE_BAT,\n            'activate.ps1': ACTIVATE_PS,\n        }\n\n        # MSYS needs paths of the form /c/path/to/file\n        drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/'))\n        home_dir_msys = (drive and \"/%s%s\" or \"%s%s\") % (drive[:1], tail)\n\n        # Run-time conditional enables (basic) Cygwin compatibility\n        home_dir_sh = (\"\"\"$(if [ \"$OSTYPE\" \"==\" \"cygwin\" ]; then cygpath -u '%s'; else echo '%s'; fi;)\"\"\" %\n                       (home_dir, home_dir_msys))\n        files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)\n\n    else:\n        files = {'activate': ACTIVATE_SH}\n\n        # suppling activate.fish in addition to, not instead of, the\n        # bash script support.\n        files['activate.fish'] = ACTIVATE_FISH\n\n        # same for csh/tcsh support...\n        files['activate.csh'] = ACTIVATE_CSH\n\n    files['activate_this.py'] = ACTIVATE_THIS\n    if hasattr(home_dir, 'decode'):\n        home_dir = home_dir.decode(sys.getfilesystemencoding())\n    vname = os.path.basename(home_dir)\n    for name, content in files.items():\n        content = content.replace('__VIRTUAL_PROMPT__', prompt or '')\n        content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)\n        content = content.replace('__VIRTUAL_ENV__', home_dir)\n        content = content.replace('__VIRTUAL_NAME__', vname)\n        content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))\n        writefile(os.path.join(bin_dir, name), content)\n\ndef install_distutils(home_dir):\n    distutils_path = change_prefix(distutils.__path__[0], home_dir)\n    mkdir(distutils_path)\n    ## FIXME: maybe this prefix setting should only be put in place if\n    ## there's a local distutils.cfg with a prefix setting?\n    home_dir = os.path.abspath(home_dir)\n    ## FIXME: this is breaking things, removing for now:\n    #distutils_cfg = DISTUTILS_CFG + \"\\n[install]\\nprefix=%s\\n\" % home_dir\n    writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)\n    writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)\n\ndef fix_local_scheme(home_dir, symlink=True):\n    \"\"\"\n    Platforms that use the \"posix_local\" install scheme (like Ubuntu with\n    Python 2.7) need to be given an additional \"local\" location, sigh.\n    \"\"\"\n    try:\n        import sysconfig\n    except ImportError:\n        pass\n    else:\n        if sysconfig._get_default_scheme() == 'posix_local':\n            local_path = os.path.join(home_dir, 'local')\n            if not os.path.exists(local_path):\n                os.mkdir(local_path)\n                for subdir_name in os.listdir(home_dir):\n                    if subdir_name == 'local':\n                        continue\n                    copyfile(os.path.abspath(os.path.join(home_dir, subdir_name)), \\\n                                                            os.path.join(local_path, subdir_name), symlink)\n\ndef fix_lib64(lib_dir, symlink=True):\n    \"\"\"\n    Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y\n    instead of lib/pythonX.Y.  If this is such a platform we'll just create a\n    symlink so lib64 points to lib\n    \"\"\"\n    if [p for p in distutils.sysconfig.get_config_vars().values()\n        if isinstance(p, basestring) and 'lib64' in p]:\n        # PyPy's library path scheme is not affected by this.\n        # Return early or we will die on the following assert.\n        if is_pypy:\n            logger.debug('PyPy detected, skipping lib64 symlinking')\n            return\n\n        logger.debug('This system uses lib64; symlinking lib64 to lib')\n\n        assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (\n            \"Unexpected python lib dir: %r\" % lib_dir)\n        lib_parent = os.path.dirname(lib_dir)\n        top_level = os.path.dirname(lib_parent)\n        lib_dir = os.path.join(top_level, 'lib')\n        lib64_link = os.path.join(top_level, 'lib64')\n        assert os.path.basename(lib_parent) == 'lib', (\n            \"Unexpected parent dir: %r\" % lib_parent)\n        if os.path.lexists(lib64_link):\n            return\n        if symlink:\n            os.symlink('lib', lib64_link)\n        else:\n            copyfile('lib', lib64_link)\n\ndef resolve_interpreter(exe):\n    \"\"\"\n    If the executable given isn't an absolute path, search $PATH for the interpreter\n    \"\"\"\n    # If the \"executable\" is a version number, get the installed executable for\n    # that version\n    python_versions = get_installed_pythons()\n    if exe in python_versions:\n        exe = python_versions[exe]\n\n    if os.path.abspath(exe) != exe:\n        paths = os.environ.get('PATH', '').split(os.pathsep)\n        for path in paths:\n            if os.path.exists(os.path.join(path, exe)):\n                exe = os.path.join(path, exe)\n                break\n    if not os.path.exists(exe):\n        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))\n        raise SystemExit(3)\n    if not is_executable(exe):\n        logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))\n        raise SystemExit(3)\n    return exe\n\ndef is_executable(exe):\n    \"\"\"Checks a file is executable\"\"\"\n    return os.access(exe, os.X_OK)\n\n############################################################\n## Relocating the environment:\n\ndef make_environment_relocatable(home_dir):\n    \"\"\"\n    Makes the already-existing environment use relative paths, and takes out\n    the #!-based environment selection in scripts.\n    \"\"\"\n    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)\n    activate_this = os.path.join(bin_dir, 'activate_this.py')\n    if not os.path.exists(activate_this):\n        logger.fatal(\n            'The environment doesn\\'t have a file %s -- please re-run virtualenv '\n            'on this environment to update it' % activate_this)\n    fixup_scripts(home_dir, bin_dir)\n    fixup_pth_and_egg_link(home_dir)\n    ## FIXME: need to fix up distutils.cfg\n\nOK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],\n                  'activate', 'activate.bat', 'activate_this.py',\n                  'activate.fish', 'activate.csh']\n\ndef fixup_scripts(home_dir, bin_dir):\n    if is_win:\n        new_shebang_args = (\n            '%s /c' % os.path.normcase(os.environ.get('COMSPEC', 'cmd.exe')),\n            '', '.exe')\n    else:\n        new_shebang_args = ('/usr/bin/env', sys.version[:3], '')\n\n    # This is what we expect at the top of scripts:\n    shebang = '#!%s' % os.path.normcase(os.path.join(\n        os.path.abspath(bin_dir), 'python%s' % new_shebang_args[2]))\n    # This is what we'll put:\n    new_shebang = '#!%s python%s%s' % new_shebang_args\n\n    for filename in os.listdir(bin_dir):\n        filename = os.path.join(bin_dir, filename)\n        if not os.path.isfile(filename):\n            # ignore subdirs, e.g. .svn ones.\n            continue\n        f = open(filename, 'rb')\n        try:\n            try:\n                lines = f.read().decode('utf-8').splitlines()\n            except UnicodeDecodeError:\n                # This is probably a binary program instead\n                # of a script, so just ignore it.\n                continue\n        finally:\n            f.close()\n        if not lines:\n            logger.warn('Script %s is an empty file' % filename)\n            continue\n\n        old_shebang = lines[0].strip()\n        old_shebang = old_shebang[0:2] + os.path.normcase(old_shebang[2:])\n\n        if not old_shebang.startswith(shebang):\n            if os.path.basename(filename) in OK_ABS_SCRIPTS:\n                logger.debug('Cannot make script %s relative' % filename)\n            elif lines[0].strip() == new_shebang:\n                logger.info('Script %s has already been made relative' % filename)\n            else:\n                logger.warn('Script %s cannot be made relative (it\\'s not a normal script that starts with %s)'\n                            % (filename, shebang))\n            continue\n        logger.notify('Making script %s relative' % filename)\n        script = relative_script([new_shebang] + lines[1:])\n        f = open(filename, 'wb')\n        f.write('\\n'.join(script).encode('utf-8'))\n        f.close()\n\ndef relative_script(lines):\n    \"Return a script that'll work in a relocatable environment.\"\n    activate = \"import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); exec(compile(open(activate_this).read(), activate_this, 'exec'), dict(__file__=activate_this)); del os, activate_this\"\n    # Find the last future statement in the script. If we insert the activation\n    # line before a future statement, Python will raise a SyntaxError.\n    activate_at = None\n    for idx, line in reversed(list(enumerate(lines))):\n        if line.split()[:3] == ['from', '__future__', 'import']:\n            activate_at = idx + 1\n            break\n    if activate_at is None:\n        # Activate after the shebang.\n        activate_at = 1\n    return lines[:activate_at] + ['', activate, ''] + lines[activate_at:]\n\ndef fixup_pth_and_egg_link(home_dir, sys_path=None):\n    \"\"\"Makes .pth and .egg-link files use relative paths\"\"\"\n    home_dir = os.path.normcase(os.path.abspath(home_dir))\n    if sys_path is None:\n        sys_path = sys.path\n    for path in sys_path:\n        if not path:\n            path = '.'\n        if not os.path.isdir(path):\n            continue\n        path = os.path.normcase(os.path.abspath(path))\n        if not path.startswith(home_dir):\n            logger.debug('Skipping system (non-environment) directory %s' % path)\n            continue\n        for filename in os.listdir(path):\n            filename = os.path.join(path, filename)\n            if filename.endswith('.pth'):\n                if not os.access(filename, os.W_OK):\n                    logger.warn('Cannot write .pth file %s, skipping' % filename)\n                else:\n                    fixup_pth_file(filename)\n            if filename.endswith('.egg-link'):\n                if not os.access(filename, os.W_OK):\n                    logger.warn('Cannot write .egg-link file %s, skipping' % filename)\n                else:\n                    fixup_egg_link(filename)\n\ndef fixup_pth_file(filename):\n    lines = []\n    prev_lines = []\n    f = open(filename)\n    prev_lines = f.readlines()\n    f.close()\n    for line in prev_lines:\n        line = line.strip()\n        if (not line or line.startswith('#') or line.startswith('import ')\n            or os.path.abspath(line) != line):\n            lines.append(line)\n        else:\n            new_value = make_relative_path(filename, line)\n            if line != new_value:\n                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))\n            lines.append(new_value)\n    if lines == prev_lines:\n        logger.info('No changes to .pth file %s' % filename)\n        return\n    logger.notify('Making paths in .pth file %s relative' % filename)\n    f = open(filename, 'w')\n    f.write('\\n'.join(lines) + '\\n')\n    f.close()\n\ndef fixup_egg_link(filename):\n    f = open(filename)\n    link = f.readline().strip()\n    f.close()\n    if os.path.abspath(link) != link:\n        logger.debug('Link in %s already relative' % filename)\n        return\n    new_link = make_relative_path(filename, link)\n    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))\n    f = open(filename, 'w')\n    f.write(new_link)\n    f.close()\n\ndef make_relative_path(source, dest, dest_is_directory=True):\n    \"\"\"\n    Make a filename relative, where the filename is dest, and it is\n    being referred to from the filename source.\n\n        >>> make_relative_path('/usr/share/something/a-file.pth',\n        ...                    '/usr/share/another-place/src/Directory')\n        '../another-place/src/Directory'\n        >>> make_relative_path('/usr/share/something/a-file.pth',\n        ...                    '/home/user/src/Directory')\n        '../../../home/user/src/Directory'\n        >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')\n        './'\n    \"\"\"\n    source = os.path.dirname(source)\n    if not dest_is_directory:\n        dest_filename = os.path.basename(dest)\n        dest = os.path.dirname(dest)\n    dest = os.path.normpath(os.path.abspath(dest))\n    source = os.path.normpath(os.path.abspath(source))\n    dest_parts = dest.strip(os.path.sep).split(os.path.sep)\n    source_parts = source.strip(os.path.sep).split(os.path.sep)\n    while dest_parts and source_parts and dest_parts[0] == source_parts[0]:\n        dest_parts.pop(0)\n        source_parts.pop(0)\n    full_parts = ['..']*len(source_parts) + dest_parts\n    if not dest_is_directory:\n        full_parts.append(dest_filename)\n    if not full_parts:\n        # Special case for the current directory (otherwise it'd be '')\n        return './'\n    return os.path.sep.join(full_parts)\n\n\n\n############################################################\n## Bootstrap script creation:\n\ndef create_bootstrap_script(extra_text, python_version=''):\n    \"\"\"\n    Creates a bootstrap script, which is like this script but with\n    extend_parser, adjust_options, and after_install hooks.\n\n    This returns a string that (written to disk of course) can be used\n    as a bootstrap script with your own customizations.  The script\n    will be the standard virtualenv.py script, with your extra text\n    added (your extra text should be Python code).\n\n    If you include these functions, they will be called:\n\n    ``extend_parser(optparse_parser)``:\n        You can add or remove options from the parser here.\n\n    ``adjust_options(options, args)``:\n        You can change options here, or change the args (if you accept\n        different kinds of arguments, be sure you modify ``args`` so it is\n        only ``[DEST_DIR]``).\n\n    ``after_install(options, home_dir)``:\n\n        After everything is installed, this function is called.  This\n        is probably the function you are most likely to use.  An\n        example would be::\n\n            def after_install(options, home_dir):\n                subprocess.call([join(home_dir, 'bin', 'easy_install'),\n                                 'MyPackage'])\n                subprocess.call([join(home_dir, 'bin', 'my-package-script'),\n                                 'setup', home_dir])\n\n        This example immediately installs a package, and runs a setup\n        script from that package.\n\n    If you provide something like ``python_version='2.5'`` then the\n    script will start with ``#!/usr/bin/env python2.5`` instead of\n    ``#!/usr/bin/env python``.  You can use this when the script must\n    be run with a particular Python version.\n    \"\"\"\n    filename = __file__\n    if filename.endswith('.pyc'):\n        filename = filename[:-1]\n    f = codecs.open(filename, 'r', encoding='utf-8')\n    content = f.read()\n    f.close()\n    py_exe = 'python%s' % python_version\n    content = (('#!/usr/bin/env %s\\n' % py_exe)\n               + '## WARNING: This file is generated\\n'\n               + content)\n    return content.replace('##EXT' 'END##', extra_text)\n\nimport os, subprocess\ndef after_install(options, home_dir):\n    etc = join(home_dir, 'etc')\n    ## TODO: this should all come from distutils\n    ## like distutils.sysconfig.get_python_inc()\n    if sys.platform == 'win32':\n        lib_dir = join(home_dir, 'Lib')\n        bin_dir = join(home_dir, 'Scripts')\n    elif is_jython:\n        lib_dir = join(home_dir, 'Lib')\n        bin_dir = join(home_dir, 'bin')\n    else:\n        lib_dir = join(home_dir, 'lib', py_version)\n        bin_dir = join(home_dir, 'bin')\n\n    if not os.path.exists(etc):\n        os.makedirs(etc)\n    subprocess.call([join(bin_dir, 'easy_install'),\n        '-f', 'http://pylonshq.com/download/1.0.2', 'Pylons==1.0.2'])\n\n\ndef convert(s):\n    b = base64.b64decode(s.encode('ascii'))\n    return zlib.decompress(b).decode('utf-8')\n\n##file site.py\nSITE_PY = convert(\"\"\"\neJzFPf1z2zaWv/OvwMqToZTKdOJ0e3tO3RsncVrfuYm3yc7m1vXoKAmyWFMkS5C2tTd3f/u9DwAE\n+CHb2+6cphNLJPDw8PC+8PAeOhqNTopCZkuxyZd1KoWScblYiyKu1kqs8lJU66Rc7hdxWW3h6eIm\nvpZKVLlQWxVhqygInv/GT/BcfF4nyqAA3+K6yjdxlSziNN2KZFPkZSWXYlmXSXYtkiypkjhN/g4t\n8iwSz387BsFZJmDmaSJLcStLBXCVyFfiYlut80yM6wLn/DL6Y/xqMhVqUSZFBQ1KjTNQZB1XQSbl\nEtCElrUCUiaV3FeFXCSrZGEb3uV1uhRFGi+k+K//4qlR0zAMVL6Rd2tZSpEBMgBTAqwC8YCvSSkW\n+VJGQryRixgH4OcNsQKGNsU1U0jGLBdpnl3DnDK5kErF5VaM53VFgAhlscwBpwQwqJI0De7y8kZN\nYElpPe7gkYiZPfzJMHvAPHH8LucAjh+z4C9Zcj9l2MA9CK5aM9uUcpXcixjBwk95Lxcz/WycrMQy\nWa2ABlk1wSYBI6BEmswPClqOb/UKfXdAWFmujGEMiShzY35JPaLgrBJxqoBt6wJppAjzd3KexBlQ\nI7uF4QAikDToG2eZqMqOQ7MTOQAocR0rkJKNEuNNnGTArD/GC0L7r0m2zO/UhCgAq6XEL7Wq3PmP\newgArR0CTANcLLOadZYmNzLdTgCBz4B9KVWdVigQy6SUiyovE6kIAKC2FfIekJ6KuJSahMyZRm6n\nRH+iSZLhwqKAocDjSyTJKrmuS5IwsUqAc4Er3n/8Sbw7fXN28kHzmAHGMnu9AZwBCi20gxMMIA5q\nVR6kOQh0FJzjHxEvlyhk1zg+4NU0OHhwpYMxzL2I2n2cBQey68XVw8AcK1AmNFZA/f4bukzVGujz\nPw+sdxCcDFGFJs7f7tY5yGQWb6RYx8xfyBnBtxrOd1FRrV8DNyiEUwGpFC4OIpggPCCJS7NxnklR\nAIulSSYnAVBoTm39VQRW+JBn+7TWLU4ACGWQwUvn2YRGzCRMtAvrNeoL03hLM9NNArvOm7wkxQH8\nny1IF6VxdkM4KmIo/jaX10mWIULIC0G4F9LA6iYBTlxG4pxakV4wjUTI2otbokjUwEvIdMCT8j7e\nFKmcsviibt2tRmgwWQmz1ilzHLSsSL3SqjVT7eW9w+hLi+sIzWpdSgBezz2hW+X5VMxBZxM2Rbxh\n8arucuKcoEeeqBPyBLWEvvgdKHqiVL2R9iXyCmgWYqhgladpfgckOwoCIfawkTHKPnPCW3gH/wJc\n/DeV1WIdBM5IFrAGhcgPgUIgYBJkprlaI+Fxm2bltpJJMtYUebmUJQ31OGIfMOKPbIxzDT7klTZq\nPF1c5XyTVKiS5tpkJmzxsrBi/fia5w3TAMutiGamaUOnDU4vLdbxXBqXZC5XKAl6kV7bZYcxg54x\nyRZXYsNWBt4BWWTCFqRfsaDSWVWSnACAwcIXZ0lRp9RIIYOJGAbaFAR/E6NJz7WzBOzNZjlAhcTm\newH2B3D7O4jR3ToB+iwAAmgY1FKwfPOkKtFBaPRR4Bt905/HB049W2nbxEOu4iTVVj7OgjN6eFqW\nJL4LWWCvqSaGghlmFbp21xnQEcV8NBoFgXGHtsp8zVVQldsjYAVhxpnN5nWChm82Q1Ovf6iARxHO\nwF43287CAw1hOn0AKjldVmW+wdd2bp9AmcBY2CPYExekZSQ7yB4nvkbyuSq9ME3RdjvsLFAPBRc/\nnb4/+3L6SRyLy0alTdv67ArGPM1iYGuyCMBUrWEbXQYtUfElqPvEezDvxBRgz6g3ia+Mqxp4F1D/\nXNb0Gqax8F4Gpx9O3pyfzv7y6fSn2aezz6eAINgZGezRlNE81uAwqgiEA7hyqSJtX4NOD3rw5uST\nfRDMEjX75mtgN3gyvpYVMHE5hhlPRbiJ7xUwaDilphPEsdMALHg4mYjvxOHz568OCVqxLbYADMyu\n0xQfzrRFnyXZKg8n1PgXdumPWUlp/+3y6OsrcXwswl/i2zgMwIdqmjJL/Eji9HlbSOhawZ9xriZB\nsJQrEL0biQI6fk5+8YQ7wJJAy1zb6V/yJDPvmSvdIUh/jKkH4DCbLdJYKWw8m4VABOrQ84EOETvX\nKHVj6Fhs3a4TjQp+SgkLm2GXKf7Tg2I8p36IBqPodjGNQFw3i1hJbkXTh36zGeqs2WysBwRhJokB\nh4vVUChME9RZZQJ+LXEe6rC5ylP8ifBRC5AA4tYKtSQukt46RbdxWks1diYFRByPW2RERZso4kdw\nUcZgiZulm0za1DQ8A82AfGkOWrRsUQ4/e+DvgLoymzjc6PHei2mGmP477zQIB3A5Q1T3SrWgsHYU\nF6cX4tWLw310Z2DPubTU8ZqjhU6yWtqHK1gtIw+MMPcy8uLSZYV6Fp8e7Ya5iezKdFlhpZe4lJv8\nVi4BW2RgZ5XFT/QGduYwj0UMqwh6nfwBVqHGb4xxH8qzB2lB3wGotyEoZv3N0u9xMEBmChQRb6yJ\n1HrXz6awKPPbBJ2N+Va/BFsJyhItpnFsAmfhPCZDkwgaArzgDCl1J0NQh2XNDivhjSDRXiwbxRoR\nuHPU1Ff09SbL77IZ74SPUemOJ5Z1UbA082KDZgn2xHuwQoBkDhu7hmgMBVx+gbK1D8jD9GG6QFna\nWwAgMPSKtmsOLLPVoynyrhGHRRiT14KEt5ToL9yaIWirZYjhQKK3kX1gtARCgslZBWdVg2YylDXT\nDAZ2SOJz3XnEW1AfQIuKEZjNsYbGjQz9Lo9AOYtzVyk5/dAif/nyhdlGrSm+gojNcdLoQqzIWEbF\nFgxrAjrBeGQcrSE2uAPnFsDUSrOm2P8k8oK9MVjPCy3b4AfA7q6qiqODg7u7u0hHF/Ly+kCtDv74\np2+++dML1onLJfEPTMeRFh1qiw7oHXq00bfGAn1nVq7Fj0nmcyPBGkvyysgVRfy+r5NlLo72J1Z/\nIhc3Zhr/Na4MKJCZGZSpDLQdNRg9U/vPoldqJJ6RdbZtxxP2S7RJtVbMt7rQo8rBEwC/ZZHXaKob\nTlDiK7BusENfynl9HdrBPRtpfsBUUU7Hlgf2X14hBj5nGL4ypniGWoLYAi2+Q/qfmG1i8o60hkDy\noonq7J63/VrMEHf5eHm3vqYjNGaGiULuQInwmzxaAG3jruTgR7u2aPcc19Z8PENgLH1gmFc7lmMU\nHMIF12LqSp3D1ejxgjTdsWoGBeOqRlDQ4CTOmdoaHNnIEEGid2M2+7ywugXQqRU5NPEBswrQwh2n\nY+3arOB4QsgDx+IlPZHgIh913r3gpa3TlAI6LR71qMKAvYVGO50DX44NgKkYlX8ZcUuzTfnYWhRe\ngx5gOceAkMFWHWbCN64PONob9bBTx+oP9WYa94HARRpzLOpR0AnlYx6hVCBNxdjvOcTilrjdwXZa\nHGIqs0wk0mpAuNrKo1eodhqmVZKh7nUWKVqkOXjFVisSIzXvfWeB9kH4uM+YaQnUZGjI4TQ6Jm/P\nE8BQt8Pw2XWNgQY3DoMYbRJF1g3JtIZ/wK2g+AYFo4CWBM2CeayU+RP7HWTOzld/GWAPS2hkCLfp\nkBvSsRgajnm/J5CMOhoDUpABCbvCSK4jq4MUOMxZIE+44bUclG6CESmQM8eCkJoB3Omlt8HBJxGe\ngJCEIuT7SslCfCVGsHxtUX2c7v5dudQEIcZOA3IVdPTi2I1sOFGN41aUw2doP75BZyVFDhw8B5fH\nDfS7bG6Y1gZdwFn3FbdFCjQyxWFGExfVK0MYN5j8h2OnRUMsM4hhKG8g70jHjDQJ7HJr0LDgBoy3\n5u2x9GM3YoF9x2GuDuXmHvZ/YZmoRa5Cipm0YxfuR3NFlzYW2/NkPoI/3gKMJlceJJnq+AVGWf6B\nQUIPetgH3ZsshkWWcXmXZCEpME2/Y39pOnhYUnpG7uATbacOYKIY8Tx4X4KA0NHnAYgTagLYlctQ\nabe/C3bnFEcWLncfeW7z5dGrqy5xp0MRHvvpX6rT+6qMFa5WyovGQoGr1TXgqHRhcnG21YeX+nAb\ntwllrmAXKT5++iKQEBzXvYu3T5t6w/CIzYNz8j4GddBrD5KrNTtiF0AEtSIyykH4dI58PLJPndyO\niT0ByJMYZseiGEiaT/4ROLsWCsbYX24zjKO1VQZ+4PU3X896IqMukt98PXpglBYx+sR+3PIE7cic\nVLBrtqWMU3I1nD4UVMwa1rFtignrc9r+aR676vE5NVo29t3fAj8GCobUJfgIL6YN2bpTxY/vTg3C\n03ZqB7DObtV89mgRYG+fz3+BHbLSQbXbOEnpXAEmv7+PytVs7jle0a89PEg7FYxDgr79l7p8AdwQ\ncjRh0p2OdsZOTMC5ZxdsPkWsuqjs6RyC5gjMywtwjz+HFU6ve+B7Bge/r7p8IiBvTqMeMmpbbIZ4\nwQclhz1K9gnzfvqMf9dZP27mw4L1/zHLF/+cST5hKgaaNh4+rH5iuXbXAHuEeRpwO3e4hd2h+axy\nZZw7VklKPEfd9VzcUboCxVbxpAigLNnv64GDUqoPvd/WZclH16QCC1nu43HsVGCmlvH8ek3Mnjj4\nICvExDZbUKzayevJ+4Qv1NFnO5Ow2Tf0c+c6NzErmd0mJfQFhTsOf/j442nYb0IwjgudHm9FHu83\nINwnMG6oiRM+pQ9T6Cld/nH10d66+AQ1GQEmIqzJ1iVsJxBs4gj9a/BARMg7sOVjdtyhL9ZycTOT\nlDqAbIpdnaD4W3yNmNiMAj//S8UrSmKDmSzSGmnFjjdmH67qbEHnI5UE/0qnCmPqECUEcPhvlcbX\nYkydlxh60txI0anbuNTeZ1HmmJwq6mR5cJ0shfy1jlPc1svVCnDBwyv9KuLhKQIl3nFOAyctKrmo\ny6TaAglileuzP0p/cBrOtzzRsYckH/MwATEh4kh8wmnjeybc0pDLBAf8Ew+cJO67sYOTrBDRc3if\n5TMcdUY5vlNGqnsuT4+D9gg5ABgBUJj/aKIjd/4bSa/cA0Zac5eoqCU9UrqRhpycMYQynmCkg3/T\nT58RXd4awPJ6GMvr3Vhet7G87sXy2sfyejeWrkjgwtqglZGEvsBV+1ijN9/GjTnxMKfxYs3tMPcT\nczwBoijMBtvIFKdAe5EtPt8jIKS2nQNnetjkzyScVFrmHALXIJH78RBLb+ZN8rrTmbJxdGeeinFn\nh3KI/L4HUUSpYnPqzvK2jKs48uTiOs3nILYW3WkDYCra6UQcK81uZ3OO7rYs1ejiPz//8PEDNkdQ\nI5PeQN1wEdGw4FTGz+PyWnWlqdn8FcCO1NJPxKFuGuDeIyNrPMoe//OOMjyQccQdZSjkogAPgLK6\nbDM39ykMW891kpR+zkzOh03HYpRVo2ZSA0Q6ubh4d/L5ZEQhv9H/jlyBMbT1pcPFx7SwDbr+m9vc\nUhz7gFDr2FZj/Nw5ebRuOOJhG2vAdjzf1oPDxxjs3jCBP8t/KqVgSYBQkQ7+PoVQj945/Kb9UIc+\nhhE7yX/uyRo7K/adI3uOi+KIft+xQ3sA/7AT9xgzIIB2ocZmZ9DslVtK35rXHRR1gD7S1/vNe832\n1qu9k/EpaifR4wA6lLXNht0/75yGjZ6S1ZvT788+nJ+9uTj5/IPjAqIr9/HTwaE4/fGLoPwQNGDs\nE8WYGlFhJhIYFrfQSSxz+K/GyM+yrjhIDL3enZ/rk5oNlrpg7jPanAiecxqThcZBM45C24c6/wgx\nSvUGyakponQdqjnC/dKG61lUrvOjqVRpjs5qrbdeulbM1JTRuXYE0geNXVIwCE4xg1eUxV6ZXWHJ\nJ4C6zqoHKW2jbWJISkHBTrqAc/5lTle8QCl1hidNZ63oL0MX1/AqUkWawE7udWhlSXfD9JiGcfRD\ne8DNePVpQKc7jKwb8qwHsUCr9Trkuen+k4bRfq0Bw4bB3sG8M0npIZSBjcltIsRGfJITynv4apde\nr4GCBcODvgoX0TBdArOPYXMt1glsIIAn12B9cZ8AEFor4R8IHDnRAZljdkb4drPc/3OoCeK3/vnn\nnuZVme7/TRSwCxKcShT2ENNt/A42PpGMxOnH95OQkaPUXPHnGssDwCGhAKgj7ZS/xCfos7GS6Urn\nl/j6AF9oP4Fet7qXsih1937XOEQJeKbG5DU8U4Z+IaZ7WdhTnMqkBRorHyxmWEHopiGYz574tJZp\nqvPdz96dn4LviMUYKEF87nYKw3G8BI/QdfIdVzi2QOEBO7wukY1LdGEpyWIZec16g9YoctTby8uw\n60SB4W6vThS4jBPloj3GaTMsU04QISvDWphlZdZutUEKu22I4igzzBKzi5ISWH2eAF6mpzFviWCv\nhKUeJgLPp8hJVpmMxTRZgB4FlQsKdQpCgsTFekbivDzjGHheKlMGBQ+LbZlcrys83YDOEZVgYPMf\nT76cn32gsoTDV43X3cOcU9oJTDmJ5BhTBDHaAV/ctD/kqtmsj2f1K4SB2gf+tF9xdsoxD9Dpx4FF\n/NN+xXVox85OkGcACqou2uKBGwCnW5/cNLLAuNp9MH7cFMAGMx8MxSKx7EUnerjz63KibdkyJRT3\nMS+fcICzKmxKmu7spqS1P3qOqwLPuZbj/kbwtk+2zGcOXW86b4aS39xPRwqxJBYw6rb2xzDZYZ2m\nejoOsw1xC21rtY39OXNipU67RYaiDEQcu50nLpP1K2HdnDnQS6PuABPfanSNJPaq8tHP2Uh7GB4m\nltidfYrpSGUsZAQwkiF17U8NPhRaBFAglP07diR3Onl+6M3RsQYPz1HrLrCNP4Ai1Lm4VOORl8CJ\n8OVXdhz5FaGFevRIhI6nkskst3li+Llbo1f50p9jrwxQEBPFroyzazlmWFMD8yuf2AMhWNK2Hqkv\nk6s+wyLOwDm9H+Dwrlz0H5wY1FqM0Gl3I7dtdeSTBxv0loLsJJgPvozvQPcXdTXmlRw4h+6tpRuG\n+jBEzD6Epvr0fRxiOObXcGB9GsC91NCw0MP7deDsktfGOLLWPraqmkL7QnuwixK2ZpWiYxmnONH4\notYLaAzucWPyR/apThSyv3vqxJyYkAXKg7sgvbmNdINWOGHE5UpcOZpQOnxTTaPfLeWtTMFogJEd\nY7XDL7baYRLZcEpvHthvxu5ie7Htx43eNJgdmXIMRIAKMXoDPbsQanDAFf5Z70Ti7Iac47d/PZuK\ntx9+gn/fyI9gQbHmcSr+BqOLt3kJ20ou2qXbFLCAo+L9Yl4rLIwkaHRCwRdPoLd24ZEXT0N0ZYlf\nUmIVpMBk2nLDt50AijxBKmRv3ANTLwG/TUFXywk1DmLfWoz0S6TBcI0L1oUc6JbRutqkaCac4Eiz\niJej87O3px8+nUbVPTK2+Tlygid+HhZORx8Nl3gMNhX2yaLGJ1eOv/yDTIsed1nvNU29DO41RQjb\nkcLuL/kmjdjuKeISAwai2C7zRYQtgdO5RK+6A/954mwrH7TvnnFFWOOJPjxrnHh8DNQQP7f1zwga\nUh89J+pJCMVzrBXjx9Go3wJPBUW04c/zm7ulGxDXRT80wTamzazHfnerAtdMZw3PchLhdWyXwdSB\npkmsNvOFWx/4MRP6IhRQbnS8IVdxnVZCZrCVor093UgBCt4t6WMJYVZhK0Z1bhSdSe/irXJyj2Il\nRjjqiIrq8RyGAoWw9f4xvmEzgLWGouYSaIBOiNK2KXe6qnqxZgnmnRBRryff4C7JXrnJL5rCPChv\njBeN/wrzRG+RMbqWlZ4/PxhPLl82CQ4UjF54Bb2LAoydyyZ7oDGL58+fj8S/Pez0MCpRmuc34I0B\n7F5n5ZxeDxhsPTm7Wl2H3ryJgB8Xa3kJD64oaG6f1xlFJHd0pQWR9q+BEeLahJYZTfuWOeZYXcnn\ny9yCz6m0wfhLltB1RxhRkqhs9a1RGG0y0kQsCYohjNUiSUKOTsB6bPMaa/Ewuqj5Rd4DxycIZopv\n8WCMd9hrdCwpb9Zyj0XnWIwI8IhSyng0KmamajTAc3ax1WjOzrKkaspIXrhnpvoKgMreYqT5SsR3\nKBlmHi1iOGWdHqs2jnW+k0W9jUq+uHTjjK1Z8uuHcAfWBknLVyuDKTw0i7TIZbkw5hRXLFkklQPG\ntEM43JkubyLrEwU9KI1AvZNVWFqJtm//YNfFxfQjHR/vm5F01lBlL8TimFCctfIKo6gZn6JPlpCW\nb82XCYzygaLZ2hPwxhJ/0LFUrCHw7u1wyxnrTN/HwWkbzSUdAIfugLIK0rKjpyOci8csfGbagVs0\n8EM7c8LtNimrOk5n+tqHGfppM3uervG0ZXA7CzyttwK+fQ6O777O2AfHwSTXID0x49ZUZByLlY5M\nRG5lmV+EVeTo5R2yrwQ+BVJmOTP10CZ2dGnZ1Raa6gRHR8UjqK9M8dKAQ26qZjoFJy7mU0pvMuUO\nA86zn29JV1eI78T41VQctnY+i2KLNzkBss+Woe+KUTeYihMMMHNs34shvjsW45dT8ccd0KOBAY4O\n3RHa+9gWhEEgr66eTMY0mRPZwr4U9of76hxG0PSM4+SqTf4umb4lKv1ri0pcIagTlV+2E5VbYw/u\nWzsfH8lwA4pjlcjl/jOFJNRIN7p5mMEJPyyg37M5Wrp2vKmoocK5OWxG7ho96GhE4zbbQUxRulZf\nXL+LuoYNp71zwKTJtFIV7S1zmMao0WsRFQDM+o7S8Bve7QLvNSlc/2zwiFUXAViwPREEXenJB2ZN\nw0ZQH3QEn6QBHmAUEeJhaqMoXMl6goiEdA8OMdFXrUNsh+N/d+bhEoOho9AOlt98vQtPVzB7izp6\nFnR3pYUnsra8ollu8+kPzHmM0tf1NwmMA6URHXBWzVWV5GYeYfYy30GT2yzmDV4GSSfTaBJT6bpN\nvJXmW7/Qj6HYASWTwVqAJ1Wv8CD5lu62PFGU9IZX1Hx9+HJqKoMZkJ7Aq+jVV/oKSOpmLj/wfeyp\n3rvBS93vMPoXB1hS+b3tq85uhqZ13LoLyh8spOjZJJpZOjSG6eE6kGbNYoF3JjbEZN/aXgDyHryd\nOfg55vLTHBw22JBGfei6GqOR3iHVNiDAD5uMIcl5VNdGkSLSu4RtSHnuUpxPFgXdq9+CYAgBOX8d\n8xt0BeviyIbYjE3Bk8+xm82Jn+qmt+6M7Qka2+om3DV97r9r7rpFYGdukhk6c/frS10a6L7DVrSP\nBhze0IR4VIlEo/H7jYlrB6Y6h6Y/Qq8/SH63E850wKw8BMZk7GC8n9hTY2/M/iZeuN8xIWyfL2R2\ny4l7nY3WtDs2o83xj/EUOPkFn9sbBiijaak5kPdLdMPejHNkZ/L6Ws1ivN1xRptsyufq7J7Mtu09\nXc4nY7U1uy28tAhAGG7Smbducj0wBuhKvmWa06Gc22kEDU1Jw04WskqWbBL01g7ARRwxpf4mEM9p\nxKNUYqBb1WVRwm54pO8i5jydvtTmBqgJ4G1idWNQNz2m+mpaUqyUHGZKkDlO20ryASKwEe+YhtnM\nvgNeedFcs5BMLTPIrN7IMq6aK4b8jIAENl3NCFR0jovrhOcaqWxxiYtYYnnDQQoDZPb7V7Cx9DbV\nO+5VmFht93h2oh465PuUKxscY2S4OLm31wu611ot6Wpr1zu0zRqus1cqwTKYu/JIR+pYGb/V93fx\nHbMcyUf/0uEfkHe38tLPQrfqjL1bi4bzzFUI3Qub8MYAMs599zB2OKB742JrA2zH9/WFZZSOhznQ\n2FJR++S9CqcZbdJEkDBh9IEIkl8U8MQIkgf/kREkfWsmGBqNj9YDvWUCD4SaWD24V1A2jAB9ZkAk\nPMBuXWBoTOXYTbovcpXcj+yF0qwrnUo+Yx6QI7t3kxEIvmpSuRnK3lVwuyJIvnTR4+/PP745OSda\nzC5O3v7HyfeUlIXHJS1b9egQW5bvM7X3vfRvN9ymE2n6Bm+w7bkhlmuYNITO+04OQg+E/nq1vgVt\nKzL39VCHTt1PtxMgvnvaLahDKrsXcscv0zUmbvpMK0870E85qdb8cjITzCNzUsfi0JzEmffN4YmW\n0U5seWjhnPTWrjrR/qq+BXQg7j2xSda0Anhmgvxlj0xMxYwNzLOD0v7ffFBmOFYbmht0QAoX0rnJ\nkS5xZFCV//8TKUHZxbi3Y0dxau/mpnZ8PKTspfN49ruQkSGIV+436s7PFfalTAeoEASs8PQ9hYyI\n0X/6QNWmHzxT4nKfCov3Udlc2V+4Ztq5/WuCSQaVve9LcYISH7NC41WduokDtk+nAzl9dBqVr5xK\nFtB8B0DnRjwVsDf6S6wQ51sRwsZRu2SYHEt01Jf1Ocij3XSwN7R6IfaHyk7dskshXg43XLYqO3WP\nQ+6hHuihalPc51hgzNIcqicV3xFkPs4UdMGX53zgGbre9sPX28uXR/ZwAfkdXzuKhLLJRo5hv3Sy\nMXdeKul0J2Ypp5Suh3s1JySsW1w5UNknGNrbdEpSBvY/Js+BIY289/0hM9PDu3p/1MbUst4RTEmM\nn6kJTcsp4tG42yeT7nQbtdUFwgVJjwDSUYEAC8F0dKOTILrlLO/xC70bnNd0Ha97whQ6UkHJYj5H\ncA/j+zX4tbtTIfGjujOKpj83aHOgXnIQbvYduNXEC4UMm4T21Bs+GHABuCa7v//LR/TvpjHa7oe7\n/Grb6lVvHSD7spj5iplBLRKZxxEYGdCbY9LWWC5hBB2voWno6DJUMzfkC3T8KJsWL9umDQY5szPt\nAVijEPwfucjncQ==\n\"\"\")\n\n##file activate.sh\nACTIVATE_SH = convert(\"\"\"\neJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+\nnfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI\nBXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D\nM/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m\nk9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU\nabMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws\nMYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD\nBbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7\n2rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ\n4H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN\nl/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz\nN3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS\nAd37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1\nD/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG\n+n8O9H8f5vsGOWXsL1+1k3g=\n\"\"\")\n\n##file activate.fish\nACTIVATE_FISH = convert(\"\"\"\neJydVW2P2jgQ/s6vmAZQoVpA9/WkqqJaTou0u6x2uZVOVWWZZEKsS+yc7UDpr+84bziQbauLxEvs\neXnsZ56ZIWwTYSAWKUJWGAs7hMJgBEdhEwiMKnSIsBNywUMrDtziPBYmCeBDrFUG7v8HmCTW5n8u\nFu7NJJim81Bl08EQTqqAkEupLOhCgrAQCY2hTU+DQVxIiqgkRNiEBphFEKy+kd1BaFvwFOUBuIxA\noy20BKtAKp3xFMo0QNtCK5mhtMEA6BmSpUELKo38TThwLfguRVNaiRgs0llnEoIR29zfstf18/bv\n5T17Wm7vAiiN3ONCzfbfwC3DtWXXDqHfAGX0q6z/bO82j3ebh1VwnbrduwTQbvwcRtesAfMGor/W\nL3fs6Xnz8LRlm9fV8/P61sM0LDNwCZjl9gSpCokJRzpryGQ5t8kNGFUt51QjOZGu0Mj35FlYlXEr\nyC09EVOp4lEXfF84Lz1qbhBsgl59vDedXI3rTV03xipduSgt9kLytI3XmBp3aV6MPoMQGNUU62T6\nuQdeefTy1Hfj10zVHg2pq8fXDoHBiOv94csfXwN49xECqWREy7pwukKfvxdMY2j23vXDPuuxxeE+\nJOdCOhxCE3N44B1ZeSLuZh8Mmkr2wEPAmPfKWHA2uxIRjEopdbQYjDz3BWOf14/scfmwoki1eQvX\nExBdF60Mqh+Y/QcX4uiH4Amwzx79KOVFtbL63sXJbtcvy8/3q5rupmO5CnE91wBviQAhjUUegYpL\nvVEbpLt2/W+PklRgq5Ku6mp+rpMhhCo/lXthQTxJ2ysO4Ka0ad97S7VT/n6YXus6fzk3fLnBZW5C\nKDC6gSO62QDqgFqLCCtPmjegjnLeAdArtSE8VYGbAJ/aLb+vnQutFhk768E9uRbSxhCMzdgEveYw\nIZ5ZqFKl6+kz7UR4U+buqQZXu9SIujrAfD7f0FXpozB4Q0gwp31H9mVTZGGC4b871/wm7lvyDLu1\nFUyvTj/yvD66k3UPTs08x1AQQaGziOl0S1qRkPG9COtBTSTWM9NzQ4R64B+Px/l3tDzCgxv5C6Ni\ne+QaF9xFWrxx0V/G5uvYQOdiZzvYpQUVQSIsTr1TTghI33GnPbTA7/GCqcE3oE3GZurq4HeQXQD6\n32XS1ITj/qLjN72ob0hc5C9bzw8MhfmL\n\"\"\")\n\n##file activate.csh\nACTIVATE_CSH = convert(\"\"\"\neJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc\nne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw\ntQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D\nr/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW\nVPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs\ncSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V\ntkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g\nQhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k\nTXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa\nn1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H\n37CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD\n\"\"\")\n\n##file activate.bat\nACTIVATE_BAT = convert(\"\"\"\neJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT\nPbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt\nr7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X\n0QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw==\n\"\"\")\n\n##file deactivate.bat\nDEACTIVATE_BAT = convert(\"\"\"\neJxzSE3OyFfIT0vj4ipOLVEI8wwKCXX0iXf1C7Pl4spMU0hJTcvMS01RiPf3cYmHyQYE+fsGhCho\ncCkAAUibEkTEVhWLMlUlLk6QGixStlyaeCyJDPHw9/Pw93VFsQguim4ZXAJoIUw5DhX47XUM8UCx\nEchHtwsohN1bILUgw61c/Vy4AJYPYm4=\n\"\"\")\n\n##file activate.ps1\nACTIVATE_PS = convert(\"\"\"\neJylWdmO41hyfW+g/0FTU7C7IXeJIqmtB/3AnZRIStxF2kaBm7gv4ipyMF/mB3+Sf8GXVGVl1tLT\n43ECSqR4b5wbETeWE8z/+a///vNCDaN6cYtSf5G1dbNw/IVXNIu6aCvX9xa3qsgWl0IJ/7IYinbh\n2nkOVqs2X0TNjz/8eeFFle826fBhQRaLBkD9uviw+LCy3Sbq7Mb/UNbrH3+YNtLcVaB+Xbipb+eL\ntly0eVsD/M6u6g8//vC+dquobH5VWU75eMFUdvHb4n02RHlXuHYTFfmHbHCLLLNz70NpN+GrBI4p\n1EeSk4FAXaZR88u0vPip8usi7fznt3fvP+OuPnx49/Pil4td+XnzigIAPoqYQH2J8v4z+C+8b98m\nQ25t7k76LIK0cOz0V89/MXXx0+Lf6z5q3PA/F+/FIif9uqnaadFf/PzXSXYBfqIb2NeApecJwPzI\ndlL/149nnvyoc7KqYfzTAT8v/voUmX7e+3n364tffl/oVaDyswKY/7J18e6bve8Wv9RuUfqfLHmK\n/u139Hwx+9ePRep97KKqae30YwmCo2y+0vTz1k+rv7159B3pb1SOGj97Pe8/flfkC1Vn/7xYR4n6\nlypNEGDDV5f7lcjil3S+4++p881Wv6qKyn5GQg1yJwcp4BZ5E+Wt/z1P/umbiHir4J8Xip/eFt6n\n9T/9gU9eY+7zUX97Jlmb136ziKrKT/3OzpvP8VX/+MObSP0lL3LvVZlJ9v1b8357jXyw8rXxYPXN\n11n4UzJ8G8S/vUbuJ6RPj999DbtS5kys//JusXwrNLnvT99cFlBNwXCe+niRz8JF/ezNr9Pze+H6\n18W7d5PPvozW7+387Zto/v4pL8BvbxTzvIW9KCv/Fj0WzVQb/YXbVlPZWTz3/9vCaRtQbPN/Bb+j\n2rUrDxTVD68gfQXu/ZewAFX53U/vf/rD2P3558W7+W79Po1y/xXoX/6RFHyNIoVjgAG4H0RTcAe5\n3bSVv3DSwk2mZYHjFB8zj6fC4sLOFTHJJQrwzFYJgso0ApOoBzFiRzzQKjIQCCbQMIFJGCKqGUyS\n8AkjiF2wTwmMEbcEUvq8Nj+X0f4YcCQmYRiOY7eRbAJDqzm1chOoNstbJ8oTBhZQ2NcfgaB6QjLp\nU4+SWFjQGCZpyqby8V4JkPGs9eH1BscXIrTG24QxXLIgCLYNsIlxSYLA6SjAeg7HAg4/kpiIB8k9\nTCLm0EM4gKIxEj8IUj2dQeqSxEwYVH88qiRlCLjEYGuNIkJB1BA5dHOZdGAoUFk54WOqEojkuf4Q\nIg3WY+96TDlKLicMC04h0+gDCdYHj0kz2xBDj9ECDU5zJ0tba6RKgXBneewhBG/xJ5m5FX+WSzsn\nwnHvKhcOciw9NunZ0BUF0n0IJAcJMdcLqgQb0zP19dl8t9PzmMBjkuIF7KkvHgqEovUPOsY0PBB1\nHCtUUhch83qEJPjQcNQDsgj0cRqx2ZbnnlrlUjE1EX2wFJyyDa/0GLrmKDEFepdWlsbmVU45Wiwt\neFM6mfs4kxg8yc4YmKDy67dniLV5FUeO5AKNPZaOQQ++gh+dXE7dbJ1aTDr7S4WPd8sQoQkDyODg\nXnEu/voeKRAXZxB/e2xaJ4LTFLPYEJ15Ltb87I45l+P6OGFA5F5Ix8A4ORV6M1NH1uMuZMnmFtLi\nVpYed+gSq9JDBoHc05J4OhKetrk1p0LYiKipxLMe3tYS7c5V7O1KcPU8BJGdLfcswhoFCSGQqJ8f\nThyQKy5EWFtHVuNhvTnkeTc8JMpN5li3buURh0+3ZGuzdwM55kon+8urbintjdQJf9U1D0ah+hNh\ni1XNu4fSKbTC5AikGEaj0CYM1dpuli7EoqUt7929f1plxGGNZnixFSFP2qzhlZMonu2bB9OWSqYx\nVuHKWNGJI8kqUhMTRtk0vJ5ycZ60JlodlmN3D9XiEj/cG2lSt+WV3OtMgt1Tf4/Z+1BaCus740kx\nNvj78+jMd9tq537Xz/mNFyiHb0HdwHytJ3uQUzKkYhK7wjGtx3oKX43YeYoJVtqDSrCnQFzMemCS\n2bPSvP+M4yZFi/iZhAjL4UOeMfa7Ex8HKBqw4umOCPh+imOP6yVTwG2MplB+wtg97olEtykNZ6wg\nFJBNXSTJ3g0CCTEEMdUjjcaBDjhJ9fyINXgQVHhA0bjk9lhhhhOGzcqQSxYdj3iIN2xGEOODx4qj\nQ2xikJudC1ujCVOtiRwhga5nPdhe1gSa649bLJ0wCuLMcEYIeSy25YcDQHJb95nfowv3rQnin0fE\nzIXFkM/EwSGxvCCMgEPNcDp/wph1gMEa8Xd1qAWOwWZ/KhjlqzgisBpDDDXz9Cmov46GYBKHC4zZ\n84HJnXoTxyWNBbXV4LK/r+OEwSN45zBp7Cub3gIYIvYlxon5BzDgtPUYfXAMPbENGrI+YVGSeTQ5\ni8NMB5UCcC+YRGIBhgs0xhAGwSgYwywpbu4vpCSTdEKrsy8osXMUnHQYenQHbOBofLCNNTg3CRRj\nA1nXY2MZcjnXI+oQ2Zk+561H4CqoW61tbPKv65Y7fqc3TDUF9CA3F3gM0e0JQ0TPADJFJXVzphpr\n2FzwAY8apGCju1QGOiUVO5KV6/hKbtgVN6hRVwpRYtu+/OC6w2bCcGzZQ8NCc4WejNEjFxOIgR3o\nQqR1ZK0IaUxZ9nbL7GWJIjxBARUhAMnYrq/S0tVOjzlOSYRqeIZxaSaOBX5HSR3MFekOXVdUPbjX\nnru61fDwI8HRYPUS7a6Inzq9JLjokU6P6OzT4UCH+Nha+JrU4VqEo4rRHQJhVuulAnvFhYz5NWFT\naS/bKxW6J3e46y4PLagGrCDKcq5B9EmP+s1QMCaxHNeM7deGEV3WPn3CeKjndlygdPyoIcNaL3dd\nbdqPs47frcZ3aNWQ2Tk+rjFR01Ul4XnQQB6CSKA+cZusD0CP3F2Ph0e78baybgioepG12luSpFXi\nbHbI6rGLDsGEodMObDG7uyxfCeU+1OiyXYk8fnGu0SpbpRoEuWdSUlNi5bd9nBxYqZGrq7Qa7zV+\nVLazLcelzzP9+n6+xUtWx9OVJZW3gk92XGGkstTJ/LreFVFF2feLpXGGuQqq6/1QbWPyhJXIXIMs\n7ySVlzMYqoPmnmrobbeauMIxrCr3sM+qs5HpwmmFt7SM3aRNQWpCrmeAXY28EJ9uc966urGKBL9H\n18MtDE5OX97GDOHxam11y5LCAzcwtkUu8wqWI1dWgHyxGZdY8mC3lXzbzncLZ2bIUxTD2yW7l9eY\ngBUo7uj02ZI3ydUViL7oAVFag37JsjYG8o4Csc5R7SeONGF8yZP+7xxi9scnHvHPcogJ44VH/LMc\nYu6Vn3jEzCFw9Eqq1ENQAW8aqbUwSiAqi+nZ+OkZJKpBL66Bj8z+ATqb/8qDIJUeNRTwrI0YrVmb\n9FArKVEbCWUNSi8ipfVv+STgkpSsUhcBg541eeKLoBpLGaiHTNoK0r4nn3tZqrcIULtq20Df+FVQ\nSa0MnWxTugMuzD410sQygF4qdntbswiJMqjs014Irz/tm+pd5oygJ0fcdNbMg165Pqi7EkYGAXcB\ndwxioCDA3+BY9+JjuOmJu/xyX2GJtaKSQcOZxyqFzTaa6/ot21sez0BtKjirROKRm2zuai02L0N+\nULaX8H5P6VwsGPbYOY7sAy5FHBROMrMzFVPYhFHZ7M3ZCZa2hsT4jGow6TGtG8Nje9405uMUjdF4\nPtKQjw6yZOmPUmO8LjFWS4aPCfE011N+l3EdYq09O3iQJ9a01B3KXiMF1WmtZ+l1gmyJ/ibAHZil\nvQzdOl6g9PoSJ4TM4ghTnTndEVMOmsSSu+SCVlGCOLQRaw9oLzamSWP62VuxPZ77mZYdfTRGuNBi\nKyhZL32S2YckO/tU7y4Bf+QKKibQSKCTDWPUwWaE8yCBeL5FjpbQuAlb53mGX1jptLeRotREbx96\ngnicYz0496dYauCjpTCA4VA0cdLJewzRmZeTwuXWD0talJsSF9J1Pe72nkaHSpULgNeK1+o+9yi0\nYpYwXZyvaZatK2eL0U0ZY6ekZkFPdC8JTF4Yo1ytawNfepqUKEhwznp6HO6+2l7L2R9Q3N49JMIe\nZ+ax1mVaWussz98QbNTRPo1xu4W33LJpd9H14dd66ype7UktfEDi3oUTccJ4nODjwBKFxS7lYWiq\nXoHu/b7ZVcK5TbRD0F/2GShg2ywwUl07k4LLqhofKxFBNd1grWY+Zt/cPtacBpV9ys2z1moMLrT3\nW0Elrjtt5y/dvDQYtObYS97pqj0eqmwvD3jCPRqamGthLiF0XkgB6IdHLBBwDGPiIDh7oPaRmTrN\ntYA/yQKFxRiok+jM6ciJq/ZgiOi5+W4DEmufPEubeSuYJaM3/JHEevM08yJAXUQwb9LS2+8FOfds\nFfOe3Bel6EDSjIEIKs4o9tyt67L1ylQlzhe0Q+7ue/bJnWMcD3q6wDSIQi8ThnRM65aqLWesi/ZM\nxhHmQvfKBbWcC194IPjbBLYR9JTPITbzwRcu+OSFHDHNSYCLt29sAHO6Gf0h/2UO9Xwvhrjhczyx\nYgz6CqP4IwxQj5694Q1Pe2IR+KF/yy+5PvCL/vgwv5mPp9n4kx7fnY/nmV++410qF/ZVCMyv5nAP\npkeOSce53yJ6ahF4aMJi52by1HcCj9mDT5i+7TF6RoPaLL+cN1hXem2DmX/mdIbeeqwQOLD5lKO/\n6FM4x77w6D5wMx3g0IAfa2D/pgY9a7bFQbinLDPz5dZi9ATIrd0cB5xfC0BfCCZO7TKP0jQ2Meih\nnRXhkA3smTAnDN9IW2vA++lsgNuZ2QP0UhqyjUPrDmgfWP2bWWiKA+YiEK7xou8cY0+d3/bk0oHR\nQLrq4KzDYF/ljQDmNhBHtkVNuoDey6TTeaD3SHO/Bf4d3IwGdqQp6FuhmwFbmbQBssDXVKDBYOpk\nJy7wxOaSRwr0rDmGbsFdCM+7XU/84JPu3D/gW7QXgzlvbjixn99/8CpWFUQWHFEz/RyXvzNXTTOd\nOXLNNFc957Jn/YikNzEpUdRNxXcC6b76ccTwMGoKj5X7c7TvHFgc3Tf4892+5A+iR+D8OaaE6ACe\ngdgHcyCoPm/xiDCWP+OZRjpzfj5/2u0i4qQfmIEOsTV9Hw6jZ3Agnh6hiwjDtGYxWvt5TiWEuabN\n77YCyRXwO8P8wdzG/8489KwfFBZWI6Vvx76gmlOc03JI1HEfXYZEL4sNFQ3+bqf7e2hdSWQknwKF\nICJjGyDs3fdmnnxubKXebpQYLjPgEt9GTzKkUgTvOoQa1J7N3nv4sR6uvYFLhkXZ+pbCoU3K9bfq\ngF7W82tNutRRZExad+k4GYYsCfmEbvizS4jsRr3fdzqjEthpEwm7pmN7OgVzRbrktjrFw1lc0vM8\nV7dyTJ71qlsd7v3KhmHzeJB35pqEOk2pEe5uPeCToNkmedmxcKbIj+MZzjFSsvCmimaMQB1uJJKa\n+hoWUi7aEFLvIxKxJavqpggXBIk2hr0608dIgnfG5ZEprqmH0b0YSy6jVXTCuIB+WER4d5BPVy9Q\nM4taX0RIlDYxQ2CjBuq78AAcHQf5qoKP8BXHnDnd/+ed5fS+csL4g3eWqECaL+8suy9r8hx7c+4L\nEegEWdqAWN1w1NezP34xsxLkvRRI0DRzKOg0U+BKfQY128YlYsbwSczEg2LqKxRmcgiwHdhc9MQJ\nIwKQHlgBejWeMGDYYxTOQUiJOmIjJbzIzHH6lAMP+y/fR0v1g4wx4St8fcqTt3gz5wc+xXFZZ3qI\nJpXI5iJk7xmNL2tYsDpcqu0375Snd5EKsIvg8u5szTOyZ4v06Ny2TZXRpHUSinh4IFp8Eoi7GINJ\n02lPJnS/9jSxolJwp2slPMIEbjleWw3eec4XaetyEnSSqTPRZ9fVA0cPXMqzrPYQQyrRux3LaAh1\nwujbgcObg1nt4iiJ5IMbc/WNPc280I2T4nTkdwG8H6iS5xO2WfsFsruBwf2QkgZlb6w7om2G65Lr\nr2Gl4dk63F8rCEHoUJ3fW+pU2Srjlmcbp+JXY3DMifEI22HcHAvT7zzXiMTr7VbUR5a2lZtJkk4k\n1heZZFdru8ucCWMTr3Z4eNnjLm7LW7rcN7QjMpxrsCzjxndeyFUX7deIs3PQkgyH8k6luI0uUyLr\nva47TBjM4JmNHFzGPcP6BV6cYgQy8VQYZe5GmzZHMxyBYhGiUdekZQ/qwyxC3WGylQGdUpSf9ZCP\na7qPdJd31fPRC0TOgzupO7nLuBGr2A02yuUQwt2KQG31sW8Gd9tQiHq+hPDt4OzJuY4pS8XRsepY\ntsd7dVEfJFmc15IYqwHverrpWyS1rFZibDPW1hUUb+85CGUzSBSTK8hpvee/ZxonW51TUXekMy3L\nuy25tMTg4mqbSLQQJ+skiQu2toIfBFYrOWql+EQipgfT15P1aq6FDK3xgSjIGWde0BPftYchDTdM\ni4QdudHFkN0u6fSKiT09QLv2mtSblt5nNzBR6UReePNs+khE4rHcXuoK21igUKHl1c3MXMgPu7y8\nrKQDxR6N/rffXv+lROXet/9Q+l9I4D1U\n\"\"\")\n\n##file distutils-init.py\nDISTUTILS_INIT = convert(\"\"\"\neJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E\nUXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB\nC4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss\naG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT\n0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9\noh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE\nNFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c\nf/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8\np7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk\nvUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw\nhUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh\ncbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw\nbuHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ\n5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh\ngGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC\n1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL\nMlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6\n84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK\n0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO\nkMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG\nqgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h\nkzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9\nGBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ=\n\"\"\")\n\n##file distutils.cfg\nDISTUTILS_CFG = convert(\"\"\"\neJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH\nxJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg\n9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=\n\"\"\")\n\n##file activate_this.py\nACTIVATE_THIS = convert(\"\"\"\neJyNU01v2zAMvetXEB4K21jnDOstQA4dMGCHbeihlyEIDMWmE62yJEiKE//7kXKdpEWLzYBt8evx\nkRSzLPs6wiEoswM8YdMpjUXcq1Dz6RZa1cSiTkJdr86GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe\n5a3p0cRKiEe2NtLAFikftnDco0ko/SFEVgEZ8aRCZDIPY9xbA8pE9M4jfW/B2CjiHq9zbJVZuOQq\nsiwTIvpxKYCembPAU4Muwi/Z4zfvrZ/MXipKeB8C+qisSZYiWfjJfs+0/MFMdWn1hJcO5U7G/SLa\nxVx8zU6VG/PXLXvfsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCJN9dzKaoexyB/uH79TnjwvxcW0ntSb\nyZ8jq1Z5Q1UXsyy3gf9nbjTEj7NzQMfCJa/YSmrQ+2D/BqfiOi6sclrGzvoeVivIj8rcfcmnIQRF\n7XCyeZI7DFe5/lhlCs5PRf5QW66VXT/NrlQ46oD/D6InkOmi3IQcbhKxAX2g4a+Xd5s3UtCtG2py\nm8eg6WYWqR6SL5OjKMGfSrYt/6kxxQtOpeAgj1LXBNmpE2ElmCSIy5H0zFd8gJ924HWijWhb2hRC\n6wNEm1QdDZtuSZcEprIUBo/XRNcbQe1OUbQ/r3hPTaPJJDNtFLu8KHV5XoNr3Eo6h6YtOKw8e8yw\nVF5PnJ+ts3a9/Mz38RpG/AUSzYUW\n\"\"\")\n\nMH_MAGIC = 0xfeedface\nMH_CIGAM = 0xcefaedfe\nMH_MAGIC_64 = 0xfeedfacf\nMH_CIGAM_64 = 0xcffaedfe\nFAT_MAGIC = 0xcafebabe\nBIG_ENDIAN = '>'\nLITTLE_ENDIAN = '<'\nLC_LOAD_DYLIB = 0xc\nmaxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')\n\n\nclass fileview(object):\n    \"\"\"\n    A proxy for file-like objects that exposes a given view of a file.\n    Modified from macholib.\n    \"\"\"\n\n    def __init__(self, fileobj, start=0, size=maxint):\n        if isinstance(fileobj, fileview):\n            self._fileobj = fileobj._fileobj\n        else:\n            self._fileobj = fileobj\n        self._start = start\n        self._end = start + size\n        self._pos = 0\n\n    def __repr__(self):\n        return '<fileview [%d, %d] %r>' % (\n            self._start, self._end, self._fileobj)\n\n    def tell(self):\n        return self._pos\n\n    def _checkwindow(self, seekto, op):\n        if not (self._start <= seekto <= self._end):\n            raise IOError(\"%s to offset %d is outside window [%d, %d]\" % (\n                op, seekto, self._start, self._end))\n\n    def seek(self, offset, whence=0):\n        seekto = offset\n        if whence == os.SEEK_SET:\n            seekto += self._start\n        elif whence == os.SEEK_CUR:\n            seekto += self._start + self._pos\n        elif whence == os.SEEK_END:\n            seekto += self._end\n        else:\n            raise IOError(\"Invalid whence argument to seek: %r\" % (whence,))\n        self._checkwindow(seekto, 'seek')\n        self._fileobj.seek(seekto)\n        self._pos = seekto - self._start\n\n    def write(self, bytes):\n        here = self._start + self._pos\n        self._checkwindow(here, 'write')\n        self._checkwindow(here + len(bytes), 'write')\n        self._fileobj.seek(here, os.SEEK_SET)\n        self._fileobj.write(bytes)\n        self._pos += len(bytes)\n\n    def read(self, size=maxint):\n        assert size >= 0\n        here = self._start + self._pos\n        self._checkwindow(here, 'read')\n        size = min(size, self._end - here)\n        self._fileobj.seek(here, os.SEEK_SET)\n        bytes = self._fileobj.read(size)\n        self._pos += len(bytes)\n        return bytes\n\n\ndef read_data(file, endian, num=1):\n    \"\"\"\n    Read a given number of 32-bits unsigned integers from the given file\n    with the given endianness.\n    \"\"\"\n    res = struct.unpack(endian + 'L' * num, file.read(num * 4))\n    if len(res) == 1:\n        return res[0]\n    return res\n\n\ndef mach_o_change(path, what, value):\n    \"\"\"\n    Replace a given name (what) in any LC_LOAD_DYLIB command found in\n    the given binary with a new name (value), provided it's shorter.\n    \"\"\"\n\n    def do_macho(file, bits, endian):\n        # Read Mach-O header (the magic number is assumed read by the caller)\n        cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)\n        # 64-bits header has one more field.\n        if bits == 64:\n            read_data(file, endian)\n        # The header is followed by ncmds commands\n        for n in range(ncmds):\n            where = file.tell()\n            # Read command header\n            cmd, cmdsize = read_data(file, endian, 2)\n            if cmd == LC_LOAD_DYLIB:\n                # The first data field in LC_LOAD_DYLIB commands is the\n                # offset of the name, starting from the beginning of the\n                # command.\n                name_offset = read_data(file, endian)\n                file.seek(where + name_offset, os.SEEK_SET)\n                # Read the NUL terminated string\n                load = file.read(cmdsize - name_offset).decode()\n                load = load[:load.index('\\0')]\n                # If the string is what is being replaced, overwrite it.\n                if load == what:\n                    file.seek(where + name_offset, os.SEEK_SET)\n                    file.write(value.encode() + '\\0'.encode())\n            # Seek to the next command\n            file.seek(where + cmdsize, os.SEEK_SET)\n\n    def do_file(file, offset=0, size=maxint):\n        file = fileview(file, offset, size)\n        # Read magic number\n        magic = read_data(file, BIG_ENDIAN)\n        if magic == FAT_MAGIC:\n            # Fat binaries contain nfat_arch Mach-O binaries\n            nfat_arch = read_data(file, BIG_ENDIAN)\n            for n in range(nfat_arch):\n                # Read arch header\n                cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)\n                do_file(file, offset, size)\n        elif magic == MH_MAGIC:\n            do_macho(file, 32, BIG_ENDIAN)\n        elif magic == MH_CIGAM:\n            do_macho(file, 32, LITTLE_ENDIAN)\n        elif magic == MH_MAGIC_64:\n            do_macho(file, 64, BIG_ENDIAN)\n        elif magic == MH_CIGAM_64:\n            do_macho(file, 64, LITTLE_ENDIAN)\n\n    assert(len(what) >= len(value))\n    do_file(open(path, 'r+b'))\n\n\nif __name__ == '__main__':\n    main()\n\n## TODO:\n## Copy python.exe.manifest\n## Monkeypatch distutils.sysconfig\n"
  },
  {
    "path": "scripts/pylintrc",
    "content": "# lint Python modules using external checkers.\n# \n# This is the main checker controling the other ones and the reports\n# generation. It is itself both a raw checker and an astng checker in order\n# to:\n# * handle message activation / deactivation at the module level\n# * handle some basic but necessary stats'data (number of classes, methods...)\n# \n[MASTER]\n\n# Specify a configuration file.\n#rcfile=\n\n# Profiled execution.\nprofile=no\n\n# Add <file or directory> to the black list. It should be a base name, not a\n# path. You may set this option multiple times.\nignore=.svn\n\n# Pickle collected data for later comparisons.\npersistent=yes\n\n# Set the cache size for astng objects.\ncache-size=500\n\n# List of plugins (as comma separated values of python modules names) to load,\n# usually to register additional checkers.\nload-plugins=\n\n\n[MESSAGES CONTROL]\n\n# Enable only checker(s) with the given id(s). This option conflict with the\n# disable-checker option\n#enable-checker=\n\n# Enable all checker(s) except those with the given id(s). This option conflict\n# with the disable-checker option\n#disable-checker=\n\n# Enable all messages in the listed categories.\n#enable-msg-cat=\n\n# Disable all messages in the listed categories.\n#disable-msg-cat=\n\n# Enable the message(s) with the given id(s).\n#enable-msg=\n\n# Disable the message(s) with the given id(s).\ndisable-msg=C0323,W0142,C0301,C0103,C0111,E0213,C0302,C0203,W0703,R0201\n\n\n[REPORTS]\n\n# set the output format. Available formats are text, parseable, colorized and\n# html\noutput-format=colorized\n\n# Include message's id in output\ninclude-ids=yes\n\n# Put messages in a separate file for each module / package specified on the\n# command line instead of printing them on stdout. Reports (if any) will be\n# written in a file name \"pylint_global.[txt|html]\".\nfiles-output=no\n\n# Tells wether to display a full report or only the messages\nreports=yes\n\n# Python expression which should return a note less than 10 (10 is the highest\n# note).You have access to the variables errors warning, statement which\n# respectivly contain the number of errors / warnings messages and the total\n# number of statements analyzed. This is used by the global evaluation report\n# (R0004).\nevaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)\n\n# Add a comment according to your evaluation note. This is used by the global\n# evaluation report (R0004).\ncomment=no\n\n# Enable the report(s) with the given id(s).\n#enable-report=\n\n# Disable the report(s) with the given id(s).\n#disable-report=\n\n\n# checks for\n# * unused variables / imports\n# * undefined variables\n# * redefinition of variable from builtins or from an outer scope\n# * use of variable before assigment\n# \n[VARIABLES]\n\n# Tells wether we should check for unused import in __init__ files.\ninit-import=no\n\n# A regular expression matching names used for dummy variables (i.e. not used).\ndummy-variables-rgx=_|dummy\n\n# List of additional names supposed to be defined in builtins. Remember that\n# you should avoid to define new builtins when possible.\nadditional-builtins=\n\n\n# try to find bugs in the code using type inference\n# \n[TYPECHECK]\n\n# Tells wether missing members accessed in mixin class should be ignored. A\n# mixin class is detected if its name ends with \"mixin\" (case insensitive).\nignore-mixin-members=yes\n\n# When zope mode is activated, consider the acquired-members option to ignore\n# access to some undefined attributes.\nzope=no\n\n# List of members which are usually get through zope's acquisition mecanism and\n# so shouldn't trigger E0201 when accessed (need zope=yes to be considered).\nacquired-members=REQUEST,acl_users,aq_parent\n\n\n# checks for :\n# * doc strings\n# * modules / classes / functions / methods / arguments / variables name\n# * number of arguments, local variables, branchs, returns and statements in\n# functions, methods\n# * required module attributes\n# * dangerous default values as arguments\n# * redefinition of function / method / class\n# * uses of the global statement\n# \n[BASIC]\n\n# Required attributes for module, separated by a comma\nrequired-attributes=\n\n# Regular expression which should only match functions or classes name which do\n# not require a docstring\nno-docstring-rgx=__.*__\n\n# Regular expression which should only match correct module names\nmodule-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$\n\n# Regular expression which should only match correct module level names\nconst-rgx=(([A-Z_][A-Z1-9_]*)|(__.*__))$\n\n# Regular expression which should only match correct class names\nclass-rgx=[A-Z_][a-zA-Z0-9]+$\n\n# Regular expression which should only match correct function names\nfunction-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match correct method names\nmethod-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match correct instance attribute names\nattr-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match correct argument names\nargument-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match correct variable names\nvariable-rgx=[a-z_][a-z0-9_]{2,30}$\n\n# Regular expression which should only match correct list comprehension /\n# generator expression variable names\ninlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$\n\n# Good variable names which should always be accepted, separated by a comma\ngood-names=i,j,k,ex,Run,_\n\n# Bad variable names which should always be refused, separated by a comma\nbad-names=foo,bar,baz,toto,tutu,tata\n\n# List of builtins function names that should not be used, separated by a comma\nbad-functions=apply,input\n\n\n# checks for sign of poor/misdesign:\n# * number of methods, attributes, local variables...\n# * size, complexity of functions, methods\n# \n[DESIGN]\n\n# Maximum number of arguments for function / method\nmax-args=12\n\n# Maximum number of locals for function / method body\nmax-locals=30\n\n# Maximum number of return / yield for function / method body\nmax-returns=12\n\n# Maximum number of branch for function / method body\nmax-branchs=30\n\n# Maximum number of statements in function / method body\nmax-statements=60\n\n# Maximum number of parents for a class (see R0901).\nmax-parents=7\n\n# Maximum number of attributes for a class (see R0902).\nmax-attributes=20\n\n# Minimum number of public methods for a class (see R0903).\nmin-public-methods=0\n\n# Maximum number of public methods for a class (see R0904).\nmax-public-methods=20\n\n\n# checks for\n# * external modules dependencies\n# * relative / wildcard imports\n# * cyclic imports\n# * uses of deprecated modules\n# \n[IMPORTS]\n\n# Deprecated modules which should not be used, separated by a comma\ndeprecated-modules=regsub,string,TERMIOS,Bastion,rexec\n\n# Create a graph of every (i.e. internal and external) dependencies in the\n# given file (report R0402 must not be disabled)\nimport-graph=\n\n# Create a graph of external dependencies in the given file (report R0402 must\n# not be disabled)\next-import-graph=\n\n# Create a graph of internal dependencies in the given file (report R0402 must\n# not be disabled)\nint-import-graph=\n\n\n# checks for :\n# * methods without self as first argument\n# * overridden methods signature\n# * access only to existant members via self\n# * attributes not defined in the __init__ method\n# * supported interfaces implementation\n# * unreachable code\n# \n[CLASSES]\n\n# List of interface methods to ignore, separated by a comma. This is used for\n# instance to not check methods defines in Zope's Interface base class.\nignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by\n\n# List of method names used to declare (i.e. assign) instance attributes.\ndefining-attr-methods=__init__,__new__,setUp\n\n\n# checks for similarities and duplicated code. This computation may be\n# memory / CPU intensive, so you should disable it if you experiments some\n# problems.\n# \n[SIMILARITIES]\n\n# Minimum lines number of a similarity.\nmin-similarity-lines=10\n\n# Ignore comments when computing similarities.\nignore-comments=yes\n\n# Ignore docstrings when computing similarities.\nignore-docstrings=yes\n\n\n# checks for:\n# * warning notes in the code like FIXME, XXX\n# * PEP 263: source code with non ascii character but no encoding declaration\n# \n[MISCELLANEOUS]\n\n# List of note tags to take in consideration, separated by a comma.\nnotes=FIXME,XXX,TODO\n\n\n# checks for :\n# * unauthorized constructions\n# * strict indentation\n# * line length\n# * use of <> instead of !=\n# \n[FORMAT]\n\n# Maximum number of characters on a single line.\nmax-line-length=90\n\n# Maximum number of lines in a module\nmax-module-lines=1000\n\n# String used as indentation unit. This is usually \" \" (4 spaces) or \"\\t\" (1\n# tab).\nindent-string='    '\n"
  },
  {
    "path": "setup.cfg",
    "content": "[egg_info]\ntag_build = dev\ntag_date = true\n\n[bdist_wheel]\nuniversal = 1\n\n[nosetests]\n# constrain nosetests to the tests dir for now: 0.10 ends up\n# overwriting pylons.config with the actual module\nwhere=tests\ncover-package=pylons\ncover-erase=True\nwith-doctest=True\nnocapture=1\n"
  },
  {
    "path": "setup.py",
    "content": "import sys\n\ntry:\n    from setuptools import setup, find_packages\nexcept ImportError:\n    from ez_setup import use_setuptools\n    use_setuptools()\n    from setuptools import setup, find_packages\n\nversion = '1.0.3'\n\ntests_require = ['nose', 'Jinja2>=2.2.1']\nif not sys.platform.startswith('java'):\n    tests_require.extend(['Genshi', 'coverage>=2.85'])\n\nsetup(\n    name=\"Pylons\",\n    version=version,\n    description='Pylons Web Framework',\n    long_description=\"\"\"\nPylons\n======\n\nThe Pylons web framework is designed for building web applications and\nsites in an easy and concise manner. They can range from as small as a\nsingle Python module, to a substantial directory layout for larger and\nmore complex web applications.\n\nPylons comes with project templates that help boot-strap a new web\napplication project, or you can start from scratch and set things up\nexactly as desired.\n\n\nExample `Hello World`\n---------------------\n\n..\n\n    from paste.httpserver import serve\n    from pylons import Configurator, Response\n\n    class Hello(object):\n        def __init__(self, request):\n            self.request = request\n\n        def index(self):\n            return Response(body=\"Hello World!\")\n\n\n    if __name__ == '__main__':\n        config = Configurator()\n        config.begin()\n        config.add_handler('home', '/', handler=Hello, action='index')\n        config.end()\n        serve(config.make_wsgi_app(), host='0.0.0.0')\n\n\nCore Features\n-------------\n\n* A framework to make writing web applications in Python easy\n\n* Utilizes a minimalist, component-based philosophy that makes it easy to\n  expand on\n\n* Harness existing knowledge about Python\n\n* Extensible application design\n\n* Fast and efficient, an incredibly small per-request call-stack providing\n  top performance\n\n* Uses existing and well tested Python packages\n\n\nCurrent Status\n--------------\n\nPylons 1.0 series is stable and production ready, but in maintenance-only\nmode. The Pylons Project now maintains the Pyramid web framework for future\ndevelopment. Pylons 1.0 users should strongly consider using Pyramid for\ntheir next project.\n\n\nDownload and Installation\n-------------------------\n\nPylons can be installed with `Easy Install\n<http://peak.telecommunity.com/DevCenter/EasyInstall>`_ by typing::\n\n    > easy_install Pylons\n\n\nDevelopment Version\n-------------------\n\nPylons development uses the git distributed version control system (DVCS)\nwith GitHub hosting the main repository here:\n\n    `Pylons GitHub repository <https://github.com/Pylons/pylons>`_\n\n\nDocumentation\n-------------\n\nhttp://docs.pylonsproject.org/projects/pylons-webframework/en/latest/\n\n\"\"\",\n    keywords='web wsgi lightweight framework sqlalchemy formencode mako templates',\n    license='BSD',\n    author='Ben Bangert, Philip Jenvey, James Gardner',\n    author_email='ben@groovie.org, pjenvey@underboss.org',\n    url='https://github.com/Pylons/pylons',\n    packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),\n    zip_safe=False,\n    include_package_data=True,\n    test_suite='nose.collector',\n    tests_require=tests_require,\n    install_requires=[\n        \"Routes>=1.12.3\", \"WebHelpers>=0.6.4\", \"Beaker>=1.5.4\",\n        \"Paste>=1.7.5.1\", \"PasteDeploy>=1.5.0\", \"PasteScript>=1.7.4.2\",\n        \"FormEncode>=1.2.4\", \"simplejson>=2.2.1\", \"decorator>=3.3.2\",\n        \"nose>=1.1.2\", \"Mako>=0.5.0\", \"WebError>=0.10.3\",\n        \"WebTest>=1.3.1\", \"Tempita>=0.5.1\", \"MarkupSafe>=0.15\",\n        \"WebOb>=1.1.1\",\n    ],\n    classifiers=[\n        \"Development Status :: 5 - Production/Stable\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: BSD License\",\n        \"Framework :: Pylons\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 2 :: Only\",\n        \"Topic :: Internet :: WWW/HTTP\",\n        \"Topic :: Internet :: WWW/HTTP :: Dynamic Content\",\n        \"Topic :: Internet :: WWW/HTTP :: WSGI\",\n        \"Topic :: Software Development :: Libraries :: Python Modules\",\n    ],\n    extras_require={\n        'genshi': ['Genshi>=0.6'],\n        'jinja2': ['Jinja2'],\n    },\n    entry_points=\"\"\"\n    [paste.paster_command]\n    controller = pylons.commands:ControllerCommand\n    restcontroller = pylons.commands:RestControllerCommand\n    routes = pylons.commands:RoutesCommand\n    shell = pylons.commands:ShellCommand\n\n    [paste.paster_create_template]\n    pylons = pylons.util:PylonsTemplate\n    pylons_minimal = pylons.util:MinimalPylonsTemplate\n\n    [paste.filter_factory]\n    debugger = pylons.middleware:debugger_filter_factory\n\n    [paste.filter_app_factory]\n    debugger = pylons.middleware:debugger_filter_app_factory\n    \"\"\",\n)\n"
  },
  {
    "path": "test_files/__init__.py",
    "content": ""
  },
  {
    "path": "test_files/event_file.py",
    "content": "from pylons.events import NewRequest, NewResponse, subscriber\n\n\n@subscriber(NewRequest)\ndef add_reggy(event):\n    event.request.reg = True\n\n@subscriber(NewResponse)\ndef add_respy(event):\n    event.response.reg = True\n"
  },
  {
    "path": "test_files/sample_controllers/__init__.py",
    "content": "#\n"
  },
  {
    "path": "test_files/sample_controllers/controllers/__init__.py",
    "content": "#\n"
  },
  {
    "path": "test_files/sample_controllers/controllers/goodbye.py",
    "content": "import logging\n\nfrom pylons import request, response, session, tmpl_context as c, url\nfrom pylons.controllers import WSGIController\nfrom pylons.controllers.util import abort, redirect\nfrom webob import Response\nfrom webob.exc import HTTPNotFound\n\nlog = logging.getLogger(__name__)\n\nclass Smithy(WSGIController):\n    def __init__(self):\n        self._pylons_log_debug = True\n\n    def index(self):\n        return 'Hello World'\n    \n__controller__ = 'Smithy'\n"
  },
  {
    "path": "test_files/sample_controllers/controllers/hello.py",
    "content": "import logging\n\nfrom pylons import request, response, session, tmpl_context as c, url\nfrom pylons.controllers import WSGIController\nfrom pylons.controllers.util import abort, redirect\nfrom pylons.templating import render_mako\nfrom webob import Response\nfrom webob.exc import HTTPNotFound\n\nlog = logging.getLogger(__name__)\n\nclass HelloController(WSGIController):\n    def __init__(self):\n        self._pylons_log_debug = True\n\n    def index(self):\n        return 'Hello World'\n    \n    def oops(self):\n        raise Exception('oops')\n    \n    def abort(self):\n        abort(404)\n    \n    def intro_template(self):\n        return render_mako('/hello.html')\n    \n    def time_template(self):\n        return render_mako('/time.html', cache_key='fred', cache_expire=20)\n\n\ndef special_controller(environ, start_response):\n    return HTTPNotFound()\n\ndef empty_wsgi(environ, start_response):\n    return\n\ndef a_view(request):\n    return Response('A View')\n"
  },
  {
    "path": "test_files/sample_controllers/controllers/i18nc.py",
    "content": "import datetime\n\nfrom pylons import request, response, session, url\nfrom pylons import tmpl_context as c\nfrom pylons import app_globals\nfrom pylons.i18n import _, get_lang, set_lang, LanguageError\nfrom pylons.controllers import WSGIController\nfrom pylons.controllers.util import abort, redirect\n\nclass I18NcController(WSGIController):\n    def set_lang(self):\n        return self._set_lang(_)\n\n    def set_lang_pylonscontext(self, pylons):\n        return self._set_lang(lambda *args: pylons.translator.ugettext(*args))\n\n    def _set_lang(self, gettext):\n        lang = request.GET['lang']\n        try:\n            set_lang(lang)\n        except (LanguageError, IOError), e:\n            resp_unicode = gettext('Could not set language to \"%(lang)s\"') % {'lang': lang}\n        else:\n            session['lang'] = lang\n            session.save()\n            resp_unicode = gettext('Set language to \"%(lang)s\"') % {'lang': lang}\n        return resp_unicode\n\n    def i18n_index(self):\n        obj = request._current_obj()\n        locale_list = request.languages\n        set_lang(request.languages)\n        return unicode(_('basic index page'))\n\n    def no_lang(self):\n        set_lang(None)\n        response.write(_('No language'))\n        set_lang([])\n        response.write(_('No languages'))\n        return ''\n    \n    def langs(self):\n        locale_list = request.languages\n        set_lang(request.languages)\n        return str(get_lang())\n"
  },
  {
    "path": "test_files/sample_controllers/i18n/es/LC_MESSAGES/sample_controllers.po",
    "content": "# -*- coding: utf-8 -*-\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PROJECT VERSION\\n\"\n\"Report-Msgid-Bugs-To: EMAIL@ADDRESS\\n\"\n\"POT-Creation-Date: 2010-06-25 18:12-0700\\n\"\n\"PO-Revision-Date: 2010-06-25 18:12-0700\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: es <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1)\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 0.9.4\\n\"\n\nmsgid \"Hello\"\nmsgstr \"¡Hola!\"\n"
  },
  {
    "path": "test_files/sample_controllers/i18n/fr/LC_MESSAGES/sample_controllers.po",
    "content": "# -*- coding: utf-8 -*-\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PROJECT VERSION\\n\"\n\"Report-Msgid-Bugs-To: EMAIL@ADDRESS\\n\"\n\"POT-Creation-Date: 2010-06-25 18:12-0700\\n\"\n\"PO-Revision-Date: 2010-06-25 18:12-0700\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: fr <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1)\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 0.9.4\\n\"\n\nmsgid \"Hello\"\nmsgstr \"Bonjour\"\n"
  },
  {
    "path": "test_files/sample_controllers/i18n/ja/LC_MESSAGES/sample_controllers.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2007-02-05 12:36+0900\\n\"\n\"PO-Revision-Date: 2007-02-05 13:06+0900\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: controller_sample.py:7\nmsgid \"basic index page\"\nmsgstr \"根本インデクスページ\"\n\n#: controller_sample.py:59\n#, python-format\nmsgid \"Could not set language to \\\"%(lang)s\\\"\"\nmsgstr \"「%(lang)s」に言語設定が変更できません\"\n\n#: controller_sample.py:63\n#, python-format\nmsgid \"Set language to \\\"%(lang)s\\\"\"\nmsgstr \"言語設定を「%(lang)s」に変更しました\""
  },
  {
    "path": "test_files/sample_controllers/templates/hello.html",
    "content": "Hi there ${4 + 2}\n"
  },
  {
    "path": "test_files/sample_controllers/templates/time.html",
    "content": "<%!\nfrom datetime import datetime\n%>\nHello, the time is ${datetime.now()}\n"
  },
  {
    "path": "tests/__init__.py",
    "content": "#\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "import sys\nimport os\nimport shutil\nimport pkg_resources\n\nhere = os.path.dirname(__file__)\nbase = os.path.dirname(here)\nsys.path.append(here)\nsys.path.insert(0, base)\n\nhere = os.path.dirname(__file__)\n\npkg_resources.working_set.add_entry(base)\n\nif not os.environ.get('PASTE_TESTING'):\n    output_dir = os.path.join(here, 'test_webapps', 'output')\n    if os.path.exists(output_dir):\n        shutil.rmtree(output_dir)\n\n"
  },
  {
    "path": "tests/test_units/__init__.py",
    "content": "import json\nimport os\nimport sys\nfrom unittest import TestCase\nfrom urllib import quote_plus\nfrom xmlrpclib import loads, dumps\n    \ndata_dir = os.path.dirname(os.path.abspath(__file__))\n\ntry:\n    shutil.rmtree(data_dir)\nexcept:\n    pass\n\ncur_dir = os.path.dirname(os.path.abspath(__file__))\npylons_root = os.path.dirname(os.path.dirname(cur_dir))\ntest_root = os.path.join(pylons_root, 'test_files')\n\nsys.path.append(test_root)\n\nclass TestMiddleware(object):\n    def __init__(self, app):\n        self.app = app\n    \n    def __call__(self, environ, start_response):\n        if 'paste.testing_variables' not in environ:\n            environ['paste.testing_variables'] = {}\n        testenv = environ['paste.testing_variables']\n        testenv['environ'] = environ\n        return self.app(environ, start_response)\n\n\nclass TestWSGIController(TestCase):\n    def setUp(self):\n        import pylons\n        from pylons.util import ContextObj, PylonsContext\n        \n        c = ContextObj()\n        py_obj = PylonsContext()\n        py_obj.tmpl_context = c\n        py_obj.request = py_obj.response = None\n        self.environ = {'pylons.routes_dict':dict(action='index'),\n                        'paste.config':dict(global_conf=dict(debug=True)),\n                        'pylons.pylons':py_obj}\n        pylons.tmpl_context._push_object(c)\n\n    def tearDown(self):\n        import pylons\n        pylons.tmpl_context._pop_object()\n    \n    def get_response(self, **kargs):\n        test_args = kargs.pop('test_args', {})\n        url = kargs.pop('_url', '/')\n        self.environ['pylons.routes_dict'].update(kargs)\n        return self.app.get(url, extra_environ=self.environ, **test_args)\n\n    def post_response(self, **kargs):\n        url = kargs.pop('_url', '/')\n        self.environ['pylons.routes_dict'].update(kargs)\n        return self.app.post(url, extra_environ=self.environ, params=kargs)\n    \n    def xmlreq(self, method, args=None):\n        if args is None:\n            args = ()\n        ee = dict(CONTENT_TYPE='text/xml')\n        data = dumps(args, methodname=method)\n        self.response = response = self.app.post('/', params = data,\n                                                 extra_environ=ee)\n        return loads(response.body)[0][0]\n\n    def jsonreq(self, method, args=()):\n        assert(isinstance(args, list) or\n               isinstance(args, tuple) or\n               isinstance(args, dict))\n\n        ee = dict(CONTENT_TYPE='application/json')\n        data = json.dumps(dict(id='test',\n                               method=method,\n                               params=args))\n        self.response = response = self.app.post('/', params=quote_plus(data),\n                                                 extra_environ=ee)\n        return json.loads(response.body)\n        \n"
  },
  {
    "path": "tests/test_units/test_basic_app.py",
    "content": "import os\nimport re\nimport sys\n\n\nfrom nose.tools import raises\n\nfrom __init__ import test_root\n\n\ndef make_app(global_conf, full_stack=True, static_files=True, include_cache_middleware=False, attribsafe=False, **app_conf):\n    import pylons\n    import pylons.configuration as configuration\n    from beaker.cache import CacheManager\n    from beaker.middleware import SessionMiddleware, CacheMiddleware\n    from nose.tools import raises\n    from paste.registry import RegistryManager\n    from paste.deploy.converters import asbool\n    from pylons.decorators import jsonify\n    from pylons.middleware import ErrorHandler, StatusCodeRedirect\n    from pylons.wsgiapp import PylonsApp\n    from routes import Mapper\n    from routes.middleware import RoutesMiddleware\n    \n    paths = dict(root=os.path.join(test_root, 'sample_controllers'), controllers=os.path.join(test_root, 'sample_controllers', 'controllers'))\n\n    config = configuration.pylons_config\n    config.init_app(global_conf, app_conf, package='sample_controllers', paths=paths)\n    map = Mapper(directory=config['pylons.paths']['controllers'])\n    map.connect('/{controller}/{action}')\n    map.connect('/test_func', controller='sample_controllers.controllers.hello:special_controller')\n    map.connect('/test_empty', controller='sample_controllers.controllers.hello:empty_wsgi')\n    config['routes.map'] = map\n    \n    class AppGlobals(object):\n        def __init__(self):\n            self.cache = 'Nothing here but a string'\n    \n    config['pylons.app_globals'] = AppGlobals()\n    \n    if attribsafe:\n        config['pylons.strict_tmpl_context'] = False\n    \n    app = PylonsApp(config=config)\n    app = RoutesMiddleware(app, config['routes.map'], singleton=False)\n    if include_cache_middleware:\n        app = CacheMiddleware(app, config)\n    app = SessionMiddleware(app, config)\n\n    if asbool(full_stack):\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [401, 403, 404, 500])\n    app = RegistryManager(app)\n\n    app.config = config\n    return app\n\nclass TestWsgiApp(object):\n    def setUp(self):\n        from paste.fixture import TestApp\n        from routes.util import URLGenerator\n        \n        app = make_app({})\n        self.app = TestApp(app)\n        self.url = URLGenerator(app.config['routes.map'], {})\n    \n    def test_testvars(self):\n        resp = self.app.get('/_test_vars', extra_environ={'paste.testing_variables': True})\n        assert re.match(r'^\\d+$', resp.body)\n    \n    def test_exception_resp_attach(self):\n        resp = self.app.get('/test_func', expect_errors=True)\n        assert resp.status == 404\n    \n    @raises(Exception)\n    def test_no_content(self):\n        resp = self.app.get('/test_empty', expect_errors=True)\n        assert 'wontgethre'\n    \n    def test_middleware_cache_obj_instance(self):\n        from paste.fixture import TestApp\n        app = TestApp(make_app({}, include_cache_middleware=True))\n        resp = app.get('/hello/index')\n        assert resp.cache\n    \n    def test_attribsafe_tmpl_context(self):\n        from paste.fixture import TestApp\n        app = TestApp(make_app({}, attribsafe=True))\n        resp = app.get('/hello/index')\n        assert 'Hello World' in resp\n    \n    def test_cache_obj_appglobals(self):\n        resp = self.app.get('/hello/index', extra_environ={'paste.testing_variables': True})\n        assert resp.cache == 'Nothing here but a string'\n    \n    def test_controller_name_override(self):\n        resp = self.app.get('/goodbye/index')\n        assert 'Hello World' in resp\n\n\nclass TestJsonifyDecorator(object):\n    def setUp(self):\n        from paste.fixture import TestApp\n        from routes.util import URLGenerator\n        app = make_app({})\n        self.config = app.config\n        self.app = TestApp(app)\n        self.url = URLGenerator(app.config['routes.map'], {})\n    \n    def test_basic_response(self):\n        response = self.app.get('/hello/index')\n        assert 'Hello World' in response\n    \n    def test_config(self):\n        import pylons\n        import pylons.configuration as configuration\n        assert pylons.config == configuration.config\n\n    @raises(AssertionError)\n    def test_eval(self):\n        from paste.fixture import TestApp\n        app = TestApp(make_app(dict(debug='True')))\n        app.get('/hello/oops', status=500, extra_environ={'paste.throw_errors': False})\n\n    def test_set_lang(self):\n        self._test_set_lang('set_lang')\n\n    def test_set_lang_pylonscontext(self):\n        self._test_set_lang('set_lang_pylonscontext')\n\n    def _test_set_lang(self, action):\n        response = self.app.get(self.url(controller='i18nc', action=action, lang='ja'))\n        assert u'\\u8a00\\u8a9e\\u8a2d\\u5b9a\\u3092\\u300cja\\u300d\\u306b\\u5909\\u66f4\\u3057\\u307e\\u3057\\u305f'.encode('utf-8') in response\n        response = self.app.get(self.url(controller='i18nc', action=action, lang='ch'))\n        assert 'Could not set language to \"ch\"' in response\n\n    def test_detect_lang(self):\n        response = self.app.get(self.url(controller='i18nc', action='i18n_index'), headers={\n                'Accept-Language':'fr;q=0.6, en;q=0.1, ja;q=0.3'})\n        # expect japanese fallback for nonexistent french.\n        assert u'\\u6839\\u672c\\u30a4\\u30f3\\u30c7\\u30af\\u30b9\\u30da\\u30fc\\u30b8'.encode('utf-8') in response\n\n    def test_no_lang(self):\n        response = self.app.get(self.url(controller='i18nc', action='no_lang'))\n        assert 'No language' in response\n        assert 'No languages' in response\n    \n    def test_langs(self):\n        response = self.app.get(self.url(controller='i18nc', action='langs'), headers={\n                'Accept-Language':'fr;q=0.6, en;q=0.1, ja;q=0.3'})\n        assert \"['fr', 'ja', 'en-us']\" in response\n"
  },
  {
    "path": "tests/test_units/test_controller.py",
    "content": "# -*- coding: utf-8 -*-\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\nfrom webob.exc import status_map\n\nimport pylons\nfrom pylons.controllers import WSGIController\n\nfrom pylons.testutil import SetupCacheGlobal, ControllerWrap\nfrom __init__ import TestWSGIController, TestMiddleware\n\nclass BasicWSGIController(WSGIController):\n    def __init__(self):\n        self._pylons_log_debug = True\n\n    def __before__(self):\n        pylons.response.headers['Cache-Control'] = 'private'\n    \n    def __after__(self):\n        pylons.response.set_cookie('big_message', 'goodbye')\n    \n    def index(self):\n        return 'hello world'\n\n    def yield_fun(self):\n        def its():\n            x = 0\n            while x < 100:\n                yield 'hi'\n                x += 1\n        return its()\n    \n    def strme(self):\n        return \"hi there\"\n    \n    def use_redirect(self):\n        pylons.response.set_cookie('message', 'Hello World')\n        exc = status_map[301]\n        raise exc('/elsewhere')\n    \n    def use_customnotfound(self):\n        exc = status_map[404]\n        raise exc('Custom not found')\n    \n    def header_check(self):\n        pylons.response.headers['Content-Type'] = 'text/plain'\n        return \"Hello all!\"\n    \n    def nothing(self):\n        return\n\n    def params(self):\n        items = pylons.request.params.mixed().items()\n        items.sort()\n        return str(items)\n\n    def list(self):\n        return ['from', ' a ', 'list']\n\nclass FilteredWSGIController(WSGIController):\n    def __init__(self):\n        self.before = 0\n        self.after = 0\n\n    def __before__(self):\n        self.before += 1\n\n    def __after__(self):\n        self.after += 1\n        action = pylons.request.environ['pylons.routes_dict'].get('action')\n        if action in ('after_response', 'after_string_response'):\n            pylons.response.write(' from __after__')\n\n    def index(self):\n        return 'hi all, before is %s' % self.before\n\n    def after_response(self):\n        return 'hi'\n\n    def after_string_response(self):\n        return 'hello'\n\nclass TestBasicWSGI(TestWSGIController):\n    def __init__(self, *args, **kargs):\n        TestWSGIController.__init__(self, *args, **kargs)\n        self.baseenviron = {}\n        app = ControllerWrap(BasicWSGIController)\n        app = self.sap = SetupCacheGlobal(app, self.baseenviron)\n        app = TestMiddleware(app)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n        \n    def setUp(self):\n        TestWSGIController.setUp(self)\n        self.baseenviron.update(self.environ)\n\n    def test_wsgi_call(self):\n        resp = self.get_response()\n        assert 'hello world' in resp\n    \n    def test_yield_wrapper(self):\n        resp = self.get_response(action='yield_fun')\n        assert 'hi' * 100 in resp\n\n    def test_404(self):\n        self.environ['paste.config']['global_conf']['debug'] = False\n        self.environ['pylons.routes_dict']['action'] = 'notthere'\n        resp = self.app.get('/', status=404)\n        assert resp.status == 404\n    \n    def test_404exception(self):\n        self.environ['paste.config']['global_conf']['debug'] = False\n        self.environ['pylons.routes_dict']['action'] = 'use_customnotfound'\n        resp = self.app.get('/', status=404)\n        assert 'pylons.controller.exception' in resp.environ\n        exc = resp.environ['pylons.controller.exception']\n        assert exc.detail == 'Custom not found'\n        assert resp.status == 404\n    \n    def test_private_func(self):\n        self.baseenviron['pylons.routes_dict']['action'] = '_private'\n        resp = self.app.get('/', status=404)\n        assert resp.status == 404\n    \n    def test_strme_func(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'strme'\n        resp = self.app.get('/')\n        assert \"hi there\" in resp\n    \n    def test_header_check(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'header_check'\n        resp = self.app.get('/')\n        assert \"Hello all!\" in resp\n        assert resp.response.headers['Content-Type'] == 'text/plain'\n        assert resp.response.headers['Cache-Control'] == 'private'\n        assert resp.header('Content-Type') == 'text/plain'\n    \n    def test_head(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'header_check'\n        resp = self.app._gen_request('HEAD', '/')\n        assert '' == resp.body\n        assert resp.header('Content-Type') == 'text/plain'\n\n    def test_redirect(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'use_redirect'\n        resp = self.app.get('/', status=301)\n\n    def test_nothing(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'nothing'\n        resp = self.app.get('/')\n        assert '' == resp.body\n        assert resp.response.headers['Cache-Control'] == 'private'\n\n    def test_unicode_action(self):\n        self.baseenviron['pylons.routes_dict']['action'] = u'ÐžÐ±ÑÑƒÐ¶Ð´ÐµÐ½Ð¸ÐµÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ð¹'\n        resp = self.app.get('/', status=404)\n\n    def test_params(self):\n        self.baseenviron['pylons.routes_dict']['action'] = u'params'\n        resp = self.app.get('/?foo=bar')\n        assert \"'foo', u'bar')]\" in resp, str(resp)\n        resp = self.app.post('/?foo=bar', params=dict(snafu='snafoo'))\n        assert \"'foo', u'bar')\" in resp, str(resp)\n        assert \"'snafu', u'snafoo')]\" in resp, str(resp)\n        resp = self.app.put('/?foo=bar', params=dict(snafu='snafoo'))\n        assert \"'foo', u'bar')\" in resp, str(resp)\n        assert \"'snafu', u'snafoo')]\" in resp, str(resp)\n\n    def test_list(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'list'\n        assert 'from a list' in self.app.get('/')\n\nclass TestFilteredWSGI(TestWSGIController):\n    def __init__(self, *args, **kargs):\n        TestWSGIController.__init__(self, *args, **kargs)\n        self.baseenviron = {}\n        app = ControllerWrap(FilteredWSGIController)\n        app = self.sap = SetupCacheGlobal(app, self.baseenviron)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n        \n    def setUp(self):\n        TestWSGIController.setUp(self)\n        self.baseenviron.update(self.environ)\n    \n    def test_before(self):\n        resp = self.get_response(action='index')\n        assert 'hi' in resp\n        assert 'before is 1' in resp\n\n    def test_after_response(self):\n        resp = self.get_response(action='after_response')\n        assert 'hi from __after__' in resp\n\n    def test_after_string_response(self):\n        resp = self.get_response(action='after_string_response')\n        assert 'hello from __after__' in resp\n\n    def test_start_response(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'start_response'\n        self.app.get('/', status=404)\n"
  },
  {
    "path": "tests/test_units/test_decorator_authenticate_form.py",
    "content": "# -*- coding: utf-8 -*-\nimport logging\nimport logging.handlers\nimport os\n\nfrom beaker.middleware import SessionMiddleware\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\nfrom routes import request_config\n\nfrom __init__ import data_dir, TestWSGIController\n\nsession_dir = os.path.join(data_dir, 'session')\n\ntry:\n    import shutil\n    shutil.rmtree(session_dir)\nexcept:\n    pass\n\n\n# Eat the logging handler messages\nmy_logger = logging.getLogger()\nmy_logger.setLevel(logging.INFO)\n# Add the log message handler to the logger\nclass NullHandler(logging.Handler):\n    def emit(self, record):\n        pass\nmy_logger.addHandler(NullHandler())\n\n\ndef make_protected():\n    from pylons.controllers import WSGIController\n    from pylons.decorators.secure import authenticate_form\n    from webhelpers.pylonslib import secure_form\n    from pylons import request\n    \n    class ProtectedController(WSGIController):\n        def form(self):\n            request_config().environ = request.environ\n            return secure_form.authentication_token()\n\n        @authenticate_form\n        def protected(self):\n            request_config().environ = request.environ\n            return 'Authenticated'\n    return ProtectedController\n\n\nclass TestAuthenticateFormDecorator(TestWSGIController):\n    def setUp(self):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n        ProtectedController = make_protected()\n        TestWSGIController.setUp(self)\n        app = ControllerWrap(ProtectedController)\n        app = SetupCacheGlobal(app, self.environ, setup_session=True)\n        app = SessionMiddleware(app, {}, data_dir=session_dir)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n\n    def test_unauthenticated(self):\n        from pylons.decorators.secure import csrf_detected_message\n        \n        self.environ['pylons.routes_dict']['action'] = 'protected'\n        response = self.app.post('/protected', extra_environ=self.environ,\n                                 expect_errors=True)\n        assert response.status == 403\n        assert csrf_detected_message in response\n\n    def test_authenticated(self):\n        from webhelpers.pylonslib import secure_form\n        \n        self.environ['pylons.routes_dict']['action'] = 'form'\n        response = self.app.get('/form', extra_environ=self.environ)\n        token = response.body\n\n        self.environ['pylons.routes_dict']['action'] = 'protected'\n        response = self.app.post('/protected',\n                                 params={secure_form.token_key: token},\n                                 extra_environ=self.environ,\n                                 expect_errors=True)\n        assert 'Authenticated' in response\n\n        self.environ['pylons.routes_dict']['action'] = 'protected'\n        response = self.app.put('/protected',\n                                params={secure_form.token_key: token},\n                                extra_environ=self.environ,\n                                expect_errors=True)\n        assert 'Authenticated' in response\n\n        # GET with token_key in query string\n        response = self.app.get('/protected',\n                                 params={secure_form.token_key: token},\n                                 extra_environ=self.environ,\n                                 expect_errors=True)\n        assert 'Authenticated' in response\n\n        # POST with token_key in query string\n        response = self.app.post('/protected?' + secure_form.token_key + '=' + token,\n                                 extra_environ=self.environ,\n                                 expect_errors=True)\n        assert 'Authenticated' in response\n"
  },
  {
    "path": "tests/test_units/test_decorator_cache.py",
    "content": "import os\nimport shutil\nimport time\n\nfrom webtest import TestApp\nfrom paste.registry import RegistryManager\n\nfrom beaker.middleware import CacheMiddleware\n\nfrom __init__ import data_dir, TestWSGIController\n\nenviron = {}\nsap = None\n\ndef make_cache_controller():\n    global sap\n    import pylons\n    from pylons.decorators.cache import beaker_cache, create_cache_key\n\n    from pylons.controllers import WSGIController, XMLRPCController\n    from pylons.testutil import SetupCacheGlobal, ControllerWrap\n    \n    class CacheController(WSGIController):\n        @beaker_cache(key=None, invalidate_on_startup=True)\n        def test_default_cache_decorator_invalidate(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(key=None)\n        def test_default_cache_decorator(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        def test_default_cache_decorator_func(self):\n            def func():\n                pylons.app_globals.counter += 1\n                return 'Counter=%s' % pylons.app_globals.counter\n            func = beaker_cache(key=None)(func)\n            return func()\n    \n        def test_response_cache_func(self, use_cache_status=True):\n            pylons.response.status_int = 404\n            def func():\n                pylons.app_globals.counter += 1\n                return 'Counter=%s' % pylons.app_globals.counter\n            if use_cache_status:\n                func = beaker_cache(key=None)(func)\n            else:\n                func = beaker_cache(key=None, cache_response=False)(func)\n            return func()\n\n        @beaker_cache(key=None, type='dbm')\n        def test_dbm_cache_decorator(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(key=\"param\", query_args=True)\n        def test_get_cache_decorator(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(query_args=True)\n        def test_get_cache_default(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(expire=1)\n        def test_expire_cache_decorator(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(expire=1)\n        def test_expire_dbm_cache_decorator(self):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s' % pylons.app_globals.counter\n\n        @beaker_cache(key=\"id\")\n        def test_key_cache_decorator(self, id):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s, id=%s' % (pylons.app_globals.counter, id)\n\n        @beaker_cache(key=[\"id\", \"id2\"])\n        def test_keyslist_cache_decorator(self, id, id2=\"123\"):\n            pylons.app_globals.counter += 1\n            return 'Counter=%s, id=%s' % (pylons.app_globals.counter, id)\n\n        def test_invalidate_cache(self):\n            ns, key = create_cache_key(CacheController.test_default_cache_decorator)\n            c = pylons.cache.get_cache(ns)\n            c.remove_value(key)\n\n        def test_invalidate_dbm_cache(self):\n            ns, key = create_cache_key(CacheController.test_dbm_cache_decorator)\n            c = pylons.cache.get_cache(ns, type='dbm')\n            c.remove_value(key)\n\n        @beaker_cache(cache_headers=('content-type','content-length', 'x-powered-by'))\n        def test_header_cache(self):\n            pylons.response.headers['Content-Type'] = 'application/special'\n            pylons.response.headers['x-powered-by'] = 'pylons'\n            pylons.response.headers['x-dont-include'] = 'should not be included'\n            return \"Hello folks, time is %s\" % time.time()\n\n        @beaker_cache(query_args=True)\n        def test_cache_key_dupe(self):\n            return \"Hello folks, time is %s\" % time.time()\n    \n    app = ControllerWrap(CacheController)\n    app = sap = SetupCacheGlobal(app, environ, setup_cache=True)\n    app = CacheMiddleware(app, {}, data_dir=cache_dir)\n    app = RegistryManager(app)\n    app = TestApp(app)\n\n    # This one is missing cache middleware and the cache object to miss on purpsoe\n    bad_app = ControllerWrap(CacheController)\n    bad_app = SetupCacheGlobal(bad_app, environ, setup_cache=False)\n    bad_app = RegistryManager(bad_app)\n    bad_app = TestApp(bad_app)\n    return app, bad_app\n\n\ncache_dir = os.path.join(data_dir, 'cache')\n\ntry:\n    shutil.rmtree(cache_dir)\nexcept:\n    pass\n\n\nclass TestBadCacheDecorator(TestWSGIController):\n    def setUp(self):\n        app, bad_app = make_cache_controller()\n        self.app = bad_app\n        TestWSGIController.setUp(self)\n        environ.update(self.environ)\n    \n    def test_no_cache(self):\n        self.assertRaises(Exception, lambda: self.get_response(action='test_default_cache_decorator'))\n\nclass TestCacheDecorator(TestWSGIController):\n    def setUp(self):\n        app, bad_app = make_cache_controller()\n        self.app = app\n        TestWSGIController.setUp(self)\n        environ.update(self.environ)\n\n    def test_default_cache_decorator(self):\n        sap.g.counter = 0\n        self.get_response(action='test_default_cache_decorator_invalidate')\n\n        response = self.get_response(action='test_default_cache_decorator_invalidate')\n        assert 'text/html' in response.headers['content-type']\n        assert 'Counter=1' in response\n\n        response = self.get_response(action='test_default_cache_decorator_invalidate')\n        assert 'Counter=1' in response\n    \n    def test_default_cache_decorator(self):\n        sap.g.counter = 0\n        self.get_response(action='test_invalidate_cache')\n\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'text/html' in response.headers['content-type']\n        assert 'Counter=1' in response\n\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=1' in response\n        \n        response = self.get_response(action='test_get_cache_decorator', _url='/?param=123')\n        assert 'Counter=2' in response\n        response = self.get_response(action='test_get_cache_decorator', _url=\"/?param=123\")\n        assert 'Counter=2' in response\n        \n        response = self.get_response(action='test_expire_cache_decorator')\n        assert 'Counter=3' in response\n        response = self.get_response(action='test_expire_cache_decorator')\n        assert 'Counter=3' in response\n        time.sleep(2)\n        response = self.get_response(action='test_expire_cache_decorator')\n        assert 'Counter=4' in response\n        \n        response = self.get_response(action='test_key_cache_decorator', id=1)\n        assert 'Counter=5' in response\n        response = self.get_response(action='test_key_cache_decorator', id=2)\n        assert 'Counter=6' in response\n        response = self.get_response(action='test_key_cache_decorator', id=1)\n        assert 'Counter=5' in response\n        \n        response = self.get_response(action='test_keyslist_cache_decorator', id=1, id2=2)\n        assert 'Counter=7' in response\n        response = self.get_response(action='test_keyslist_cache_decorator', id=1, id2=2)\n        assert 'Counter=7' in response\n        \n        response = self.get_response(action='test_get_cache_default', _url='/?param=1243')\n        assert 'Counter=8' in response\n        response = self.get_response(action='test_get_cache_default', _url=\"/?param=1243\")\n        assert 'Counter=8' in response\n        response = self.get_response(action='test_get_cache_default', _url=\"/?param=123\")\n        assert 'Counter=9' in response\n\n        response = self.get_response(action='test_default_cache_decorator_func')\n        assert 'text/html' in response.headers['content-type']\n        assert 'Counter=10' in response\n        response = self.get_response(action='test_default_cache_decorator_func')\n        assert 'Counter=10' in response\n        \n        response = self.get_response(action='test_response_cache_func', use_cache_status=True)\n        \n        assert 'Counter=10' in response\n        \n        response = self.get_response(action='test_response_cache_func', use_cache_status=False,\n                                     test_args=dict(status=404))\n        assert 'Counter=10' in response\n        \n    \n    def test_dbm_cache_decorator(self):\n        sap.g.counter = 0\n        self.get_response(action=\"test_invalidate_dbm_cache\")\n        \n        response = self.get_response(action=\"test_dbm_cache_decorator\")\n        assert \"Counter=1\" in response\n\n        response = self.get_response(action=\"test_dbm_cache_decorator\")\n        assert \"Counter=1\" in response\n        \n        self.get_response(action=\"test_invalidate_dbm_cache\")\n        response = self.get_response(action=\"test_dbm_cache_decorator\")\n        assert \"Counter=2\" in response\n\n        sap.g.counter = 0\n        response = self.get_response(action=\"test_expire_dbm_cache_decorator\")\n        assert \"Counter=1\" in response\n        response = self.get_response(action=\"test_expire_dbm_cache_decorator\")\n        assert \"Counter=1\" in response\n        time.sleep(2)\n        response = self.get_response(action=\"test_expire_dbm_cache_decorator\")\n        assert \"Counter=2\" in response\n        \n    def test_cache_key(self):\n        from pylons.decorators.cache import beaker_cache, create_cache_key\n        \n        key = create_cache_key(TestCacheDecorator.test_default_cache_decorator)\n        assert key == ('%s.TestCacheDecorator' % self.__module__, 'test_default_cache_decorator')\n        \n        response = self.get_response(action='test_invalidate_cache')\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=1' in response\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=1' in response\n        response = self.get_response(action='test_invalidate_cache')\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=2' in response\n\n    def test_cache_key_dupe(self):\n        response = self.get_response(action='test_cache_key_dupe',\n                                     _url='/test_cache_key_dupe?id=1')\n        time.sleep(0.1)\n        response2 = self.get_response(action='test_cache_key_dupe',\n                                      _url='/test_cache_key_dupe?id=2&id=1')\n        assert str(response) != str(response2)\n        \n    def test_header_cache(self):\n        response = self.get_response(action='test_header_cache')\n        assert response.headers['content-type'] == 'application/special'\n        assert response.headers['x-powered-by'] == 'pylons'\n        assert 'x-dont-include' not in response.headers\n        output = response.body\n\n        time.sleep(1)\n        response = self.get_response(action='test_header_cache')\n        assert response.body == output\n        assert response.headers['content-type'] == 'application/special'\n        assert response.headers['x-powered-by'] == 'pylons'\n        assert 'x-dont-include' not in response.headers\n        \n    def test_nocache(self):\n        import pylons\n        sap.g.counter = 0\n        pylons.config['cache_enabled'] = 'False'\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=1' in response\n        response = self.get_response(action='test_default_cache_decorator')\n        assert 'Counter=2' in response\n        pylons.config['cache_enabled'] = 'True'\n"
  },
  {
    "path": "tests/test_units/test_decorator_https.py",
    "content": "from paste.fixture import TestApp\nfrom paste.registry import RegistryManager\n\nfrom routes.middleware import RoutesMiddleware\n\nfrom __init__ import TestWSGIController\n\ndef make_httpscontroller():\n    from pylons import request, url\n    from pylons.controllers import WSGIController\n    from pylons.decorators.secure import https\n    \n    class HttpsController(WSGIController):\n\n        @https('/pylons')\n        def index(self):\n            return 'index page'\n\n        @https(lambda: url(controller='auth', action='login'))\n        def login2(self):\n            return 'login2 page'\n\n        @https(lambda: request.url)\n        def secure(self):\n            return 'secure page'\n\n        @https()\n        def get(self):\n            return 'get page'\n    return HttpsController\n\nclass TestHttpsDecorator(TestWSGIController):\n    def setUp(self):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n        HttpsController = make_httpscontroller()\n        TestWSGIController.setUp(self)\n        from routes import Mapper\n        map = Mapper()\n        map.connect('/:action')\n        map.connect('/:action/:id')\n        map.connect('/:controller/:action/:id')\n        map.connect('/:controller/:action')\n        app = ControllerWrap(HttpsController)\n        app = SetupCacheGlobal(app, self.environ, setup_cache=False)\n        app = RoutesMiddleware(app, map)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n\n    def test_https_explicit_path(self):\n        self.environ['pylons.routes_dict']['action'] = 'index'\n\n        response = self.app.get('/index', status=302)\n        assert response.header_dict.get('location') == \\\n            'https://localhost/pylons'\n\n        self.environ['wsgi.url_scheme'] = 'https'\n        response = self.app.get('/index', status=200)\n        assert 'location' not in response.header_dict\n        assert 'index page' in response\n\n    def test_https_disallows_post(self):\n        self.environ['pylons.routes_dict']['action'] = 'index'\n        response = self.app.post('/index', status=405)\n\n    def test_https_callable(self):\n        self.environ['pylons.routes_dict']['action'] = 'login2'\n\n        response = self.app.get('/login2', status=302)\n        assert response.header_dict.get('location') == \\\n            'https://localhost/auth/login'\n\n        self.environ['wsgi.url_scheme'] = 'https'\n        response = self.app.get('/login2', status=200)\n        assert 'location' not in response.header_dict\n        assert 'login2 page' in response\n\n    def test_https_callable_current(self):\n        self.environ['pylons.routes_dict']['action'] = 'secure'\n\n        response = self.app.get('/secure', status=302)\n        assert response.header_dict.get('location') == \\\n            'https://localhost/secure'\n\n        self.environ['wsgi.url_scheme'] = 'https'\n        response = self.app.get('/secure', status=200)\n        assert 'location' not in response.header_dict\n        assert 'secure page' in response\n\n    def test_https_redirect_to_self(self):\n        self.environ['pylons.routes_dict']['action'] = 'get'\n\n        response = self.app.get('/get', status=302)\n        assert response.header_dict.get('location') == \\\n            'https://localhost/get'\n\n        self.environ['wsgi.url_scheme'] = 'https'\n        response = self.app.get('/get', status=200)\n        assert 'location' not in response.header_dict\n        assert 'get page' in response\n"
  },
  {
    "path": "tests/test_units/test_decorator_jsonify.py",
    "content": "import warnings\n\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\n\nfrom __init__ import TestWSGIController\n\ndef make_cache_controller_app():\n    from pylons.testutil import ControllerWrap, SetupCacheGlobal\n    from pylons.decorators import jsonify\n    from pylons.controllers import WSGIController\n    \n    class CacheController(WSGIController):\n\n        @jsonify\n        def test_bad_json(self):\n            return [\"this is neat\"]\n\n        @jsonify\n        def test_bad_json2(self):\n            return (\"this is neat\",)\n    \n        @jsonify\n        def test_good_json(self):\n            return dict(fred=42)\n\n    environ = {}\n    app = ControllerWrap(CacheController)\n    app = sap = SetupCacheGlobal(app, environ)\n    app = RegistryManager(app)\n    app = TestApp(app)\n    return app, environ\n\n\nclass TestJsonifyDecorator(TestWSGIController):\n    def setUp(self):\n        self.app, environ = make_cache_controller_app()\n        TestWSGIController.setUp(self)\n        environ.update(self.environ)\n        warnings.simplefilter('error', Warning)\n    \n    def tearDown(self):\n        warnings.simplefilter('always', Warning)\n\n    def test_bad_json(self):\n        for action in 'test_bad_json', 'test_bad_json2':\n            try:\n                response = self.get_response(action=action)\n            except Warning, msg:\n                assert 'JSON responses with Array envelopes are' in msg[0]\n    \n    def test_good_json(self):\n        response = self.get_response(action='test_good_json')\n        assert '{\"fred\": 42}' in response\n        assert response.header('Content-Type') == 'application/json; charset=utf-8'\n"
  },
  {
    "path": "tests/test_units/test_decorator_validate.py",
    "content": "# -*- coding: utf-8 -*-\nimport formencode\nfrom formencode.htmlfill import html_quote\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\n\nfrom __init__ import TestWSGIController\n\n\ndef custom_error_formatter(error):\n    return '<p><span class=\"pylons-error\">%s</span></p>\\n' % html_quote(error)\n\nclass NetworkForm(formencode.Schema):\n    allow_extra_fields = True\n    filter_extra_fields = True\n    new_network = formencode.validators.URL(not_empty=True)\n\nclass HelloForm(formencode.Schema):\n    hello = formencode.ForEach(formencode.validators.Int())\n\ndef make_validating_controller():\n    from pylons.decorators import validate\n    from pylons.controllers import WSGIController\n\n    class ValidatingController(WSGIController):\n        def new_network(self):\n            return \"\"\"\n<html>\n  <form action=\"/dhcp/new_form\" method=\"POST\">\n    <table>\n      <tr>\n        <th>Network</th>\n        <td>\n          <input id=\"new_network\" name=\"new_network\" type=\"text\" value=\"\" />\n        </td>\n      </tr>\n    </table>\n    <input name=\"commit\" type=\"submit\" value=\"Save changes\" />\n  </form>\n</html>\n\"\"\"\n\n        @validate(schema=NetworkForm, form='new_network')\n        def network(self):\n            return 'Your network is: %s' % self.form_result.get('new_network')\n\n        def view_hello(self):\n            return \"\"\"\n<html>\n  <form action=\"/hello\" method=\"POST\">\n    <table>\n      <tr>\n        <th>Hello</th>\n        <td>\n          <form:iferror name=\"hello\">Bad Hello!&nbsp;</form:iferror>\n          <input id=\"hello\" name=\"hello\" type=\"text\" value=\"\" />\n          <input id=\"hello\" name=\"hello\" type=\"text\" value=\"\" />\n          <input id=\"hello\" name=\"hello\" type=\"text\" value=\"\" />\n        </td>\n      </tr>\n    </table>\n    <input name=\"commit\" type=\"submit\" value=\"Submit\" />\n  </form>\n</html>\n\"\"\"\n\n        @validate(schema=HelloForm(), post_only=False, form='view_hello')\n        def hello(self):\n            return str(self.form_result)\n\n        @validate(schema=HelloForm(), post_only=False, form='view_hello',\n                  auto_error_formatter=custom_error_formatter)\n        def hello_custom(self):\n            return str(self.form_result)\n\n        @validate(schema=NetworkForm, form='hello_recurse')\n        def hello_recurse(self, environ):\n            if environ['REQUEST_METHOD'] == 'GET':\n                return self.new_network()\n            else:\n                return 'Your network is: %s' % self.form_result.get('new_network')\n    return ValidatingController\n\n\nclass TestValidateDecorator(TestWSGIController):\n    def setUp(self):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n        ValidatingController = make_validating_controller()\n\n        TestWSGIController.setUp(self)\n        app = SetupCacheGlobal(ControllerWrap(ValidatingController),\n                               self.environ)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n\n    def test_network_validated(self):\n        response = self.post_response(action='network',\n                                      new_network='http://pylonshq.com/')\n        assert 'Your network is: http://pylonshq.com/' in response\n\n    def test_network_failed_validation_non_ascii(self):\n        response = self.post_response(action='network', new_network='Росси́я')\n        assert 'You must provide a full domain name' in response\n        assert 'Росси́я' in response\n\n    def test_recurse_validated(self):\n        response = self.post_response(action='hello_recurse',\n                                      new_network='http://pylonshq.com/')\n        assert 'Your network is: http://pylonshq.com/' in response\n\n    def test_hello(self):\n        self.environ['pylons.routes_dict']['action'] = 'hello'\n        response = self.app.post('/hello?hello=1&hello=2&hello=3',\n                                 extra_environ=self.environ)\n        assert \"'hello': [1, 2, 3]\" in response\n\n    def test_hello_failed(self):\n        self.environ['pylons.routes_dict']['action'] = 'hello'\n        response = self.app.post('/hello?hello=1&hello=2&hello=hi',\n                                 extra_environ=self.environ)\n        assert 'Bad Hello!&nbsp;' in response\n        assert \"[None, None, u'Please enter an integer value']\" in response\n\n    def test_hello_custom_failed(self):\n        self.environ['pylons.routes_dict']['action'] = 'hello_custom'\n        response = \\\n            self.app.post('/hello_custom?hello=1&hello=2&hello=hi',\n                          extra_environ=self.environ)\n        assert 'Bad Hello!&nbsp;' in response\n        assert \"[None, None, u'Please enter an integer value']\" in response\n        assert (\"\"\"<p><span class=\"pylons-error\">[None, None, u'Please enter \"\"\"\n                \"\"\"an integer value']</span></p>\"\"\") in response\n"
  },
  {
    "path": "tests/test_units/test_helpers.py",
    "content": "import warnings\nfrom unittest import TestCase\n\nfrom paste.fixture import TestApp\nfrom paste.httpexceptions import HTTPMovedPermanently\nfrom paste.registry import RegistryManager\n\nfrom __init__ import TestWSGIController\n\n\ndef make_helperscontroller():\n    import pylons\n    from pylons.controllers import WSGIController\n    from pylons.controllers.util import etag_cache\n    \n    class HelpersController(WSGIController):\n\n        def test_etag_cache(self):\n            etag_cache('test')\n            return \"from etag_cache\"\n    return HelpersController\n\nclass TestHelpers(TestWSGIController):\n    def __init__(self, *args, **kargs):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n        HelpersController = make_helperscontroller()\n        TestWSGIController.__init__(self, *args, **kargs)\n        self.baseenviron = {}\n        app = ControllerWrap(HelpersController)\n        app = self.sap = SetupCacheGlobal(app, self.baseenviron)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n        \n    def setUp(self):\n        TestWSGIController.setUp(self)\n        self.baseenviron.update(self.environ)\n        warnings.simplefilter('error', DeprecationWarning)\n\n    def tearDown(self):\n        warnings.simplefilter('always', DeprecationWarning)\n\n    def test_return_etag_cache(self):\n        self.baseenviron['pylons.routes_dict']['action'] = 'test_etag_cache'\n        response = self.app.get('/')\n        assert '\"test\"' == response.header('Etag')\n        assert 'from etag_cache' in response\n"
  },
  {
    "path": "tests/test_units/test_i18n.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\nimport sys\n\nfrom paste.fixture import TestApp\n\nfrom __init__ import test_root\n\nlang_setup = None\n\n\ndef setup_py_trans():\n    global lang_setup\n    import pylons\n    from pylons.i18n.translation import _get_translator\n    root = os.path.join(test_root, 'sample_controllers')\n    lang_setup = {'pylons.paths': {'root': root}, 'pylons.package': 'sample_controllers'}\n    sys.path.append(test_root)\n    pylons.translator._push_object(_get_translator(None, pylons_config=lang_setup))\n\nglob_set = []\n\n\nclass TestI18N(object):\n    def setUp(self):\n        setup_py_trans()\n\n    def test_lazify(self):\n        from pylons.i18n.translation import lazify\n\n        def show_str(st):\n            return '%s%s' % (st, len(glob_set))\n        lazy_show_str = lazify(show_str)\n        result1 = lazy_show_str('fred')\n        result2 = show_str('fred')\n        assert str(result1) == str(result2)\n        glob_set.append('1')\n        assert str(result1) != str(result2)\n\n    def test_noop(self):\n        import pylons\n        from pylons.i18n.translation import _, N_, set_lang\n        foo = N_('Hello')\n\n        class Bar(object):\n            def __init__(self):\n                self.local_foo = _(foo)\n\n        assert Bar().local_foo == 'Hello'\n\n        t = set_lang('fr', set_environ=False, pylons_config=lang_setup)\n        pylons.translator._push_object(t)\n        assert Bar().local_foo == 'Bonjour'\n        t = set_lang('es', set_environ=False, pylons_config=lang_setup)\n        pylons.translator._push_object(t)\n        assert Bar().local_foo == u'¡Hola!'\n        assert foo == 'Hello'\n"
  },
  {
    "path": "tests/test_units/test_jsonrpc.py",
    "content": "# -*- coding: utf-8 -*-\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\n\nimport webob.exc as exc\nimport json\n\nfrom __init__ import TestWSGIController\n\ndef make_basejsonrpc():\n    from pylons.controllers import JSONRPCController, JSONRPCError\n\n    class BaseJSONRPCController(JSONRPCController):\n\n        def __init__(self):\n            self._pylons_log_debug = True\n\n        def echo(self, message):\n            return message\n\n        def int_arg_check(self, arg):\n            if not isinstance(arg, int):\n                raise JSONRPCError(1, 'That is not an integer')\n            else:\n                return 'got an integer'\n\n        def return_garbage(self):\n            return JSONRPCController\n\n        def subtract(self, x, y):\n            if not isinstance(x, int) and not isinstance(y, int):\n                raise JSONRPCError(1, 'That is not an integer')\n            else:\n                return x - y\n\n        def v2_echo(self, message='Default message'):\n            return message\n\n        def v2_int_arg_check(self, arg=99):\n            if not isinstance(arg, int):\n                raise JSONRPCError(1, 'That is not an integer')\n            else:\n                return 'got an integer'\n\n        def v2_decrement(self, x, y=1):\n            \"\"\"Like subtract, but decrements by default.\"\"\"\n            if not isinstance(x, int) and not isinstance(y, int):\n                raise JSONRPCError(1, 'That is not an integer')\n            else:\n                return x - y\n\n        def _private(self):\n            return 'private method'\n\n    return BaseJSONRPCController\n\n\nclass TestJSONRPCController(TestWSGIController):\n\n    def __init__(self, *args, **kwargs):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n\n        BaseJSONRPCController = make_basejsonrpc()\n        TestWSGIController.__init__(self, *args, **kwargs)\n        self.baseenviron = {}\n        self.baseenviron['pylons.routes_dict'] = {}\n        app = ControllerWrap(BaseJSONRPCController)\n        app = self.sap = SetupCacheGlobal(app, self.baseenviron)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n\n    def test_echo(self):\n        response = self.jsonreq('echo', args=('hello, world',))\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result='hello, world') == response\n\n    def test_int_arg_check(self):\n        response = self.jsonreq('int_arg_check', args=('1',))\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': 1,\n                           'message': 'That is not an integer'}) == response\n\n    def test_return_garbage(self):\n        response = self.jsonreq('return_garbage')\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': -32603,\n                           'message': \"Internal error\"}) == response\n\n    def test_private_method(self):\n        response = self.jsonreq('_private')\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': -32601,\n                           'message': \"Method not found\"}) == response\n\n    def test_content_type(self):\n        response = self.jsonreq('echo', args=('foo',))\n        assert self.response.header('Content-Type') == 'application/json'\n\n    def test_missing_method(self):\n        response = self.jsonreq('foo')\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': -32601,\n                           'message': \"Method not found\"}) == response\n\n    def test_no_content_length(self):\n        data = json.dumps(dict(jsonrpc='2.0',\n                               id='test',\n                               method='echo',\n                               args=('foo',)))\n        self.assertRaises(exc.HTTPLengthRequired,\n                          lambda: self.app.post('/', extra_environ=\\\n                                                    dict(CONTENT_LENGTH='')))\n\n    def test_zero_content_length(self):\n        data = json.dumps(dict(jsonrpc='2.0',\n                               id='test',\n                               method='echo',\n                               args=('foo',)))\n        self.assertRaises(exc.HTTPLengthRequired,\n                          lambda: self.app.post('/', extra_environ=\\\n                                                    dict(CONTENT_LENGTH='0')))\n\n    def test_positional_params(self):\n        response = self.jsonreq('subtract', args=[4, 2])\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result=2) == response\n\n    def test_missing_positional_param(self):\n        response = self.jsonreq('subtract', args=[1])\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': -32602,\n                           'message': \"Invalid params\"}) == response\n\n    def test_wrong_param_type(self):\n        response = self.jsonreq('subtract', args=['1', '2'])\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': 1,\n                           'message': \"That is not an integer\"}) == response\n\n    def test_v2_echo(self):\n        response = self.jsonreq('v2_echo', args={'message': 'hello, world'})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result='hello, world') == response\n\n    def test_v2_echo_default(self):\n        response = self.jsonreq('v2_echo', args={})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result='Default message') == response\n\n    def test_v2_int_arg_check_valid(self):\n        response = self.jsonreq('v2_int_arg_check', args={'arg': 5})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result='got an integer')\n\n    def test_v2_int_arg_check_default_keyword_argument(self):\n        response = self.jsonreq('v2_int_arg_check', args={})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result='got an integer')\n\n    def test_v2_int_arg_check(self):\n        response = self.jsonreq('v2_int_arg_check', args={'arg': 'abc'})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': 1,\n                           'message': \"That is not an integer\"}) == response\n\n    def test_v2_decrement(self):\n        response = self.jsonreq('v2_decrement', args={'x': 50, 'y': 100})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result=-50) == response\n\n    def test_v2_decrement_default_keywoard_argument(self):\n        response = self.jsonreq('v2_decrement', args={'x': 50})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    result=49) == response\n\n    def test_v2_decrement_missing_keyword_argument(self):\n        response = self.jsonreq('v2_decrement', args={})\n        assert dict(jsonrpc='2.0',\n                    id='test',\n                    error={'code': -32602,\n                           'message': \"Invalid params\"}) == response\n"
  },
  {
    "path": "tests/test_units/test_middleware.py",
    "content": "# -*- coding: utf-8 -*-\nfrom webtest import TestApp\n\ndef simple_app(environ, start_response):\n    start_response('200 OK', [('Content-type', 'text/plain')])\n    return ['Hello world!']\n\ndef simple_exception_app(environ, start_response):\n    if environ['PATH_INFO'].startswith('/error/document'):\n        start_response('200 OK', [('Content-type', 'text/plain')])\n        return ['Made it to the error']\n    else:\n        start_response('404 Not Found', [('Content-type', 'text/plain')])\n        return ['No page found!']\n\ndef test_plain_wrap():\n    from pylons.middleware import StatusCodeRedirect\n    app = TestApp(StatusCodeRedirect(simple_app))\n    res = app.get('/')\n    assert res.status_int == 200\n\ndef test_status_intercept():\n    from pylons.middleware import StatusCodeRedirect\n    app = TestApp(StatusCodeRedirect(simple_exception_app))\n    res = app.get('/', status=404)\n    assert 'Made it to the error' in res\n\ndef test_original_path():\n    from pylons.middleware import StatusCodeRedirect\n    app = TestApp(StatusCodeRedirect(simple_exception_app))\n    res = app.get('/', status=404)\n    if getattr(res, 'environ', None) is not None: # webob<1.2\n        assert res.environ['PATH_INFO'] == '/'\n\ndef test_retains_response():\n    from pylons.middleware import StatusCodeRedirect\n    app = TestApp(StatusCodeRedirect(simple_exception_app))\n    res = app.get('/', status=404)\n    if getattr(res, 'environ', None) is not None: # webob<1.2\n        assert 'pylons.original_response' in res.environ\n        assert 'No page found!' in res.environ['pylons.original_response'].body\n\ndef test_retains_request():\n    from pylons.middleware import StatusCodeRedirect\n    app = TestApp(StatusCodeRedirect(simple_exception_app))\n    res = app.get('/fredrick', status=404)\n    if getattr(res, 'environ', None) is not None: # webob<1.2\n        assert 'pylons.original_request' in res.environ\n        assert '/fredrick' == res.environ['pylons.original_request'].path_info\n    \n"
  },
  {
    "path": "tests/test_units/test_templating.py",
    "content": "import os\nimport re\nimport sys\n\nfrom beaker.cache import CacheManager\nfrom beaker.middleware import SessionMiddleware, CacheMiddleware\nfrom mako.lookup import TemplateLookup\nfrom nose.tools import raises\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\nfrom paste.deploy.converters import asbool\nfrom routes import Mapper\nfrom routes.middleware import RoutesMiddleware\n\nfrom nose.tools import raises\n\nfrom __init__ import test_root\n\n\ndef make_app(global_conf, full_stack=True, static_files=True, include_cache_middleware=False, attribsafe=False, **app_conf):\n    import pylons\n    import pylons.configuration as configuration\n    from pylons import url\n    from pylons.decorators import jsonify\n    from pylons.middleware import ErrorHandler, StatusCodeRedirect\n    from pylons.error import handle_mako_error\n    from pylons.wsgiapp import PylonsApp\n\n    root = os.path.dirname(os.path.abspath(__file__))\n    paths = dict(root=os.path.join(test_root, 'sample_controllers'), controllers=os.path.join(test_root, 'sample_controllers', 'controllers'),\n                 templates=os.path.join(test_root, 'sample_controllers', 'templates'))\n    sys.path.append(test_root)\n\n    config = configuration.PylonsConfig()\n    config.init_app(global_conf, app_conf, package='sample_controllers', paths=paths)\n    map = Mapper(directory=config['pylons.paths']['controllers'])\n    map.connect('/{controller}/{action}')\n    config['routes.map'] = map\n    \n    class AppGlobals(object): pass\n    \n    config['pylons.app_globals'] = AppGlobals()\n    \n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'], imports=['from markupsafe import escape']\n    )\n        \n    if attribsafe:\n        config['pylons.strict_tmpl_context'] = False\n    \n    app = PylonsApp(config=config)\n    app = RoutesMiddleware(app, config['routes.map'], singleton=False)\n    if include_cache_middleware:\n        app = CacheMiddleware(app, config)\n    app = SessionMiddleware(app, config)\n\n    if asbool(full_stack):\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [401, 403, 404, 500])\n    app = RegistryManager(app)\n\n    app.config = config\n    return app\n\nclass TestTemplatingApp(object):\n    def setUp(self):\n        self.app = TestApp(make_app({'cache_dir': os.path.join(os.path.dirname(__file__), 'cache')}, include_cache_middleware=True))\n    \n    def test_testvars(self):\n        resp = self.app.get('/hello/intro_template')\n        assert 'Hi there 6' in resp\n    \n    def test_template_cache(self):\n        resp = self.app.get('/hello/time_template')\n        resp2 = self.app.get('/hello/time_template')\n        assert resp.body == resp2.body\n\n"
  },
  {
    "path": "tests/test_units/test_xmlrpc.py",
    "content": "# -*- coding: utf-8 -*-\nfrom paste.fixture import TestApp\nfrom paste.registry import RegistryManager\n\nimport webob.exc as exc\nimport xmlrpclib\n\nfrom __init__ import TestWSGIController\n\ndef make_basexmlrpc():\n    from pylons.controllers import XMLRPCController\n    class BaseXMLRPCController(XMLRPCController):\n        def __init__(self):\n            self._pylons_log_debug = True\n    \n        foo = 'bar'\n    \n        def userstatus(self):\n            return 'basic string'\n        userstatus.signature = [ ['string'] ]\n    \n        def docs(self):\n            \"This method has a docstring\"\n            return dict(mess='a little somethin', a=1, b=[1,2,3], c=('all','the'))\n        docs.signature = [ ['struct'] ]\n    \n        def uni(self):\n            \"This method has a docstring\"\n            return dict(mess=u'A unicode string, oh boy')\n        uni.signature = [ ['struct'] ]\n    \n        def intargcheck(self, arg):\n            if not isinstance(arg, int):\n                return xmlrpclib.Fault(0, 'Integer required')\n            else:\n                return \"received int\"\n        intargcheck.signature = [ ['string', 'int'] ]\n    \n        def nosig(self):\n            return 'not much'\n    \n        def structured_methodname(self, arg):\n            \"This method has a docstring\"\n            return 'Transform okay'\n        structured_methodname.signature = [ ['string', 'string'] ]\n    \n        def longdoc(self):\n            \"\"\"This function\n            has multiple lines\n            in it\"\"\"\n            return \"hi all\"\n    \n        def _private(self):\n            return 'private method'\n    return BaseXMLRPCController\n    \nclass TestXMLRPCController(TestWSGIController):\n    def __init__(self, *args, **kargs):\n        from pylons.testutil import ControllerWrap, SetupCacheGlobal\n        BaseXMLRPCController = make_basexmlrpc()\n        \n        TestWSGIController.__init__(self, *args, **kargs)\n        self.baseenviron = {}\n        self.baseenviron['pylons.routes_dict'] = {}\n        app = ControllerWrap(BaseXMLRPCController)\n        app = self.sap = SetupCacheGlobal(app, self.baseenviron)\n        app = RegistryManager(app)\n        self.app = TestApp(app)\n    \n    def test_index(self):\n        response = self.xmlreq('userstatus')\n        assert response == 'basic string'\n    \n    def test_structure(self):\n        response = self.xmlreq('docs')\n        assert dict(mess='a little somethin', a=1, b=[1,2,3], c=['all','the']) == response\n    \n    def test_methodhelp(self):\n        response = self.xmlreq('system.methodHelp', ('docs',))\n        assert \"This method has a docstring\" in response\n    \n    def test_methodhelp_with_structured_methodname(self):\n        response = self.xmlreq('system.methodHelp', ('structured.methodname',))\n        assert \"This method has a docstring\" in response\n    \n    def test_methodsignature(self):\n        response = self.xmlreq('system.methodSignature', ('docs',))\n        assert [['struct']] == response\n    \n    def test_methodsignature_with_structured_methodname(self):\n        response = self.xmlreq('system.methodSignature', ('structured.methodname',))\n        assert [['string', 'string']] == response\n    \n    def test_listmethods(self):\n        response = self.xmlreq('system.listMethods')\n        assert response == ['docs', 'intargcheck', 'longdoc', 'nosig', 'structured.methodname', 'system.listMethods', 'system.methodHelp', 'system.methodSignature', 'uni', 'userstatus']    \n    \n    def test_unicode(self):\n        response = self.xmlreq('uni')\n        assert 'A unicode string' in response['mess']\n    \n    def test_unicode_method(self):\n        data = xmlrpclib.dumps((), methodname=u'ОбсуждениеКомпаний')\n        self.response = response = self.app.post('/', params=data, extra_environ=dict(CONTENT_TYPE='text/xml'))\n    \n    def test_no_length(self):\n        data = xmlrpclib.dumps((), methodname=u'ОбсуждениеКомпаний')\n        self.assertRaises(exc.HTTPLengthRequired, lambda: self.app.post('/', extra_environ=dict(CONTENT_LENGTH='')))\n    \n    def test_too_big(self):\n        data = xmlrpclib.dumps((), methodname=u'ОбсуждениеКомпаний')\n        self.assertRaises(exc.HTTPRequestEntityTooLarge, lambda: self.app.post('/', extra_environ=dict(CONTENT_LENGTH='4194314')))\n    \n    def test_badargs(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'system.methodHelp')\n    \n    def test_badarity(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'system.methodHelp')\n    \n    # Unsure whether this is actually picked up by xmlrpclib, but what the hey\n    def test_bad_paramval(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'intargcheck', (12.5,))\n    \n    def test_missingmethod(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'doesntexist')\n    \n    def test_nosignature(self):\n        response = self.xmlreq('system.methodSignature', ('nosig',))\n        assert response == ''\n    \n    def test_nosignature_unicode(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'system.methodSignature',\n                          (u'ОбсуждениеКомпаний',))\n    \n    def test_nodocs(self):\n        response = self.xmlreq('system.methodHelp', ('nosig',))\n        assert response == ''\n    \n    def test_nodocs_unicode(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'system.methodHelp',\n                          (u'ОбсуждениеКомпаний',))\n    \n    def test_multilinedoc(self):\n        response = self.xmlreq('system.methodHelp', ('longdoc',))\n        assert 'This function\\nhas multiple lines\\nin it' in response\n    \n    def test_contenttype(self):\n        response = self.xmlreq('system.methodHelp', ('longdoc',))\n        assert self.response.header('Content-Type') == 'text/xml'\n    \n    def test_start_response(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'start_response')\n    \n    def test_private_func(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, '_private')\n    \n    def test_var(self):\n        self.assertRaises(xmlrpclib.Fault, self.xmlreq, 'foo')\n    \n\n"
  },
  {
    "path": "tests/test_webapps/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_webapps/filestotest/app_globals.py",
    "content": "\"\"\"The application's Globals object\"\"\"\nfrom pylons import config\n\nfrom beaker.cache import CacheManager\nfrom beaker.util import parse_cache_config_options\n\nclass Globals(object):\n    \"\"\"Globals acts as a container for objects available throughout the\n    life of the application\n\n    \"\"\"\n    def __init__(self, config):\n        \"\"\"One instance of Globals is created during application\n        initialization and is available during requests via the\n        'app_globals' variable\n\n        \"\"\"\n        self.cache = CacheManager(**parse_cache_config_options(config))\n        self.message = 'Hello'\n        self.counter = 0\n"
  },
  {
    "path": "tests/test_webapps/filestotest/base_with_xmlrpc.py",
    "content": "from pylons import tmpl_context as c, app_globals, cache, request, session\nfrom pylons.controllers import WSGIController, XMLRPCController\nfrom pylons.controllers.util import abort, etag_cache, redirect\nfrom pylons.decorators import jsonify, validate\nfrom pylons.templating import render_mako as render\nfrom pylons.i18n import N_, _, ungettext\nimport projectname.model as model\nimport projectname.lib.helpers as h\n\nclass BaseController(WSGIController):\n    def __call__(self, environ, start_response):\n        # Insert any code to be run per request here. The Routes match\n        # is under environ['pylons.routes_dict'] should you want to check\n        # the action or route vars here\n        return WSGIController.__call__(self, environ, start_response)\n\n# Include the '_' function in the public names\n__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \\\n           or __name == '_']\n"
  },
  {
    "path": "tests/test_webapps/filestotest/cache_controller.py",
    "content": "from pylons import app_globals\nfrom pylons.decorators.cache import beaker_cache\nfrom projectname.lib.base import BaseController\n\nclass CacheController(BaseController):\n\n    @beaker_cache(key=None)\n    def test_default_cache_decorator(self):\n        app_globals.counter += 1\n        return 'Counter=%s' % app_globals.counter\n\n    @beaker_cache(key=\"param\", query_args=True)\n    def test_get_cache_decorator(self):\n        app_globals.counter += 1\n        return 'Counter=%s' % app_globals.counter\n\n    @beaker_cache(expire=4)\n    def test_expire_cache_decorator(self):\n        app_globals.counter += 1\n        return 'Counter=%s' % app_globals.counter\n\n    @beaker_cache(key=\"id\")\n    def test_key_cache_decorator(self, id):\n        app_globals.counter += 1\n        return 'Counter=%s, id=%s' % (app_globals.counter, id)\n\n    @beaker_cache(key=[\"id\", \"id2\"])\n    def test_keyslist_cache_decorator(self, id, id2=\"123\"):\n        app_globals.counter += 1\n        return 'Counter=%s, id=%s' % (app_globals.counter, id)\n"
  },
  {
    "path": "tests/test_webapps/filestotest/controller_sample.py",
    "content": "import datetime\n\nfrom projectname.lib.base import *\nimport projectname.lib.helpers as h\nfrom pylons import request, response, session, url\nfrom pylons import tmpl_context as c\nfrom pylons import app_globals\nfrom pylons.decorators import rest\nfrom pylons.i18n import _, get_lang, set_lang, LanguageError\nfrom pylons.templating import render_mako, render_genshi, render_jinja2\nfrom pylons.controllers.util import abort, redirect\n\nclass SampleController(BaseController):\n    def index(self):\n        return 'basic index page'\n    \n    def session_increment(self):\n        session.setdefault('counter', -1)\n        session['counter'] += 1\n        session.save()\n        return 'session incrementer'\n    \n    def globalup(self):\n        return app_globals.message\n    \n    def global_store(self, id=None):\n        if id:\n            app_globals.counter += int(id)\n        return str(app_globals.counter)\n    \n    def myself(self):\n        return request.url\n    \n    def myparams(self):\n        return str(request.params)\n    \n    def testdefault(self):\n        c.test = \"This is in c var\"\n        return render_genshi('testgenshi.html')\n        \n    def test_template_caching(self):\n        return render_mako('/test_mako.html', cache_expire='never')\n\n    @rest.dispatch_on(GET='test_only_get')\n    @rest.restrict('POST')\n    def test_only_post(self):\n        return 'It was a post!'\n\n    @rest.restrict('GET')\n    def test_only_get(self):\n        return 'It was a get!'\n\n    @rest.restrict('POST')\n    @rest.dispatch_on(POST='test_only_post')\n    def impossible(self):\n        return 'This should never be shown'\n\n    def testjinja2(self):\n        c.test = \"This is in c var\"\n        c.now = datetime.datetime.now\n        return render_jinja2('testjinja2.html')\n\n    def set_lang(self):\n        return self._set_lang(_)\n\n    def set_lang_pylonscontext(self, pylons):\n        return self._set_lang(lambda *args: pylons.translator.ugettext(*args))\n\n    def _set_lang(self, gettext):\n        lang = request.GET['lang']\n        try:\n            set_lang(lang)\n        except (LanguageError, IOError), e:\n            resp_unicode = gettext('Could not set language to \"%(lang)s\"') % {'lang': lang}\n        else:\n            session['lang'] = lang\n            session.save()\n            resp_unicode = gettext('Set language to \"%(lang)s\"') % {'lang': lang}\n        return resp_unicode\n\n    def i18n_index(self):\n        locale_list = request.languages\n        set_lang(request.languages)\n        return unicode(_('basic index page'))\n\n    def no_lang(self):\n        set_lang(None)\n        response.write(_('No language'))\n        set_lang([])\n        response.write(_('No languages'))\n        return ''\n"
  },
  {
    "path": "tests/test_webapps/filestotest/controller_sqlatest.py",
    "content": "import datetime\n\nfrom projectname.lib.base import *\ntry:\n    import sqlalchemy as sa\n    from projectname.model.meta import Session, Base\n    from projectname.model import Foo\n    SQLAtesting = True\nexcept:\n    SQLAtesting = False\nimport projectname.lib.helpers as h\nfrom pylons import request, response, session\nfrom pylons import tmpl_context as c\nfrom pylons import app_globals\nfrom pylons.decorators import rest\nfrom pylons.i18n import _, get_lang, set_lang, LanguageError\nfrom pylons.templating import render_mako, render_genshi, render_jinja2\nfrom pylons.controllers.util import abort, redirect\n\nclass SampleController(BaseController):\n    def index(self):\n        return 'basic index page'\n    \n    def testsqlalchemy(self):\n        if SQLAtesting:\n            c.foos = Session.query(Foo).all()\n            return render_mako('test_sqlalchemy.html')\n        pass\n    \n    def set_lang(self):\n        return self._set_lang(_)\n    \n    def set_lang_pylonscontext(self, pylons):\n        return self._set_lang(lambda *args: pylons.translator.ugettext(*args))\n    \n    def _set_lang(self, gettext):\n        lang = request.GET['lang']\n        try:\n            set_lang(lang)\n        except (LanguageError, IOError), e:\n            resp_unicode = gettext('Could not set language to \"%(lang)s\"') % {'lang': lang}\n        else:\n            session['lang'] = lang\n            session.save()\n            resp_unicode = gettext('Set language to \"%(lang)s\"') % {'lang': lang}\n        return resp_unicode\n    \n    def i18n_index(self):\n        locale_list = request.languages\n        set_lang(request.languages)\n        return unicode(_('basic index page'))\n    \n    def no_lang(self):\n        set_lang(None)\n        response.write(_('No language'))\n        set_lang([])\n        response.write(_('No languages'))\n        return ''\n        \n"
  },
  {
    "path": "tests/test_webapps/filestotest/controller_xmlrpc.py",
    "content": "from projectname.lib.base import *\nfrom pylons.controllers import XMLRPCController\n\nclass XmlrpcController(XMLRPCController):\n    def userstatus(self):\n        return 'basic string'\n    userstatus.signature = [ ['string'] ]\n    \n    def docs(self):\n        \"This method has a docstring\"\n        return dict(mess='a little somethin', a=1, b=[1,2,3], c=('all','the'))\n    docs.signature = [ ['struct'] ]\n\n    def uni(self):\n        \"This method has a docstring\"\n        return dict(mess=u'A unicode string, oh boy')\n    docs.signature = [ ['struct'] ]\n    "
  },
  {
    "path": "tests/test_webapps/filestotest/development.ini",
    "content": "[DEFAULT]\ndebug = true\nemail_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@exceptions.com\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = egg:projectname\ncache_dir = %(here)s/data\nbeaker.session.key = projectname\nbeaker.session.secret = somesecret\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for Myghty, the Cache data, or the Session saves, un-comment the desired\n# settings here:\n#beaker.cache_data_dir = %(here)s/data/cache\n#beaker.session_data_dir = %(here)s/data/sessions\n\n# If you are using SQLAlchemy you will need to specify a\n# dburi. You can do this with a line similar to the \n# one below but adjusted for your database connection \n# according to the SQLAlchemy documentation. The %(here)s\n# part is replaced with the current directory which is\n# useful when using sqlite on UNIX based platforms. \n# For Windows you should look at the SQLAlchemy\n# documentation for a special syntax to use because the\n# path returned by %(here)s contains a : character.\n# SQLAlchemy database URL\n#sqlalchemy.url = sqlite:///%(here)s/development.db\n\n# Do not set debug to true or uncomment the line below\n# on a production environment otherwise in the event of\n# an error occurring the visitor will be presented with\n# interactive debugging tools and these could be used to \n# execute malicious code.\n# For development purposes debug should be set to true\n# to enable the debugging code but be sure to set it back\n# to false before releasing your application.\n#set debug = false\n"
  },
  {
    "path": "tests/test_webapps/filestotest/development_sqlatesting.ini",
    "content": "[DEFAULT]\ndebug = true\nemail_to = you@yourdomain.com\nsmtp_server = localhost\nerror_email_from = paste@exceptions.com\n\n[server:main]\nuse = egg:Paste#http\nhost = 127.0.0.1\nport = 5000\n\n[app:main]\nuse = egg:projectname\ncache_dir = %(here)s/data\nbeaker.session.key = projectname\nbeaker.session.secret = somesecret\n\n# If you'd like to fine-tune the individual locations of the cache data dirs\n# for Myghty, the Cache data, or the Session saves, un-comment the desired\n# settings here:\n#beaker.cache_data_dir = %(here)s/data/cache\n#beaker.session_data_dir = %(here)s/data/sessions\n\n# If you are using SQLAlchemy you will need to specify a\n# dburi. You can do this with a line similar to the \n# one below but adjusted for your database connection \n# according to the SQLAlchemy documentation. The %(here)s\n# part is replaced with the current directory which is\n# useful when using sqlite on UNIX based platforms. \n# For Windows you should look at the SQLAlchemy\n# documentation for a special syntax to use because the\n# path returned by %(here)s contains a : character.\n# SQLAlchemy database URL\nsqlalchemy.url = sqlite:///%(here)s/development.db\nsqlalchemy.echo = True\n\n# Do not set debug to true or uncomment the line below\n# on a production environment otherwise in the event of\n# an error occurring the visitor will be presented with\n# interactive debugging tools and these could be used to \n# execute malicious code.\n# For development purposes debug should be set to true\n# to enable the debugging code but be sure to set it back\n# to false before releasing your application.\n#set debug = false\n\n"
  },
  {
    "path": "tests/test_webapps/filestotest/environment_def_engine.py",
    "content": "\"\"\"Pylons environment configuration\"\"\"\nimport os\n\n\nfrom mako.lookup import TemplateLookup\nfrom genshi.template import TemplateLoader\nfrom jinja2 import ChoiceLoader, Environment, FileSystemLoader\nfrom pylons.configuration import PylonsConfig\nfrom pylons.error import handle_mako_error\n\nimport projectname.lib.app_globals as app_globals\nimport projectname.lib.helpers\nfrom projectname.config.routing import make_map\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"Configure the Pylons environment via the ``pylons.config``\n    object\n    \"\"\"\n    config = PylonsConfig()\n    \n    # Pylons paths\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, 'public'),\n                 templates=[os.path.join(root, 'templates')])\n\n    # Initialize config with the basic options\n    config.init_app(global_conf, app_conf, package='projectname', paths=paths)\n\n    config['routes.map'] = make_map(config)\n    config['pylons.app_globals'] = app_globals.Globals(config)\n    config['pylons.h'] = projectname.lib.helpers\n    \n    # Setup cache object as early as possible\n    import pylons\n    pylons.cache._push_object(config['pylons.app_globals'].cache)\n    \n    # Create the Mako TemplateLookup, with the default auto-escaping\n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from webhelpers.html import escape'])\n\n    # Create the Genshi TemplateLoader\n    config['pylons.app_globals'].genshi_loader = TemplateLoader(\n        paths['templates'], auto_reload=True)\n\n    # Create the Jinja2 Environment\n    config['pylons.app_globals'].jinja2_env = Environment(loader=ChoiceLoader(\n            [FileSystemLoader(path) for path in paths['templates']]))\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n    \n    return config\n"
  },
  {
    "path": "tests/test_webapps/filestotest/environment_def_sqlamodel.py",
    "content": "\"\"\"Pylons environment configuration\"\"\"\nimport os\n\n\nfrom mako.lookup import TemplateLookup\nfrom genshi.template import TemplateLoader\nfrom jinja2 import ChoiceLoader, Environment, FileSystemLoader\nfrom pylons.configuration import PylonsConfig\nfrom pylons.error import handle_mako_error\nfrom sqlalchemy import engine_from_config\n \nimport projectname.lib.app_globals as app_globals\nimport projectname.lib.helpers\nfrom projectname.config.routing import make_map\nfrom projectname.model import init_model\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"Configure the Pylons environment via the ``pylons.config``\n    object\n    \"\"\"\n    config = PylonsConfig()\n    \n    # Pylons paths\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, 'public'),\n                 templates=[os.path.join(root, 'templates')])\n\n    # Initialize config with the basic options\n    config.init_app(global_conf, app_conf, package='projectname', paths=paths)\n\n    config['routes.map'] = make_map(config)\n    config['pylons.app_globals'] = app_globals.Globals(config)\n    config['pylons.h'] = projectname.lib.helpers\n    \n    # Setup cache object as early as possible\n    import pylons\n    pylons.cache._push_object(config['pylons.app_globals'].cache)\n    \n    # Create the Mako TemplateLookup, with the default auto-escaping\n    config['pylons.app_globals'].mako_lookup = TemplateLookup(\n        directories=paths['templates'],\n        error_handler=handle_mako_error,\n        module_directory=os.path.join(app_conf['cache_dir'], 'templates'),\n        input_encoding='utf-8', default_filters=['escape'],\n        imports=['from webhelpers.html import escape'])\n\n    # Create the Genshi TemplateLoader\n    config['pylons.app_globals'].genshi_loader = TemplateLoader(\n        paths['templates'], auto_reload=True)\n\n    # Create the Jinja2 Environment\n    config['pylons.app_globals'].jinja2_env = Environment(loader=ChoiceLoader(\n            [FileSystemLoader(path) for path in paths['templates']]))\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n    \n    engine = engine_from_config(config, 'sqlalchemy.')\n    init_model(engine)\n\n    return config\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_controller_cache_decorator.py",
    "content": "import time\n\nfrom projectname.tests import *\n\nclass TestCacheController(TestController):\n    \n    def test_default_cache_decorator(self):\n        response = self.app.get(url(controller='cache', action='test_default_cache_decorator'))\n        assert 'Counter=1' in response\n\n        response = self.app.get(url(controller='cache', action='test_default_cache_decorator'))\n        assert 'Counter=1' in response\n        \n        response = self.app.get(url(controller='cache', action='test_get_cache_decorator', param=\"123\"))\n        assert 'Counter=2' in response\n        response = self.app.get(url(controller='cache', action='test_get_cache_decorator', param=\"123\"))\n        assert 'Counter=2' in response\n        \n        response = self.app.get(url(controller='cache', action='test_expire_cache_decorator'))\n        assert 'Counter=3' in response\n        response = self.app.get(url(controller='cache', action='test_expire_cache_decorator'))\n        assert 'Counter=3' in response\n        time.sleep(8)\n        response = self.app.get(url(controller='cache', action='test_expire_cache_decorator'))\n        assert 'Counter=4' in response\n        \n        response = self.app.get(url(controller='cache', action='test_key_cache_decorator', id=1))\n        assert 'Counter=5' in response\n        response = self.app.get(url(controller='cache', action='test_key_cache_decorator', id=2))\n        assert 'Counter=6' in response\n        response = self.app.get(url(controller='cache', action='test_key_cache_decorator', id=1))\n        assert 'Counter=5' in response\n        \n        response = self.app.get(url(controller='cache', action='test_keyslist_cache_decorator', id=1, id2=2))\n        assert 'Counter=7' in response\n        response = self.app.get(url(controller='cache', action='test_keyslist_cache_decorator', id=1, id2=2))\n        assert 'Counter=7' in response\n       \n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_controller_xmlrpc.py",
    "content": "from projectname.tests import *\nfrom xmlrpclib import loads, dumps\n\nclass TestXmlrpcController(TestController):\n    xmlurl = None\n    \n    def xmlreq(self, method, args=None):\n        if args is None:\n            args = ()\n        ee = dict(CONTENT_TYPE='text/xml')\n        data = dumps(args, methodname=method)\n        response = self.app.post(self.xmlurl, params = data, extra_environ=ee)\n        return loads(response.body)[0][0]\n    \n    def setUp(self):\n        self.xmlurl = url(controller='xmlrpc', action='index')\n    \n    def test_index(self):\n        response = self.xmlreq('userstatus')\n        assert response == 'basic string'\n    \n    def test_structure(self):\n        response = self.xmlreq('docs')\n        assert dict(mess='a little somethin', a=1, b=[1,2,3], c=['all','the']) == response\n        \n    def test_methodhelp(self):\n        response = self.xmlreq('system.methodHelp', ('docs',))\n        assert \"This method has a docstring\" in response\n    \n    def test_methodsignature(self):\n        response = self.xmlreq('system.methodSignature', ('docs',))\n        assert [['struct']] == response\n    \n    def test_listmethods(self):\n        response = self.xmlreq('system.listMethods')\n        assert response == ['docs', 'system.listMethods', 'system.methodHelp', 'system.methodSignature', 'uni', 'userstatus']\n    \n    def test_unicode(self):\n        response = self.xmlreq('uni')\n        assert 'A unicode string' in response['mess']"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_i18n.py",
    "content": "from projectname.tests import *\n\nclass TestSampleController(TestController):\n    def test_set_lang(self):\n        self._test_set_lang('set_lang')\n\n    def test_set_lang_pylonscontext(self):\n        self._test_set_lang('set_lang_pylonscontext')\n\n    def _test_set_lang(self, action):\n        response = self.app.get(url(controller='sample', action=action, lang='ja'))\n        assert u'\\u8a00\\u8a9e\\u8a2d\\u5b9a\\u3092\\u300cja\\u300d\\u306b\\u5909\\u66f4\\u3057\\u307e\\u3057\\u305f'.encode('utf-8') in response\n        response = self.app.get(url(controller='sample', action=action, lang='fr'))\n        assert 'Could not set language to \"fr\"' in response\n\n    def test_detect_lang(self):\n        response = self.app.get(url(controller='sample', action='i18n_index'), headers={\n                'Accept-Language':'fr;q=0.6, en;q=0.1, ja;q=0.3'})\n        # expect japanese fallback for nonexistent french.\n        assert u'\\u6839\\u672c\\u30a4\\u30f3\\u30c7\\u30af\\u30b9\\u30da\\u30fc\\u30b8'.encode('utf-8') in response\n\n    def test_no_lang(self):\n        response = self.app.get(url(controller='sample', action='no_lang'))\n        assert 'No language' in response\n        assert 'No languages' in response\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_jinja2.py",
    "content": "from projectname.tests import *\n\nclass TestJinja2Controller(TestController):\n    def test_jinja2(self):\n        response = self.app.get(url(controller='sample', action='testjinja2'))\n        assert 'Hello from Jinja2' in response\n        assert 'This is in c var' in response\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_mako.py",
    "content": "from projectname.tests import *\n\nclass TestMakoController(TestController):\n    def test_mako(self):\n        response = self.app.get(url(controller='sample', action='testmako'))\n        assert 'Hello, 5+5 is 10' in response\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_sample1.py",
    "content": "import pylons\nfrom projectname.tests import *\n\nclass TestSampleController(TestController):\n    def test_conf_with_app_globals(self):\n        assert 'pylons.app_globals' in pylons.config\n        assert hasattr(pylons.app_globals, 'cache')\n    \n    def test_root_index(self):\n        response = self.app.get('/')\n        assert 'Welcome' in response\n        # Test response...\n    \n    def test_index(self):\n        response = self.app.get(url(controller='sample', action='index'))\n        assert 'basic index page' in response\n    \n    def test_session(self):\n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session.has_key('counter')\n        assert response.session['counter'] == 0\n        \n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session['counter'] == 1\n        assert 'session incrementer' in response\n    \n    def test_global(self):\n        response = self.app.get(url(controller='sample', action='globalup'))\n        assert 'Hello' in response\n    \n    def test_global_persistence(self):\n        response = self.app.get(url(controller='sample', action='global_store'))\n        assert '0' in response\n        \n        response = self.app.get(url(controller='sample', action='global_store', id=2))\n        assert '2' in response\n        \n        response = self.app.get(url(controller='sample', action='global_store'))\n        assert '2' in response\n        \n        response = self.app.get(url(controller='sample', action='global_store', id=3))\n        assert '5' in response\n        \n        response = self.app.get(url(controller='sample', action='global_store'))\n        assert '5' in response\n    \n    def test_helper_urlfor(self):\n        response = self.app.get(url(controller='sample', action='myself'))\n        assert 'sample/myself' in response\n    \n    def test_params(self):\n        response = self.app.get(url(controller='sample', action='myparams', extra='something', data=4))\n        assert 'extra' in response\n        assert 'something' in response\n        assert 'data' in response\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_sample2.py",
    "content": "from projectname.tests import *\n\nclass TestSample2Controller(TestController):\n    def test_session(self):\n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session.has_key('counter')\n        assert response.session['counter'] == 0\n        \n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session['counter'] == 1\n        assert 'session incrementer' in response\n    \n    def test_genshi_default(self):\n        self._test_genshi_default('testdefault')\n    \n    def _test_genshi_default(self, action):\n        response = self.app.get(url(controller='sample', action=action))\n        assert 'Hello from Genshi' in response\n        assert 'This is in c var' in response\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_sample3.py",
    "content": "from projectname.tests import *\n\nclass TestSample2Controller(TestController):\n    def test_session(self):\n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session.has_key('counter')\n        assert response.session['counter'] == 0\n        \n        response = self.app.get(url(controller='sample', action='session_increment'))\n        assert response.session['counter'] == 1\n        assert 'session incrementer' in response\n        \n    def test_default(self):\n        response = self.app.get(url(controller='sample', action='test_template_caching'))\n        assert 'Hi everyone!' in response\n    "
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_sample4.py",
    "content": "from projectname.tests import *\n\nclass TestSample2Controller(TestController):\n    def test_get(self):\n        response = self.app.get(url(controller='sample', action='test_only_get'))\n        assert 'It was a get' in response\n    \n    def test_redir_get(self):\n        response = self.app.get(url(controller='sample', action='test_only_post'))\n        assert 'It was a get' in response\n        \n    def test_post(self):\n        response = self.app.post(url(controller='sample', action='test_only_post'),\n            params={'id':4})\n        assert 'It was a post' in response\n\n    def test_head(self):\n        response = self.app._gen_request('HEAD', url(controller='sample', action='index'))\n        assert '' == response.body\n"
  },
  {
    "path": "tests/test_webapps/filestotest/functional_sample_controller_sqlatesting.py",
    "content": "from projectname.tests import *\ntry:\n    from sqlalchemy.exceptions import IntegrityError\nexcept ImportError:\n    from sqlalchemy.exc import IntegrityError\n    \nfrom projectname.model.meta import Session, Base\nfrom projectname.model import Foo\n\nclass TestSQLAlchemyController(TestController):\n    def setUp(self):\n        Base.metadata.create_all(bind=Session.bind)\n        f = Foo(id = 1, bar = u\"Wabbit\")\n        Session.add(f)\n        Session.commit()\n        assert f.bar == u\"Wabbit\"\n    \n    def tearDown(self):\n        Base.metadata.drop_all(bind=Session.bind)\n\n    def test_sqlalchemy(self):\n        response = self.app.get(url(controller='sample', action='testsqlalchemy'))\n        assert 'foos = [Foo:1]' in response\n\n    # def test_exception(self):\n    #     me = Foo(id=3, bar='giuseppe')\n    #     me_again = Foo(id=3, bar='giuseppe')\n    #     self.assertRaises(IntegrityError, Session.commit)\n    #     Session.rollback()\n"
  },
  {
    "path": "tests/test_webapps/filestotest/helpers_sample.py",
    "content": "\"\"\"Helper functions\n\nConsists of functions to typically be used within templates, but also\navailable to Controllers. This module is available to both as 'h'.\n\"\"\"\n"
  },
  {
    "path": "tests/test_webapps/filestotest/messages.ja.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2007-02-05 12:36+0900\\n\"\n\"PO-Revision-Date: 2007-02-05 13:06+0900\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: controller_sample.py:7\nmsgid \"basic index page\"\nmsgstr \"根本インデクスページ\"\n\n#: controller_sample.py:59\n#, python-format\nmsgid \"Could not set language to \\\"%(lang)s\\\"\"\nmsgstr \"「%(lang)s」に言語設定が変更できません\"\n\n#: controller_sample.py:63\n#, python-format\nmsgid \"Set language to \\\"%(lang)s\\\"\"\nmsgstr \"言語設定を「%(lang)s」に変更しました\""
  },
  {
    "path": "tests/test_webapps/filestotest/messages.pot",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2007-02-05 12:36+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=CHARSET\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: controller_sample.py:7\nmsgid \"basic index page\"\nmsgstr \"\"\n\n#: controller_sample.py:59\n#, python-format\nmsgid \"Could not set language to \\\"%(lang)s\\\"\"\nmsgstr \"\"\n\n#: controller_sample.py:63\n#, python-format\nmsgid \"Set language to \\\"%(lang)s\\\"\"\nmsgstr \"\"\n"
  },
  {
    "path": "tests/test_webapps/filestotest/middleware_mako.py",
    "content": "\"\"\"Pylons middleware initialization\"\"\"\nfrom beaker.middleware import SessionMiddleware\nfrom paste.cascade import Cascade\nfrom paste.registry import RegistryManager\nfrom paste.urlparser import StaticURLParser\nfrom paste.deploy.converters import asbool\nfrom pylons.middleware import ErrorHandler, StatusCodeRedirect\nfrom pylons.wsgiapp import PylonsApp\nfrom routes.middleware import RoutesMiddleware\n\nfrom projectname.config.environment import load_environment\n\ndef make_app(global_conf, full_stack=True, static_files=True, **app_conf):\n    \"\"\"Create a Pylons WSGI application and return it\n\n    ``global_conf``\n        The inherited configuration for this application. Normally from\n        the [DEFAULT] section of the Paste ini file.\n\n    ``full_stack``\n        Whether this application provides a full WSGI stack (by default,\n        meaning it handles its own exceptions and errors). Disable\n        full_stack when this application is \"managed\" by another WSGI\n        middleware.\n\n    ``static_files``\n        Whether this application serves its own static files; disable\n        when another web server is responsible for serving them.\n\n    ``app_conf``\n        The application's local configuration. Normally specified in\n        the [app:<name>] section of the Paste ini file (where <name>\n        defaults to main).\n\n    \"\"\"\n    # Configure the Pylons environment\n    config = load_environment(global_conf, app_conf)\n\n    # The Pylons WSGI app\n    app = PylonsApp(config=config)\n\n    # Routing/Session/Cache Middleware\n    app = RoutesMiddleware(app, config['routes.map'], singleton=False)\n    app = SessionMiddleware(app, config)\n\n    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)\n\n    if asbool(full_stack):\n        # Handle Python exceptions\n        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])\n\n        # Display error documents for 401, 403, 404 status codes (and\n        # 500 when debug is disabled)\n        if asbool(config['debug']):\n            app = StatusCodeRedirect(app)\n        else:\n            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])\n\n    # Establish the Registry for this application\n    app = RegistryManager(app)\n\n    if asbool(static_files):\n        # Serve static files\n        static_app = StaticURLParser(config['pylons.paths']['static_files'])\n        app = Cascade([static_app, app])\n    app.config = config\n    return app\n"
  },
  {
    "path": "tests/test_webapps/filestotest/model__init__.py",
    "content": "\"\"\"The application's model objects\"\"\"\nfrom sqlalchemy import types, Column\n\nfrom projectname.model.meta import Base, Session\n\ndef init_model(engine):\n    \"\"\"Call me before using any of the tables or classes in the model\"\"\"\n    Session.configure(bind=engine)\n\n\nclass Foo(Base):\n    __tablename__ = 'foo'\n\n    id = Column(types.Integer, primary_key=True)\n    bar = Column(types.String(255), nullable=False)\n    def __repr__(self):\n        return \"Foo:%s\" % self.id\n"
  },
  {
    "path": "tests/test_webapps/filestotest/rest_routing.py",
    "content": "\"\"\"Routes configuration\n\nThe more specific and detailed routes should be defined first so they\nmay take precedent over the more generic routes. For more information\nrefer to the routes manual at http://routes.groovie.org/docs/\n\"\"\"\nfrom routes import Mapper\n\ndef make_map(config):\n    \"\"\"Create, configure and return the routes Mapper\"\"\"\n    map = Mapper(directory=config['pylons.paths']['controllers'],\n                 always_scan=config['debug'])\n    map.minimization = False\n    map.explicit = False\n    \n    # The ErrorController route (handles 404/500 error pages); it should\n    # likely stay at the top, ensuring it can always be resolved\n    map.connect('/error/{action}', controller='error')\n    map.connect('/error/{action}/{id}', controller='error')\n\n    # CUSTOM ROUTES HERE\n    map.resource('restsample', 'restsamples')\n    map.resource('restsample', 'restsamples', controller='mysubdir/restsamples', \n        path_prefix='/mysubdir', name_prefix='mysubdir_')\n\n    map.connect('/{controller}/{action}')\n    map.connect('/{controller}/{action}/{id}')\n\n    return map\n"
  },
  {
    "path": "tests/test_webapps/filestotest/test_mako.html",
    "content": "<%\nfrom datetime import datetime\nmytime = datetime.now()\n%>\n\nHi everyone!\n\nThe time is ${mytime}\n"
  },
  {
    "path": "tests/test_webapps/filestotest/test_sqlalchemy.html",
    "content": "foos = ${c.foos}\n"
  },
  {
    "path": "tests/test_webapps/filestotest/testgenshi.html",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<?python import datetime ?>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:py=\"http://genshi.edgewall.org/\">\n  <head>\n    <title>Hello from Genshi</title>\n  </head>\n  <body>\n    <h1>Hello from Genshi</h1>\n    <p>You visited the URL <tt>${request.url}</tt> at <tt>${datetime.datetime.now()}</tt></p>\n    <p>${c.test}</p>\n   </body>\n</html>\n"
  },
  {
    "path": "tests/test_webapps/filestotest/testjinja2.html",
    "content": "#import datetime\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n  <head>\n    <title>Hello from Jinja2</title>\n  </head>\n  <body>\n    <h1>Hello from Jinja2</h1>\n    <p>You visited the URL <tt>{{ request.url }}</tt> at <tt>{{ c.now() }}</tt></p>\n    <p>{{ c.test }}</p>\n   </body>\n</html>\n"
  },
  {
    "path": "tests/test_webapps/filestotest/tests__init__.py",
    "content": "\"\"\"Pylons application test package\n\nThis package assumes the Pylons environment is already loaded, such as\nwhen this script is imported from the `nosetests --with-pylons=test.ini`\ncommand.\n\nThis module initializes the application via ``websetup`` (`paster\nsetup-app`) and provides the base testing objects.\n\"\"\"\nfrom unittest import TestCase\n\nfrom paste.deploy import loadapp\nfrom paste.script.appinstall import SetupCommand\nfrom pylons import url\nfrom routes.util import URLGenerator\nfrom webtest import TestApp\n\nimport pylons.test\n\n__all__ = ['environ', 'url', 'TestController']\n\ntry:\n    from sqlalchemy import engine_from_config\n    from projectname.model.meta import Session, Base\n    from projectname.model import Foo, init_model\n    SQLAtesting = True\nexcept:\n    SQLAtesting = False\n\nimport os\nimport pylons\nfrom pylons.i18n.translation import _get_translator\n\nfrom paste.deploy import appconfig\nfrom projectname.config.environment import load_environment\n\nhere_dir = os.path.dirname(__file__)\nconf_dir = os.path.dirname(os.path.dirname(here_dir))\n\ntest_file = os.path.join(conf_dir, 'test.ini')\nconf = appconfig('config:' + test_file)\nconfig = load_environment(conf.global_conf, conf.local_conf)\n\nif SQLAtesting:\n    engine = engine_from_config(config, 'sqlalchemy.')\n    init_model(engine)\n\n# Invoke websetup with the current config file\nSetupCommand('setup-app').run([test_file])\n\nenviron = {}\n\nclass TestController(TestCase):\n    def __init__(self, *args, **kwargs):\n        wsgiapp = loadapp('config:test.ini', relative_to=conf_dir)\n        config = wsgiapp.config\n        pylons.app_globals._push_object(config['pylons.app_globals'])\n        pylons.config._push_object(config)\n        \n        # Initialize a translator for tests that utilize i18n\n        translator = _get_translator(pylons.config.get('lang'))\n        pylons.translator._push_object(translator)\n        \n        url._push_object(URLGenerator(config['routes.map'], environ))\n        self.app = TestApp(wsgiapp)\n        TestCase.__init__(self, *args, **kwargs)\n"
  },
  {
    "path": "tests/test_webapps/filestotest/websetup.py",
    "content": "\"\"\"Setup the projectname application\"\"\"\nimport logging\n\nimport pylons.test\n\nfrom projectname.config.environment import load_environment\nfrom projectname.model.meta import Session, Base\nfrom projectname.model import Foo\nfrom sqlalchemy import engine_from_config\n\nlog = logging.getLogger(__name__)\n\ndef setup_app(command, conf, vars):\n    \"\"\"Place any commands to setup projectname here\"\"\"\n    config = load_environment(conf.global_conf, conf.local_conf)\n    # Create the tables if they don't already exist\n    Base.metadata.create_all(bind=Session.bind)\n"
  },
  {
    "path": "tests/test_webapps/test_make_project.py",
    "content": "\"\"\"Tests against full Pylons projects created from scratch\"\"\"\nimport os\nimport sys\nimport shutil\nimport re\n\nimport pkg_resources\nfrom nose import SkipTest\nfrom paste.fixture import TestFileEnvironment\n\nif os.environ.get('SKIP_INTEGRATED', 'False') != '0':\n    raise SkipTest()\n\nimport pylons\nimport pylons.test\n\ntry:\n    import sqlalchemy as sa\n    SQLAtesting = True\nexcept ImportError:\n    SQLAtesting = False\n# SQLAtesting = False\n\nis_jython = sys.platform.startswith('java')\n\nTEST_OUTPUT_DIRNAME = 'output'\n\nfor spec in ['PasteScript', 'Paste', 'PasteDeploy', 'pylons']:\n    pkg_resources.require(spec)\n\ntemplate_path = os.path.join(\n    os.path.dirname(__file__), 'filestotest').replace('\\\\','/')\n\ntest_environ = os.environ.copy()\ntest_environ['PASTE_TESTING'] = 'true'\n\ntestenv = TestFileEnvironment(\n    os.path.join(os.path.dirname(__file__), TEST_OUTPUT_DIRNAME).replace('\\\\','/'),\n    template_path=template_path,\n    environ=test_environ)\n\nprojenv = None\n\ndef _get_script_name(script):\n    if sys.platform == 'win32' and not script.lower().endswith('.exe'):\n        script += '.exe'\n    return script\n\ndef svn_repos_setup():\n    res = testenv.run(_get_script_name('svnadmin'), 'create', 'REPOS',\n                      printresult=False)\n    path = testenv.base_path.replace('\\\\','/').replace(' ','%20')\n    base = 'file://'\n    if ':' in path:\n        base = 'file:///'\n    testenv.svn_url = base + path + '/REPOS'\n    assert 'REPOS' in res.files_created\n    testenv.ignore_paths.append('REPOS')\n\ndef paster_create(template_engine='mako', overwrite=False, sqlatesting=False):\n    global projenv\n    paster_args = ['create', '--verbose', '--no-interactive']\n    if overwrite:\n        paster_args.append('-f')\n    paster_args.extend(['--template=pylons',\n                        'ProjectName',\n                        'version=0.1',\n                        'sqlalchemy=%s' % sqlatesting,\n                        'zip_safe=False',\n                        'template_engine=%s' % template_engine])\n    res = testenv.run(_get_script_name('paster'), *paster_args)\n    expect_fn = ['projectname', 'development.ini', 'setup.cfg', 'README.txt',\n                 'setup.py']\n    for fn in expect_fn:\n        fn = os.path.join('ProjectName', fn)\n        if not overwrite:\n            assert fn in res.files_created.keys()\n        assert fn in res.stdout\n    \n    if not overwrite:\n        setup = res.files_created[os.path.join('ProjectName','setup.py')]\n        setup.mustcontain('0.1')\n        setup.mustcontain('projectname.config.middleware:make_app')\n        setup.mustcontain('main = pylons.util:PylonsInstaller')\n        setup.mustcontain(\"include_package_data=True\")\n        assert '0.1' in setup\n    testenv.run(_get_script_name(sys.executable)+' setup.py egg_info',\n                cwd=os.path.join(testenv.cwd, 'ProjectName').replace('\\\\','/'),\n                expect_stderr=True)\n    #testenv.run(_get_script_name('svn'), 'commit', '-m', 'Created project', 'ProjectName')\n    # A new environment with a new\n    projenv = TestFileEnvironment(\n        os.path.join(testenv.base_path, 'ProjectName').replace('\\\\','/'),\n        start_clear=False,\n        template_path=template_path,\n        environ=test_environ)\n    projenv.environ['PYTHONPATH'] = (\n        projenv.environ.get('PYTHONPATH', '') + ':'\n        + projenv.base_path)\n    \n\ndef make_controller():\n    res = projenv.run(_get_script_name('paster')+' controller sample')\n    assert os.path.join('projectname','controllers','sample.py') in res.files_created\n    assert os.path.join('projectname','tests','functional','test_sample.py') in res.files_created\n    #res = projenv.run(_get_script_name('svn')+' status')\n    # Make sure all files are added to the repository:\n    assert '?' not in res.stdout\n\ndef make_controller_subdirectory():\n    res = projenv.run(_get_script_name('paster')+' controller mysubdir/sample')\n    assert os.path.join('projectname','controllers', 'mysubdir', 'sample.py') in res.files_created\n    assert os.path.join('projectname','tests','functional','test_mysubdir_sample.py') in res.files_created\n    #res = projenv.run(_get_script_name('svn')+' status')\n    # Make sure all files are added to the repository:\n    assert '?' not in res.stdout\n\ndef make_restcontroller():\n    res = projenv.run(_get_script_name('paster')+' restcontroller restsample restsamples')\n    assert os.path.join('projectname','controllers','restsamples.py') in res.files_created\n    assert os.path.join('projectname','tests','functional','test_restsamples.py') in res.files_created\n    #res = projenv.run(_get_script_name('svn')+' status')\n    # Make sure all files are added to the repository:\n    assert '?' not in res.stdout\n\ndef make_restcontroller_subdirectory():\n    res = projenv.run(_get_script_name('paster')+' restcontroller mysubdir/restsample mysubdir/restsamples')\n    assert os.path.join('projectname','controllers','mysubdir', 'restsamples.py') in res.files_created\n    assert os.path.join('projectname','tests','functional','test_mysubdir_restsamples.py') in res.files_created\n    #res = projenv.run(_get_script_name('svn')+' status')\n    # Make sure all files are added to the repository:\n    assert '?' not in res.stdout\n\n\ndef _do_proj_test(copydict, emptyfiles=None, match_routes_output=None):\n    \"\"\"Given a dict of files, where the key is a filename in filestotest, the value is\n    the destination in the new projects dir. emptyfiles is a list of files that should\n    be created and empty.\"\"\"\n    if pylons.test.pylonsapp:\n        pylons.test.pylonsapp = None\n    \n    if not emptyfiles:\n        emptyfiles = []\n    for original, newfile in copydict.iteritems():\n        projenv.writefile(newfile, frompath=original)\n    for fi in emptyfiles:\n        projenv.writefile(fi)\n    \n    # here_dir = os.getcwd()\n    # test_dir = os.path.join(testenv.cwd, 'ProjectName').replace('\\\\','/')\n    # os.chdir(test_dir)\n    # sys.path.append(test_dir)\n    # nose.run(argv=['nosetests', '-d', test_dir])\n    # \n    # sys.path.pop(-1)\n    # os.chdir(here_dir)\n    \n    res = projenv.run(_get_script_name('nosetests')+' -d',\n                      expect_stderr=True,\n                      cwd=os.path.join(testenv.cwd, 'ProjectName').replace('\\\\','/'))\n    if match_routes_output:\n        res = projenv.run(_get_script_name('paster')+' routes',\n                          expect_stderr=False,\n                          cwd=os.path.join(testenv.cwd, 'ProjectName').replace('\\\\','/'))\n        for pattern in match_routes_output:\n            assert re.compile(pattern).search(res.stdout)\n        \n\ndef do_nosetests():\n    _do_proj_test({'development.ini':'development.ini'})\n\ndef do_knowntest():\n    copydict = {\n        'helpers_sample.py':'projectname/lib/helpers.py',\n        'controller_sample.py':'projectname/controllers/sample.py',\n        'app_globals.py':'projectname/lib/app_globals.py',\n        'functional_sample_controller_sample1.py':'projectname/tests/functional/test_sample.py',\n    }\n    _do_proj_test(copydict)\n\ndef do_i18ntest():\n    copydict = {\n        'functional_sample_controller_i18n.py':'projectname/tests/functional/test_i18n.py',\n        'messages.ja.po':'projectname/i18n/ja/LC_MESSAGES/projectname.po',\n        'messages.ja.mo':'projectname/i18n/ja/LC_MESSAGES/projectname.mo',\n    }\n    _do_proj_test(copydict)\n\ndef do_genshi():\n    paster_create(template_engine='genshi', overwrite=True)\n    reset = {\n        'helpers_sample.py':'projectname/lib/helpers.py',\n        'app_globals.py':'projectname/lib/app_globals.py',\n        'rest_routing.py':'projectname/config/routing.py',\n        'development.ini':'development.ini',\n        }\n    copydict = {\n        'testgenshi.html':'projectname/templates/testgenshi.html',\n        'environment_def_engine.py':'projectname/config/environment.py',\n        'functional_sample_controller_sample2.py':'projectname/tests/functional/test_sample2.py'\n    }\n    copydict.update(reset)\n    empty = ['projectname/templates/__init__.py', 'projectname/tests/functional/test_cache.py']\n    _do_proj_test(copydict, empty)\n\ndef do_two_engines():\n    copydict = {\n        'middleware_two_engines.py':'projectname/config/middleware.py',\n        'test_mako.html':'projectname/templates/test_mako.html',\n        'functional_sample_controller_sample3.py':'projectname/tests/functional/test_sample2.py',\n    }\n    _do_proj_test(copydict)\n\ndef do_crazy_decorators():\n    _do_proj_test({'functional_sample_controller_sample4.py':'projectname/tests/functional/test_sample3.py'})\n\ndef do_jinja2():\n    paster_create(template_engine='jinja2', overwrite=True)\n    reset = {\n        'helpers_sample.py':'projectname/lib/helpers.py',\n        'app_globals.py':'projectname/lib/app_globals.py',\n        'rest_routing.py':'projectname/config/routing.py',\n        'development.ini':'development.ini',\n        }\n    copydict = {\n        'controller_sample.py':'projectname/controllers/sample.py',\n        'testjinja2.html':'projectname/templates/testjinja2.html',\n        'environment_def_engine.py':'projectname/config/environment.py',\n        'functional_sample_controller_jinja2.py':'projectname/tests/functional/test_jinja2.py',\n    }\n    copydict.update(reset)\n    empty = [\n         'projectname/templates/__init__.py',\n         'projectname/tests/functional/test_sample.py',\n         'projectname/tests/functional/test_sample2.py',\n         'projectname/tests/functional/test_sample3.py',\n         'projectname/tests/functional/test_cache.py'\n     ]\n    _do_proj_test(copydict, empty)\n\ndef do_cache_decorator():\n    copydict = {\n        'middleware_mako.py':'projectname/config/middleware.py',\n        'app_globals.py':'projectname/lib/app_globals.py',\n        'cache_controller.py':'projectname/controllers/cache.py',\n        'functional_controller_cache_decorator.py':'projectname/tests/functional/test_cache.py',\n    }\n    empty = [\n        'projectname/tests/functional/test_mako.py',\n        'projectname/tests/functional/test_jinja2.py',\n        'projectname/tests/functional/test_sample.py',\n        'projectname/tests/functional/test_sample2.py',\n        'projectname/tests/functional/test_sample3.py'\n     ]\n    _do_proj_test(copydict, empty)\n\ndef do_xmlrpc():\n    copydict = {\n        'middleware_mako.py':'projectname/config/middleware.py',\n        'base_with_xmlrpc.py':'projectname/lib/base.py',\n        'controller_xmlrpc.py':'projectname/controllers/xmlrpc.py',\n        'functional_controller_xmlrpc.py':'projectname/tests/functional/test_xmlrpc.py'\n    }\n    empty = [\n        'projectname/tests/functional/test_cache.py',\n        'projectname/tests/functional/test_jinja2.py',\n    ]\n    _do_proj_test(copydict, empty)\n\n\ndef make_tag():\n    global tagenv\n    #res = projenv.run(_get_script_name('svn')+' commit -m \"updates\"')\n    # Space at the end needed so run() doesn't add \\n causing svntag to complain\n    #res = projenv.run(_get_script_name(sys.executable)+' setup.py svntag --version=0.5 ')\n    # XXX Still fails => setuptools problem on win32?\n    assert 'Tagging 0.5 version' in res.stdout\n    assert 'Auto-update of version strings' in res.stdout\n    res = testenv.run(_get_script_name('svn')+' co %s/ProjectName/tags/0.5 Proj-05 '\n                      % testenv.svn_url)\n    setup = res.files_created['Proj-05/setup.py']\n    setup.mustcontain('0.5')\n    assert 'Proj-05/setup.cfg' not in res.files_created\n    tagenv = TestFileEnvironment(\n        os.path.join(testenv.base_path, 'Proj-05').replace('\\\\','/'),\n        start_clear=False,\n        template_path=template_path)\n\ndef do_sqlaproject():\n    paster_create(template_engine='mako', overwrite=True, sqlatesting=True)\n    reset = {\n        'helpers_sample.py':'projectname/lib/helpers.py',\n        'app_globals.py':'projectname/lib/app_globals.py',\n        'rest_routing.py':'projectname/config/routing.py',\n        'development_sqlatesting.ini':'development.ini',\n        'websetup.py':'projectname/websetup.py',\n        'model__init__.py':'projectname/model/__init__.py',\n        'environment_def_sqlamodel.py':'projectname/config/environment.py',\n        'tests__init__.py':'projectname/tests/__init__.py',\n        }\n    copydict = {\n        'controller_sqlatest.py':'projectname/controllers/sample.py',\n        'test_mako.html':'projectname/templates/test_mako.html',\n        'test_sqlalchemy.html':'projectname/templates/test_sqlalchemy.html',\n        'functional_sample_controller_sqlatesting.py':'projectname/tests/functional/test_sqlalchemyproject.py',\n    }\n    copydict.update(reset)\n    empty = [\n         'projectname/templates/__init__.py',\n         'projectname/tests/functional/test_sample.py',\n         'projectname/tests/functional/test_sample2.py',\n         'projectname/tests/functional/test_sample3.py',\n         'projectname/tests/functional/test_cache.py'\n     ]\n    _do_proj_test(copydict, empty)\n    # res = projenv.run(_get_script_name('paster')+' setup-app development.ini', expect_stderr=True,)\n    # assert '?' not in res.stdout\n\n\n# Unfortunately, these are ordered, so be careful\ndef test_project_paster_create():\n    paster_create()\n\ndef test_project_make_controller():\n    make_controller()\n\ndef test_project_make_controller_subdirectory():\n    make_controller_subdirectory()\n\ndef test_project_do_nosetests():\n    do_nosetests()\n\ndef test_project_do_knowntest():\n    do_knowntest()\n\ndef test_project_do_i18ntest():\n    do_i18ntest()\n\ndef test_project_make_restcontroller():\n    make_restcontroller()\n\ndef test_project_make_restcontroller_subdirectory():\n    make_restcontroller_subdirectory()\n    \ndef test_project_do_rest_nosetests():\n    copydict = {\n        'rest_routing.py':'projectname/config/routing.py',\n        'development.ini':'development.ini',\n    }\n    match_routes_output = [\n        'Route name +Methods +Path',\n        'restsamples +GET +/restsamples'\n    ]\n    _do_proj_test(copydict, match_routes_output)\n\n# Tests with templating plugin dependencies\ndef test_project_do_crazy_decorators():\n    do_crazy_decorators()\n\ndef test_project_do_cache_decorator():\n    do_cache_decorator()\n\ndef test_project_do_genshi_default():\n    if is_jython:\n        raise SkipTest('Jython does not currently support Genshi')\n    do_genshi()\n\ndef test_project_do_jinja2():\n    do_jinja2()\n\ndef test_project_do_xmlrpc():\n    do_xmlrpc()\n\n#def test_project_make_tag():\n#    make_tag()\ndef test_project_do_sqlaproject():\n    if SQLAtesting:\n        do_sqlaproject()\n    else:\n        pass\n\ndef teardown():\n    dir_to_clean = os.path.join(os.path.dirname(__file__), TEST_OUTPUT_DIRNAME)\n    cov_dir = os.path.join(dir_to_clean, 'ProjectName')\n    main_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))\n    \n    # Scan and move the coverage files\n    # for name in os.listdir(cov_dir):\n    #     if name.startswith('.coverage.'):\n    #         shutil.move(os.path.join(cov_dir, name), main_dir)\n    #     \n    shutil.rmtree(dir_to_clean)\n"
  }
]